[Mlir-commits] [mlir] [MLIR] Add more logging to DenseAnalysis/DeaDCodeAnalysis/TestDenseBackwardDataFlowAnalysis (NFC) (PR #161503)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 1 03:54:25 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

<details>
<summary>Changes</summary>

Just some more debugging help here.

---

Patch is 37.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161503.diff


3 Files Affected:

- (modified) mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp (+2-2) 
- (modified) mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp (+210-23) 
- (modified) mlir/test/lib/Analysis/DataFlow/TestDenseBackwardDataFlowAnalysis.cpp (+69-3) 


``````````diff
diff --git a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
index de1ed39ed4fdb..377f7ebe06750 100644
--- a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
@@ -522,14 +522,14 @@ void DeadCodeAnalysis::visitRegionBranchEdges(
     // Mark the entry block as executable.
     auto *state = getOrCreate<Executable>(point);
     propagateIfChanged(state, state->setToLive());
-    LDBG() << "Marked region successor live: " << point;
+    LDBG() << "Marked region successor live: " << *point;
 
     // Add the parent op as a predecessor.
     auto *predecessors = getOrCreate<PredecessorState>(point);
     propagateIfChanged(
         predecessors,
         predecessors->join(predecessorOp, successor.getSuccessorInputs()));
-    LDBG() << "Added region branch as predecessor for successor: " << point;
+    LDBG() << "Added region branch as predecessor for successor: " << *point;
   }
 }
 
diff --git a/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp b/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp
index b51465bc31ec3..daa3db55b2852 100644
--- a/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp
@@ -17,44 +17,74 @@
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/DebugLog.h"
 #include <cassert>
 #include <optional>
 
 using namespace mlir;
 using namespace mlir::dataflow;
 
+#define DEBUG_TYPE "dense-analysis"
+
 //===----------------------------------------------------------------------===//
 // AbstractDenseForwardDataFlowAnalysis
 //===----------------------------------------------------------------------===//
 
 void AbstractDenseForwardDataFlowAnalysis::initializeEquivalentLatticeAnchor(
     Operation *top) {
+  LDBG() << "initializeEquivalentLatticeAnchor: "
+         << OpWithFlags(top, OpPrintingFlags().skipRegions());
   top->walk([&](Operation *op) {
-    if (isa<RegionBranchOpInterface, CallOpInterface>(op))
+    if (isa<RegionBranchOpInterface, CallOpInterface>(op)) {
+      LDBG() << "  Skipping "
+             << OpWithFlags(op, OpPrintingFlags().skipRegions())
+             << " (region branch or call)";
       return;
+    }
+    LDBG() << "  Building equivalent lattice anchor for "
+           << OpWithFlags(op, OpPrintingFlags().skipRegions());
     buildOperationEquivalentLatticeAnchor(op);
   });
 }
 
 LogicalResult AbstractDenseForwardDataFlowAnalysis::initialize(Operation *top) {
+  LDBG() << "initialize (forward): "
+         << OpWithFlags(top, OpPrintingFlags().skipRegions());
   // Visit every operation and block.
-  if (failed(processOperation(top)))
+  if (failed(processOperation(top))) {
+    LDBG() << "  Failed to process top-level operation";
     return failure();
+  }
 
   for (Region &region : top->getRegions()) {
+    LDBG() << "  Processing region with " << region.getBlocks().size()
+           << " blocks";
     for (Block &block : region) {
+      LDBG() << "    Processing block with " << block.getOperations().size()
+             << " operations";
       visitBlock(&block);
-      for (Operation &op : block)
-        if (failed(initialize(&op)))
+      for (Operation &op : block) {
+        LDBG() << "      Initializing operation: "
+               << OpWithFlags(&op, OpPrintingFlags().skipRegions());
+        if (failed(initialize(&op))) {
+          LDBG() << "      Failed to initialize operation";
           return failure();
+        }
+      }
     }
   }
+  LDBG() << "  Forward initialization completed successfully";
   return success();
 }
 
 LogicalResult AbstractDenseForwardDataFlowAnalysis::visit(ProgramPoint *point) {
-  if (!point->isBlockStart())
+  LDBG() << "visit (forward): " << *point;
+  if (!point->isBlockStart()) {
+    LDBG() << "  Processing operation: "
+           << OpWithFlags(point->getPrevOp(), OpPrintingFlags().skipRegions());
     return processOperation(point->getPrevOp());
+  }
+  LDBG() << "  Visiting block: " << point->getBlock();
   visitBlock(point->getBlock());
   return success();
 }
