diff --git a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp index e805e21d878bf..1abdfcbf3496f 100644 --- a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp @@ -22,9 +22,14 @@ #include "mlir/Interfaces/ControlFlowInterfaces.h" #include "mlir/Support/LLVM.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" #include #include +#define DEBUG_TYPE "dead-code-analysis" +#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ") +#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n") + using namespace mlir; using namespace mlir::dataflow; @@ -122,6 +127,7 @@ DeadCodeAnalysis::DeadCodeAnalysis(DataFlowSolver &solver) } LogicalResult DeadCodeAnalysis::initialize(Operation *top) { + LDBG("Initializing DeadCodeAnalysis for top-level op: " << top->getName()); // Mark the top-level blocks as executable. for (Region ®ion : top->getRegions()) { if (region.empty()) @@ -129,6 +135,7 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) { auto *state = getOrCreate(getProgramPointBefore(®ion.front())); propagateIfChanged(state, state->setToLive()); + LDBG("Marked entry block live for region in op: " << top->getName()); } // Mark as overdefined the predecessors of symbol callables with potentially @@ -139,13 +146,18 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) { } void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) { + LDBG("[init] Entering initializeSymbolCallables for top-level op: " + << top->getName()); analysisScope = top; auto walkFn = [&](Operation *symTable, bool allUsesVisible) { + LDBG("[init] Processing symbol table op: " << symTable->getName()); Region &symbolTableRegion = symTable->getRegion(0); Block *symbolTableBlock = &symbolTableRegion.front(); bool foundSymbolCallable = false; for (auto callable : symbolTableBlock->getOps()) { + LDBG("[init] Found CallableOpInterface: " + << callable.getOperation()->getName()); Region *callableRegion = callable.getCallableRegion(); if (!callableRegion) continue; @@ -159,6 +171,8 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) { auto *state = getOrCreate(getProgramPointAfter(callable)); propagateIfChanged(state, state->setHasUnknownPredecessors()); + LDBG("[init] Marked callable as having unknown predecessors: " + << callable.getOperation()->getName()); } foundSymbolCallable = true; } @@ -173,10 +187,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) { if (!uses) { // If we couldn't gather the symbol uses, conservatively assume that // we can't track information for any nested symbols. + LDBG("[init] Could not gather symbol uses, conservatively marking " + "all nested callables as having unknown predecessors"); return top->walk([&](CallableOpInterface callable) { auto *state = getOrCreate(getProgramPointAfter(callable)); propagateIfChanged(state, state->setHasUnknownPredecessors()); + LDBG("[init] Marked nested callable as " + "having unknown predecessors: " + << callable.getOperation()->getName()); }); } @@ -190,10 +209,15 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) { continue; auto *state = getOrCreate(getProgramPointAfter(symbol)); propagateIfChanged(state, state->setHasUnknownPredecessors()); + LDBG("[init] Found non-call use for symbol, " + "marked as having unknown predecessors: " + << symbol->getName()); } }; SymbolTable::walkSymbolTables(top, /*allSymUsesVisible=*/!top->getBlock(), walkFn); + LDBG("[init] Finished initializeSymbolCallables for top-level op: " + << top->getName()); } /// Returns true if the operation is a returning terminator in region @@ -205,9 +229,12 @@ static bool isRegionOrCallableReturn(Operation *op) { } LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) { + LDBG("[init] Entering initializeRecursively for op: " << op->getName() + << " at " << op); // Initialize the analysis by visiting every op with control-flow semantics. if (op->getNumRegions() || op->getNumSuccessors() || isRegionOrCallableReturn(op) || isa(op)) { + LDBG("[init] Visiting op with control-flow semantics: " << *op); // When the liveness of the parent block changes, make sure to re-invoke the // analysis on the op. if (op->getBlock()) @@ -218,14 +245,22 @@ LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) { return failure(); } // Recurse on nested operations. - for (Region ®ion : op->getRegions()) - for (Operation &op : region.getOps()) - if (failed(initializeRecursively(&op))) + for (Region ®ion : op->getRegions()) { + LDBG("[init] Recursing into region of op: " << op->getName()); + for (Operation &nestedOp : region.getOps()) { + LDBG("[init] Recursing into nested op: " << nestedOp.getName() << " at " + << &nestedOp); + if (failed(initializeRecursively(&nestedOp))) return failure(); + } + } + LDBG("[init] Finished initializeRecursively for op: " << op->getName() + << " at " << op); return success(); } void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) { + LDBG("Marking edge live from block " << from << " to block " << to); auto *state = getOrCreate(getProgramPointBefore(to)); propagateIfChanged(state, state->setToLive()); auto *edgeState = @@ -234,37 +269,48 @@ void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) { } void DeadCodeAnalysis::markEntryBlocksLive(Operation *op) { + LDBG("Marking entry blocks live for op: " << op->getName()); for (Region ®ion : op->getRegions()) { if (region.empty()) continue; auto *state = getOrCreate(getProgramPointBefore(®ion.front())); propagateIfChanged(state, state->setToLive()); + LDBG("Marked entry block live for region in op: " << op->getName()); } } LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) { + LDBG("Visiting program point: " << point << " " << *point); if (point->isBlockStart()) return success(); Operation *op = point->getPrevOp(); + LDBG("Visiting operation: " << *op); // If the parent block is not executable, there is nothing to do. if (op->getBlock() != nullptr && - !getOrCreate(getProgramPointBefore(op->getBlock()))->isLive()) + !getOrCreate(getProgramPointBefore(op->getBlock())) + ->isLive()) { + LDBG("Parent block not live, skipping op: " << *op); return success(); + } // We have a live call op. Add this as a live predecessor of the callee. - if (auto call = dyn_cast(op)) + if (auto call = dyn_cast(op)) { + LDBG("Visiting call operation: " << *op); visitCallOperation(call); + } // Visit the regions. if (op->getNumRegions()) { // Check if we can reason about the region control-flow. if (auto branch = dyn_cast(op)) { + LDBG("Visiting region branch operation: " << *op); visitRegionBranchOperation(branch); // Check if this is a callable operation. } else if (auto callable = dyn_cast(op)) { + LDBG("Visiting callable operation: " << *op); const auto *callsites = getOrCreateFor( getProgramPointAfter(op), getProgramPointAfter(callable)); @@ -276,16 +322,19 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) { // Otherwise, conservatively mark all entry blocks as executable. } else { + LDBG("Marking all entry blocks live for op: " << *op); markEntryBlocksLive(op); } } if (isRegionOrCallableReturn(op)) { if (auto branch = dyn_cast(op->getParentOp())) { + LDBG("Visiting region terminator: " << *op); // Visit the exiting terminator of a region. visitRegionTerminator(op, branch); } else if (auto callable = dyn_cast(op->getParentOp())) { + LDBG("Visiting callable terminator: " << *op); // Visit the exiting terminator of a callable. visitCallableTerminator(op, callable); } @@ -294,10 +343,12 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) { if (op->getNumSuccessors()) { // Check if we can reason about the control-flow. if (auto branch = dyn_cast(op)) { + LDBG("Visiting branch operation: " << *op); visitBranchOperation(branch); // Otherwise, conservatively mark all successors as exectuable. } else { + LDBG("Marking all successors live for op: " << *op); for (Block *successor : op->getSuccessors()) markEdgeLive(op->getBlock(), successor); } @@ -307,6 +358,7 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) { } void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) { + LDBG("visitCallOperation: " << call.getOperation()->getName()); Operation *callableOp = call.resolveCallableInTable(&symbolTable); // A call to a externally-defined callable has unknown predecessors. @@ -329,11 +381,15 @@ void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) { auto *callsites = getOrCreate(getProgramPointAfter(callableOp)); propagateIfChanged(callsites, callsites->join(call)); + LDBG("Added callsite as predecessor for callable: " + << callableOp->getName()); } else { // Mark this call op's predecessors as overdefined. auto *predecessors = getOrCreate(getProgramPointAfter(call)); propagateIfChanged(predecessors, predecessors->setHasUnknownPredecessors()); + LDBG("Marked call op's predecessors as unknown for: " + << call.getOperation()->getName()); } } @@ -365,6 +421,7 @@ DeadCodeAnalysis::getOperandValues(Operation *op) { } void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch) { + LDBG("visitBranchOperation: " << branch.getOperation()->getName()); // Try to deduce a single successor for the branch. std::optional> operands = getOperandValues(branch); if (!operands) @@ -372,15 +429,18 @@ void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch) { if (Block *successor = branch.getSuccessorForOperands(*operands)) { markEdgeLive(branch->getBlock(), successor); + LDBG("Branch has single successor: " << successor); } else { // Otherwise, mark all successors as executable and outgoing edges. for (Block *successor : branch->getSuccessors()) markEdgeLive(branch->getBlock(), successor); + LDBG("Branch has multiple/all successors live"); } } void DeadCodeAnalysis::visitRegionBranchOperation( RegionBranchOpInterface branch) { + LDBG("visitRegionBranchOperation: " << branch.getOperation()->getName()); // Try to deduce which regions are executable. std::optional> operands = getOperandValues(branch); if (!operands) @@ -397,16 +457,19 @@ void DeadCodeAnalysis::visitRegionBranchOperation( // Mark the entry block as executable. auto *state = getOrCreate(point); propagateIfChanged(state, state->setToLive()); + LDBG("Marked region successor live: " << point); // Add the parent op as a predecessor. auto *predecessors = getOrCreate(point); propagateIfChanged( predecessors, predecessors->join(branch, successor.getSuccessorInputs())); + LDBG("Added region branch as predecessor for successor: " << point); } } void DeadCodeAnalysis::visitRegionTerminator(Operation *op, RegionBranchOpInterface branch) { + LDBG("visitRegionTerminator: " << *op); std::optional> operands = getOperandValues(op); if (!operands) return; @@ -425,6 +488,7 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op, auto *state = getOrCreate(getProgramPointBefore(®ion->front())); propagateIfChanged(state, state->setToLive()); + LDBG("Marked region entry block live for region: " << region); predecessors = getOrCreate( getProgramPointBefore(®ion->front())); } else { @@ -434,11 +498,14 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op, } propagateIfChanged(predecessors, predecessors->join(op, successor.getSuccessorInputs())); + LDBG("Added region terminator as predecessor for successor: " + << (successor.getSuccessor() ? "region entry" : "parent op")); } } void DeadCodeAnalysis::visitCallableTerminator(Operation *op, CallableOpInterface callable) { + LDBG("visitCallableTerminator: " << *op); // Add as predecessors to all callsites this return op. auto *callsites = getOrCreateFor( getProgramPointAfter(op), getProgramPointAfter(callable)); @@ -449,11 +516,15 @@ void DeadCodeAnalysis::visitCallableTerminator(Operation *op, getOrCreate(getProgramPointAfter(predecessor)); if (canResolve) { propagateIfChanged(predecessors, predecessors->join(op)); + LDBG("Added callable terminator as predecessor for callsite: " + << predecessor->getName()); } else { // If the terminator is not a return-like, then conservatively assume we // can't resolve the predecessor. propagateIfChanged(predecessors, predecessors->setHasUnknownPredecessors()); + LDBG("Could not resolve callable terminator for callsite: " + << predecessor->getName()); } } } diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index 24a78400eb84a..6a12fe3acc2c2 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,10 @@ #include #include +#define DEBUG_TYPE "liveness-analysis" +#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ") +#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n") + using namespace mlir; using namespace mlir::dataflow; @@ -76,28 +81,46 @@ ChangeResult Liveness::meet(const AbstractSparseLattice &other) { LogicalResult LivenessAnalysis::visitOperation(Operation *op, ArrayRef operands, ArrayRef results) { + LLVM_DEBUG(DBGS() << "[visitOperation] Enter: "; + op->print(llvm::dbgs(), OpPrintingFlags().skipRegions()); + llvm::dbgs() << "\n"); // This marks values of type (1.a) and (4) liveness as "live". if (!isMemoryEffectFree(op) || op->hasTrait()) { - for (auto *operand : operands) + LDBG("[visitOperation] Operation has memory effects or is " + "return-like, marking operands live"); + for (auto *operand : operands) { + LDBG(" [visitOperation] Marking operand live: " + << operand << " (" << operand->isLive << ")"); propagateIfChanged(operand, operand->markLive()); + } } // This marks values of type (3) liveness as "live". bool foundLiveResult = false; for (const Liveness *r : results) { if (r->isLive && !foundLiveResult) { + LDBG("[visitOperation] Found live result, " + "meeting all operands with result: " + << r); // It is assumed that each operand is used to compute each result of an // op. Thus, if at least one result is live, each operand is live. - for (Liveness *operand : operands) + for (Liveness *operand : operands) { + LDBG(" [visitOperation] Meeting operand: " << operand + << " with result: " << r); meet(operand, *r); + } foundLiveResult = true; } + LDBG("[visitOperation] Adding dependency for result: " << r << " after op: " + << *op); addDependency(const_cast(r), getProgramPointAfter(op)); } return success(); } void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { + LDBG("Visiting branch operand: " << operand.get() + << " in op: " << *operand.getOwner()); // We know (at the moment) and assume (for the future) that `operand` is a // non-forwarded branch operand of a `RegionBranchOpInterface`, // `BranchOpInterface`, `RegionBranchTerminatorOpInterface` or return-like op. @@ -129,6 +152,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { for (Value result : op->getResults()) { if (getLatticeElement(result)->isLive) { mayLive = true; + LDBG("[visitBranchOperand] Non-forwarded branch " + "operand may be live due to live result: " + << result); break; } } @@ -148,6 +174,8 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { // Therefore, we conservatively consider the non-forwarded operand of the // branch operation may live. mayLive = true; + LDBG("[visitBranchOperand] Non-forwarded branch operand may " + "be live due to branch op interface"); } else { Operation *parentOp = op->getParentOp(); assert(isa(parentOp) && @@ -163,6 +191,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { for (Value result : parentOp->getResults()) { if (getLatticeElement(result)->isLive) { mayLive = true; + LDBG("[visitBranchOperand] Non-forwarded branch " + "operand may be live due to parent live result: " + << result); break; } } @@ -183,6 +214,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { for (Operation &nestedOp : *block) { if (!isMemoryEffectFree(&nestedOp)) { mayLive = true; + LDBG("Non-forwarded branch operand may be " + "live due to memory effect in block: " + << block); break; } } @@ -190,6 +224,7 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { if (mayLive) { Liveness *operandLiveness = getLatticeElement(operand.get()); + LDBG("Marking branch operand live: " << operand.get()); propagateIfChanged(operandLiveness, operandLiveness->markLive()); } @@ -201,6 +236,7 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { SmallVector resultsLiveness; for (const Value result : op->getResults()) resultsLiveness.push_back(getLatticeElement(result)); + LDBG("Visiting operation for non-forwarded branch operand: " << *op); (void)visitOperation(op, operandLiveness, resultsLiveness); // We also visit the parent op with the parent's results and this operand if @@ -213,10 +249,14 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { SmallVector parentResultsLiveness; for (const Value parentResult : parentOp->getResults()) parentResultsLiveness.push_back(getLatticeElement(parentResult)); + LDBG("Visiting parent operation for non-forwarded branch operand: " + << *parentOp); (void)visitOperation(parentOp, operandLiveness, parentResultsLiveness); } void LivenessAnalysis::visitCallOperand(OpOperand &operand) { + LDBG("Visiting call operand: " << operand.get() + << " in op: " << *operand.getOwner()); // We know (at the moment) and assume (for the future) that `operand` is a // non-forwarded call operand of an op implementing `CallOpInterface`. assert(isa(operand.getOwner()) && @@ -229,14 +269,18 @@ void LivenessAnalysis::visitCallOperand(OpOperand &operand) { // This marks values of type (1.c) liveness as "live". A non-forwarded // call operand is live. Liveness *operandLiveness = getLatticeElement(operand.get()); + LDBG("Marking call operand live: " << operand.get()); propagateIfChanged(operandLiveness, operandLiveness->markLive()); } void LivenessAnalysis::setToExitState(Liveness *lattice) { + LDBG("setToExitState for lattice: " << lattice); if (lattice->isLive) { + LDBG("Lattice already live, nothing to do"); return; } // This marks values of type (2) liveness as "live". + LDBG("Marking lattice live due to exit state"); (void)lattice->markLive(); propagateIfChanged(lattice, ChangeResult::Change); } @@ -246,11 +290,14 @@ void LivenessAnalysis::setToExitState(Liveness *lattice) { //===----------------------------------------------------------------------===// RunLivenessAnalysis::RunLivenessAnalysis(Operation *op) { + LDBG("Constructing RunLivenessAnalysis for op: " << op->getName()); SymbolTableCollection symbolTable; loadBaselineAnalyses(solver); solver.load(symbolTable); + LDBG("Initializing and running solver"); (void)solver.initializeAndRun(op); + LDBG("Dumping liveness state for op"); } const Liveness *RunLivenessAnalysis::getLiveness(Value val) { diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp index 08dfea8eb2648..ad21ce8f18700 100644 --- a/mlir/lib/Transforms/RemoveDeadValues.cpp +++ b/mlir/lib/Transforms/RemoveDeadValues.cpp @@ -52,12 +52,17 @@ #include "mlir/Transforms/FoldUtils.h" #include "mlir/Transforms/Passes.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" #include #include #include #include #include +#define DEBUG_TYPE "remove-dead-values" +#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ") +#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n") + namespace mlir { #define GEN_PASS_DEF_REMOVEDEADVALUES #include "mlir/Transforms/Passes.h.inc" @@ -115,12 +120,23 @@ struct RDVFinalCleanupList { static bool hasLive(ValueRange values, const DenseSet &nonLiveSet, RunLivenessAnalysis &la) { for (Value value : values) { - if (nonLiveSet.contains(value)) + if (nonLiveSet.contains(value)) { + LDBG("Value " << value << " is already marked non-live (dead)"); continue; + } const Liveness *liveness = la.getLiveness(value); - if (!liveness || liveness->isLive) + if (!liveness) { + LDBG("Value " << value + << " has no liveness info, conservatively considered live"); return true; + } + if (liveness->isLive) { + LDBG("Value " << value << " is live according to liveness analysis"); + return true; + } else { + LDBG("Value " << value << " is dead according to liveness analysis"); + } } return false; } @@ -134,6 +150,8 @@ static BitVector markLives(ValueRange values, const DenseSet &nonLiveSet, for (auto [index, value] : llvm::enumerate(values)) { if (nonLiveSet.contains(value)) { lives.reset(index); + LDBG("Value " << value << " is already marked non-live (dead) at index " + << index); continue; } @@ -144,8 +162,19 @@ static BitVector markLives(ValueRange values, const DenseSet &nonLiveSet, // of the results of an op and we know that these new values are live // (because they weren't erased) and also their liveness is null because // liveness analysis ran before their creation. - if (liveness && !liveness->isLive) + if (!liveness) { + LDBG("Value " << value << " at index " << index + << " has no liveness info, conservatively considered live"); + continue; + } + if (!liveness->isLive) { lives.reset(index); + LDBG("Value " << value << " at index " << index + << " is dead according to liveness analysis"); + } else { + LDBG("Value " << value << " at index " << index + << " is live according to liveness analysis"); + } } return lives; @@ -160,6 +189,8 @@ static void collectNonLiveValues(DenseSet &nonLiveSet, ValueRange range, if (!nonLive[index]) continue; nonLiveSet.insert(result); + LDBG("Marking value " << result << " as non-live (dead) at index " + << index); } } @@ -229,9 +260,16 @@ static SmallVector operandsToOpOperands(OperandRange operands) { static void processSimpleOp(Operation *op, RunLivenessAnalysis &la, DenseSet &nonLiveSet, RDVFinalCleanupList &cl) { - if (!isMemoryEffectFree(op) || hasLive(op->getResults(), nonLiveSet, la)) + LDBG("Processing simple op: " << *op); + if (!isMemoryEffectFree(op) || hasLive(op->getResults(), nonLiveSet, la)) { + LDBG("Simple op is not memory effect free or has live results, skipping: " + << *op); return; + } + LDBG("Simple op has all dead results and is memory effect free, scheduling " + "for removal: " + << *op); cl.operations.push_back(op); collectNonLiveValues(nonLiveSet, op->getResults(), BitVector(op->getNumResults(), true)); @@ -250,8 +288,12 @@ static void processSimpleOp(Operation *op, RunLivenessAnalysis &la, static void processFuncOp(FunctionOpInterface funcOp, Operation *module, RunLivenessAnalysis &la, DenseSet &nonLiveSet, RDVFinalCleanupList &cl) { - if (funcOp.isPublic() || funcOp.isExternal()) + LDBG("Processing function op: " << funcOp.getOperation()->getName()); + if (funcOp.isPublic() || funcOp.isExternal()) { + LDBG("Function is public or external, skipping: " + << funcOp.getOperation()->getName()); return; + } // Get the list of unnecessary (non-live) arguments in `nonLiveArgs`. SmallVector arguments(funcOp.getArguments()); @@ -369,6 +411,9 @@ static void processRegionBranchOp(RegionBranchOpInterface regionBranchOp, RunLivenessAnalysis &la, DenseSet &nonLiveSet, RDVFinalCleanupList &cl) { + LLVM_DEBUG(DBGS() << "Processing region branch op: "; regionBranchOp->print( + llvm::dbgs(), OpPrintingFlags().skipRegions()); + llvm::dbgs() << "\n"); // Mark live results of `regionBranchOp` in `liveResults`. auto markLiveResults = [&](BitVector &liveResults) { liveResults = markLives(regionBranchOp->getResults(), nonLiveSet, la); @@ -654,6 +699,7 @@ static void processRegionBranchOp(RegionBranchOpInterface regionBranchOp, static void processBranchOp(BranchOpInterface branchOp, RunLivenessAnalysis &la, DenseSet &nonLiveSet, RDVFinalCleanupList &cl) { + LDBG("Processing branch op: " << *branchOp); unsigned numSuccessors = branchOp->getNumSuccessors(); for (unsigned succIdx = 0; succIdx < numSuccessors; ++succIdx) {