diff options
Diffstat (limited to 'mlir/lib/Analysis')
-rw-r--r-- | mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp | 4 | ||||
-rw-r--r-- | mlir/lib/Analysis/DataFlow/DenseAnalysis.cpp | 233 |
2 files changed, 212 insertions, 25 deletions
diff --git a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp index de1ed39..377f7eb 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 b51465b..daa3db5 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 ®ion : 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 ®ion : 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 AbstractDenseLattice &latticeAtCalleeEntry = *getLatticeFor(getProgramPointBefore(call.getOperation()), calleeEntry); + LDBG() << " Lattice at callee entry: " << latticeAtCalleeEntry; AbstractDenseLattice *latticeBeforeCall = before; visitCallControlFlowTransfer(call, CallControlFlowAction::EnterCallee, latticeAtCalleeEntry, latticeBeforeCall); @@ -339,12 +486,16 @@ void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation( LogicalResult AbstractDenseBackwardDataFlowAnalysis::processOperation(Operation *op) { + LDBG() << "processOperation (backward): " + << OpWithFlags(op, OpPrintingFlags().skipRegions()); ProgramPoint *point = getProgramPointBefore(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 *before = getLattice(point); @@ -352,30 +503,39 @@ AbstractDenseBackwardDataFlowAnalysis::processOperation(Operation *op) { // Get the dense state after execution of this op. const AbstractDenseLattice *after = getLatticeFor(point, getProgramPointAfter(op)); + LDBG() << " before state: " << *before; + LDBG() << " after state: " << *after; // Special cases where control flow may dictate data flow. if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) { + LDBG() << " Processing as region branch operation"; visitRegionBranchOperation(point, branch, RegionBranchPoint::parent(), before); return success(); } if (auto call = dyn_cast<CallOpInterface>(op)) { + LDBG() << " Processing as call operation"; visitCallOperation(call, *after, before); return success(); } // Invoke the operation transfer function. + LDBG() << " Invoking operation transfer function"; return visitOperationImpl(op, *after, before); } void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) { + LDBG() << "visitBlock (backward): " << block; ProgramPoint *point = getProgramPointAfter(block); // If the block is not executable, bail out. if (!getOrCreateFor<Executable>(point, getProgramPointBefore(block)) - ->isLive()) + ->isLive()) { + LDBG() << " Block not executable, skipping"; return; + } AbstractDenseLattice *before = getLattice(point); + LDBG() << " Block lattice state: " << *before; // We need "exit" blocks, i.e. the blocks that may return control to the // parent operation. @@ -391,23 +551,32 @@ void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) { b->getTerminator()); }; if (isExitBlock(block)) { + LDBG() << " Processing exit block"; // If this block is exiting from a callable, the successors of exiting from // a callable are the successors of all call sites. And the call sites // themselves are predecessors of the callable. auto callable = dyn_cast<CallableOpInterface>(block->getParentOp()); if (callable && callable.getCallableRegion() == block->getParent()) { + LDBG() << " Exit block of callable region"; const auto *callsites = getOrCreateFor<PredecessorState>( point, getProgramPointAfter(callable)); // If not all call sites are known, conservative mark all lattices as // having reached their pessimistic fix points. if (!callsites->allPredecessorsKnown() || !getSolverConfig().isInterprocedural()) { + LDBG() << " Not all callsites known or non-interprocedural, setting " + "to exit state"; return setToExitState(before); } + LDBG() << " Processing " << callsites->getKnownPredecessors().size() + << " known callsites"; for (Operation *callsite : callsites->getKnownPredecessors()) { + LDBG() << " Processing callsite: " + << OpWithFlags(callsite, OpPrintingFlags().skipRegions()); const AbstractDenseLattice *after = getLatticeFor(point, getProgramPointAfter(callsite)); + LDBG() << " Lattice after callsite: " << *after; visitCallControlFlowTransfer(cast<CallOpInterface>(callsite), CallControlFlowAction::ExitCallee, *after, before); @@ -418,22 +587,29 @@ void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) { // If this block is exiting from an operation with region-based control // flow, propagate the lattice back along the control flow edge. if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) { + LDBG() << " Exit block of region branch operation"; visitRegionBranchOperation(point, branch, block->getParent(), before); return; } // Cannot reason about successors of an exit block, set the pessimistic // fixpoint. + LDBG() << " Cannot reason about successors, setting to exit state"; return setToExitState(before); } // Meet the state with the state before block's successors. + LDBG() << " Meeting state from " << block->getSuccessors().size() + << " successors"; for (Block *successor : block->getSuccessors()) { if (!getOrCreateFor<Executable>(point, getLatticeAnchor<CFGEdge>(block, successor)) - ->isLive()) + ->isLive()) { + LDBG() << " Skipping non-executable edge to " << successor; continue; + } + LDBG() << " Meeting state from successor " << successor; // Merge in the state from the successor: either the first operation, or the // block itself when empty. meet(before, *getLatticeFor(point, getProgramPointBefore(successor))); @@ -443,28 +619,39 @@ void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) { void AbstractDenseBackwardDataFlowAnalysis::visitRegionBranchOperation( ProgramPoint *point, RegionBranchOpInterface branch, RegionBranchPoint branchPoint, AbstractDenseLattice *before) { + LDBG() << "visitRegionBranchOperation (backward): " + << OpWithFlags(branch.getOperation(), OpPrintingFlags().skipRegions()); + LDBG() << " branchPoint: " << (branchPoint.isParent() ? "parent" : "region"); + LDBG() << " before state: " << *before; // The successors of the operation may be either the first operation of the // entry block of each possible successor region, or the next operation when // the branch is a successor of itself. SmallVector<RegionSuccessor> successors; branch.getSuccessorRegions(branchPoint, successors); + LDBG() << " Processing " << successors.size() << " successor regions"; for (const RegionSuccessor &successor : successors) { const AbstractDenseLattice *after; if (successor.isParent() || successor.getSuccessor()->empty()) { + LDBG() << " Successor is parent or empty region"; after = getLatticeFor(point, getProgramPointAfter(branch)); } else { Region *successorRegion = successor.getSuccessor(); assert(!successorRegion->empty() && "unexpected empty successor region"); Block *successorBlock = &successorRegion->front(); + LDBG() << " Successor region with " + << successorRegion->getBlocks().size() << " blocks"; if (!getOrCreateFor<Executable>(point, getProgramPointBefore(successorBlock)) - ->isLive()) + ->isLive()) { + LDBG() << " Successor block not executable, skipping"; continue; + } after = getLatticeFor(point, getProgramPointBefore(successorBlock)); } + LDBG() << " After state: " << *after; visitRegionBranchControlFlowTransfer(branch, branchPoint, successor, *after, before); |