@@ -62,6 +92,11 @@ LogicalResult AbstractDenseForwardDataFlowAnalysis::visit(ProgramPoint *point) {
 void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
     CallOpInterface call, const AbstractDenseLattice &before,
     AbstractDenseLattice *after) {
+  LDBG() << "visitCallOperation (forward): "
+         << OpWithFlags(call.getOperation(), OpPrintingFlags().skipRegions());
+  LDBG() << "  before state: " << before;
+  LDBG() << "  after state: " << *after;
+
   // Allow for customizing the behavior of calls to external symbols, including
   // when the analysis is explicitly marked as non-interprocedural.
   auto isExternalCallable = [&]() {
@@ -70,6 +105,7 @@ void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
     return callable && !callable.getCallableRegion();
   };
   if (!getSolverConfig().isInterprocedural() || isExternalCallable()) {
+    LDBG() << "  Handling as external callee (non-interprocedural or external)";
     return visitCallControlFlowTransfer(
         call, CallControlFlowAction::ExternalCallee, before, after);
   }
@@ -78,10 +114,16 @@ void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
       getProgramPointAfter(call.getOperation()), getProgramPointAfter(call));
   // Otherwise, if not all return sites are known, then conservatively assume we
   // can't reason about the data-flow.
-  if (!predecessors->allPredecessorsKnown())
+  if (!predecessors->allPredecessorsKnown()) {
+    LDBG() << "  Not all predecessors known, setting to entry state";
     return setToEntryState(after);
+  }
 
+  LDBG() << "  Processing " << predecessors->getKnownPredecessors().size()
+         << " known predecessors";
   for (Operation *predecessor : predecessors->getKnownPredecessors()) {
+    LDBG() << "    Processing predecessor: "
+           << OpWithFlags(predecessor, OpPrintingFlags().skipRegions());
     // Get the lattices at callee return:
     //
     //   func.func @callee() {
@@ -99,6 +141,7 @@ void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
     const AbstractDenseLattice *latticeAtCalleeReturn =
         getLatticeFor(getProgramPointAfter(call.getOperation()),
                       getProgramPointAfter(predecessor));
+    LDBG() << "    Lattice at callee return: " << *latticeAtCalleeReturn;
     visitCallControlFlowTransfer(call, CallControlFlowAction::ExitCallee,
                                  *latticeAtCalleeReturn, latticeAfterCall);
   }
@@ -106,12 +149,16 @@ void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(
 
 LogicalResult
 AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {
+  LDBG() << "processOperation (forward): "
+         << OpWithFlags(op, OpPrintingFlags().skipRegions());
   ProgramPoint *point = getProgramPointAfter(op);
   // If the containing block is not executable, bail out.
   if (op->getBlock() != nullptr &&
       !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))
-           ->isLive())
+           ->isLive()) {
+    LDBG() << "  Block not executable, skipping operation";
     return success();
+  }
 
   // Get the dense lattice to update.
   AbstractDenseLattice *after = getLattice(point);
@@ -119,10 +166,13 @@ AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {
   // Get the dense state before the execution of the op.
   const AbstractDenseLattice *before =
       getLatticeFor(point, getProgramPointBefore(op));
+  LDBG() << "  before state: " << *before;
+  LDBG() << "  after state: " << *after;
 
   // If this op implements region control-flow, then control-flow dictates its
   // transfer function.
   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
+    LDBG() << "  Processing as region branch operation";
     visitRegionBranchOperation(point, branch, after);
     return success();
   }
@@ -130,41 +180,57 @@ AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {
   // If this is a call operation, then join its lattices across known return
   // sites.
   if (auto call = dyn_cast<CallOpInterface>(op)) {
+    LDBG() << "  Processing as call operation";
     visitCallOperation(call, *before, after);
     return success();
   }
 
   // Invoke the operation transfer function.
+  LDBG() << "  Invoking operation transfer function";
   return visitOperationImpl(op, *before, after);
 }
 
 void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
+  LDBG() << "visitBlock (forward): " << block;
   // If the block is not executable, bail out.
   ProgramPoint *point = getProgramPointBefore(block);
-  if (!getOrCreateFor<Executable>(point, point)->isLive())
+  if (!getOrCreateFor<Executable>(point, point)->isLive()) {
+    LDBG() << "  Block not executable, skipping";
     return;
+  }
 
   // Get the dense lattice to update.
   AbstractDenseLattice *after = getLattice(point);
+  LDBG() << "  Block lattice state: " << *after;
 
   // The dense lattices of entry blocks are set by region control-flow or the
   // callgraph.
   if (block->isEntryBlock()) {
+    LDBG() << "  Processing entry block";
     // Check if this block is the entry block of a callable region.
     auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());
     if (callable && callable.getCallableRegion() == block->getParent()) {
+      LDBG() << "    Entry block of callable region";
       const auto *callsites = getOrCreateFor<PredecessorState>(
           point, getProgramPointAfter(callable));
       // If not all callsites are known, conservatively mark all lattices as
       // having reached their pessimistic fixpoints. Do the same if
       // interprocedural analysis is not enabled.
       if (!callsites->allPredecessorsKnown() ||
-          !getSolverConfig().isInterprocedural())
+          !getSolverConfig().isInterprocedural()) {
+        LDBG() << "    Not all callsites known or non-interprocedural, setting "
+                  "to entry state";
         return setToEntryState(after);
+      }
+      LDBG() << "    Processing " << callsites->getKnownPredecessors().size()
+             << " known callsites";
       for (Operation *callsite : callsites->getKnownPredecessors()) {
+        LDBG() << "      Processing callsite: "
+               << OpWithFlags(callsite, OpPrintingFlags().skipRegions());
         // Get the dense lattice before the callsite.
         const AbstractDenseLattice *before;
         before = getLatticeFor(point, getProgramPointBefore(callsite));
+        LDBG() << "      Lattice before callsite: " << *before;
 
         visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),
                                      CallControlFlowAction::EnterCallee,
@@ -174,23 +240,32 @@ void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
     }
 
     // Check if we can reason about the control-flow.
-    if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp()))
+    if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {
+      LDBG() << "    Entry block of region branch operation";
       return visitRegionBranchOperation(point, branch, after);
+    }
 
     // Otherwise, we can't reason about the data-flow.
+    LDBG() << "    Cannot reason about data-flow, setting to entry state";
     return setToEntryState(after);
   }
 
   // Join the state with the state after the block's predecessors.
+  LDBG() << "  Joining state from "
+         << std::distance(block->pred_begin(), block->pred_end())
+         << " predecessors";
   for (Block::pred_iterator it = block->pred_begin(), e = block->pred_end();
        it != e; ++it) {
     // Skip control edges that aren't executable.
     Block *predecessor = *it;
     if (!getOrCreateFor<Executable>(
              point, getLatticeAnchor<CFGEdge>(predecessor, block))
-             ->isLive())
+             ->isLive()) {
+      LDBG() << "    Skipping non-executable edge from " << predecessor;
       continue;
+    }
 
+    LDBG() << "    Joining state from predecessor " << predecessor;
     // Merge in the state from the predecessor's terminator.
     join(after, *getLatticeFor(
                     point, getProgramPointAfter(predecessor->getTerminator())));
@@ -200,20 +275,34 @@ void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {
 void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(
     ProgramPoint *point, RegionBranchOpInterface branch,
     AbstractDenseLattice *after) {
+  LDBG() << "visitRegionBranchOperation (forward): "
+         << OpWithFlags(branch.getOperation(), OpPrintingFlags().skipRegions());
+  LDBG() << "  point: " << *point;
+  LDBG() << "  after state: " << *after;
+
   // Get the terminator predecessors.
   const auto *predecessors = getOrCreateFor<PredecessorState>(point, point);
   assert(predecessors->allPredecessorsKnown() &&
          "unexpected unresolved region successors");
 
+  LDBG() << "  Processing " << predecessors->getKnownPredecessors().size()
+         << " known predecessors";
   for (Operation *op : predecessors->getKnownPredecessors()) {
+    LDBG() << "    Processing predecessor: "
+           << OpWithFlags(op, OpPrintingFlags().skipRegions());
     const AbstractDenseLattice *before;
     // If the predecessor is the parent, get the state before the parent.
     if (op == branch) {
+      LDBG() << "      Predecessor is the branch itself, getting state before "
+                "parent";
       before = getLatticeFor(point, getProgramPointBefore(op));
       // Otherwise, get the state after the terminator.
     } else {
+      LDBG()
+          << "      Predecessor is terminator, getting state after terminator";
       before = getLatticeFor(point, getProgramPointAfter(op));
     }
+    LDBG() << "      before state: " << *before;
 
     // This function is called in two cases:
     //   1. when visiting the block (point = block start);
@@ -231,19 +320,31 @@ void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(
     std::optional<unsigned> regionFrom =
         op == branch ? std::optional<unsigned>()
                      : op->getBlock()->getParent()->getRegionNumber();
+    LDBG() << "      regionFrom: "
+           << (regionFrom ? std::to_string(*regionFrom) : "parent");
+
     if (point->isBlockStart()) {
       unsigned regionTo = point->getBlock()->getParent()->getRegionNumber();
+      LDBG() << "      Point is block start, regionTo: " << regionTo;
+      LDBG() << "      Calling visitRegionBranchControlFlowTransfer with "
+                "regionFrom/regionTo";
       visitRegionBranchControlFlowTransfer(branch, regionFrom, regionTo,
                                            *before, after);
     } else {
       assert(point->getPrevOp() == branch &&
              "expected to be visiting the branch itself");
+      LDBG() << "      Point is not block start, checking if predecessor is "
+                "region or op itself";
       // Only need to call the arc transfer when the predecessor is the region
       // or the op itself, not the previous op.
       if (op->getParentOp() == branch || op == branch) {
+        LDBG() << "      Predecessor is region or op itself, calling "
+                  "visitRegionBranchControlFlowTransfer";
         visitRegionBranchControlFlowTransfer(
             branch, regionFrom, /*regionTo=*/std::nullopt, *before, after);
       } else {
+        LDBG()
+            << "      Predecessor is not region or op itself, performing join";
         join(after, *before);
       }
     }
@@ -256,35 +357,61 @@ void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(
 
 void AbstractDenseBackwardDataFlowAnalysis::initializeEquivalentLatticeAnchor(
     Operation *top) {
+  LDBG() << "initializeEquivalentLatticeAnchor (backward): "
+         << OpWithFlags(top, OpPrintingFlags().skipRegions());
   top->walk([&](Operation *op) {
-    if (isa<RegionBranchOpInterface, CallOpInterface>(op))
+    if (isa<RegionBranchOpInterface, CallOpInterface>(op)) {
+      LDBG() << "  Skipping "
+             << OpWithFlags(op, OpPrintingFlags().skipRegions())
+             << " (region branch or call)";
       return;
+    }
+    LDBG() << "  Building equivalent lattice anchor for "
+           << OpWithFlags(op, OpPrintingFlags().skipRegions());
     buildOperationEquivalentLatticeAnchor(op);
   });
 }
 
 LogicalResult
 AbstractDenseBackwardDataFlowAnalysis::initialize(Operation *top) {
+  LDBG() << "initialize (backward): "
+         << OpWithFlags(top, OpPrintingFlags().skipRegions());
   // Visit every operation and block.
-  if (failed(processOperation(top)))
+  if (failed(processOperation(top))) {
+    LDBG() << "  Failed to process top-level operation";
     return failure();
+  }
 
   for (Region &region : top->getRegions()) {
+    LDBG() << "  Processing region with " << region.getBlocks().size()
+           << " blocks";
     for (Block &block : region) {
+      LDBG() << "    Processing block with " << block.getOperations().size()
+             << " operations";
       visitBlock(&block);
       for (Operation &op : llvm::reverse(block)) {
-        if (failed(initialize(&op)))
+        LDBG() << "      Initializing operation (backward): "
+               << OpWithFlags(&op, OpPrintingFlags().skipRegions());
+        if (failed(initialize(&op))) {
+          LDBG() << "      Failed to initialize operation";
           return failure();
+        }
       }
     }
   }
+  LDBG() << "  Backward initialization completed successfully";
   return success();
 }
 
 LogicalResult
 AbstractDenseBackwardDataFlowAnalysis::visit(ProgramPoint *point) {
-  if (!point->isBlockEnd())
+  LDBG() << "visit (backward): " << *point;
+  if (!point->isBlockEnd()) {
+    LDBG() << "  Processing operation: "
+           << OpWithFlags(point->getNextOp(), OpPrintingFlags().skipRegions());
     return processOperation(point->getNextOp());
+  }
+  LDBG() << "  Visiting block: " << point->getBlock();
   visitBlock(point->getBlock());
   return success();
 }
@@ -292,28 +419,47 @@ AbstractDenseBackwardDataFlowAnalysis::visit(ProgramPoint *point) {
 void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(
     CallOpInterface call, const AbstractDenseLattice &after,
     AbstractDenseLattice *before) {
+  LDBG() << "visitCallOperation (backward): "
+         << OpWithFlags(call.getOperation(), OpPrintingFlags().skipRegions());
+  LDBG() << "  after state: " << after;
+  LDBG() << "  before state: " << *before;
+
   // If the solver is not interprocedural, let the hook handle it as an external
   // callee.
-  if (!getSolverConfig().isInterprocedural())
+  if (!getSolverConfig().isInterprocedural()) {
+    LDBG() << "  Non-interprocedural analysis, handling as external callee";
     return visitCallControlFlowTransfer(
         call, CallControlFlowAction::ExternalCallee, after, before);
+  }
 
   // Find the callee.
   Operation *callee = call.resolveCallableInTable(&symbolTable);
+  if (callee) {
+    LDBG() << "  Resolved callee: "
+           << OpWithFlags(callee, OpPrintingFlags().skipRegions());
+  } else {
+    LDBG() << "  Resolved callee: null";
+  }
 
   auto callable = dyn_cast_or_null<CallableOpInterface>(callee);
   // No region means the callee is only declared in this module.
   // If that is the case or if the solver is not interprocedural,
   // let the hook handle it.
-  if (callable &&
-      (!callable.getCallableRegion() || callable.getCallableRegion()->empty()))
+  if (callable && (!callable.getCallableRegion() ||
+                   callable.getCallableRegion()->empty())) {
+    LDBG() << "  Callee has no region or empty region, handling as external "
+              "callee";
     return visitCallControlFlowTransfer(
         call, CallControlFlowAction::ExternalCallee, after, before);
+  }
 
-  if (!callable)
+  if (!callable) {
+    LDBG() << "  No callable found, setting to exit state";
     return setToExitState(before);
+  }
 
   Region *region = callable.getCallableRegion();
+  LDBG() << "  Processing callable with region";
 
   // Call-level control flow specifies the data flow here.
   //
@@ -332,6 +478,7 @@ void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(
   ProgramPoint *calleeEntry = getProgramPointBefore(calleeEntryBlock);
   const AbstractDen...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/161503


More information about the Mlir-commits mailing list