3333
3434#include " mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
3535#include " mlir/Analysis/DataFlow/LivenessAnalysis.h"
36+ #include " mlir/Dialect/UB/IR/UBOps.h"
3637#include " mlir/IR/Builders.h"
3738#include " mlir/IR/BuiltinAttributes.h"
3839#include " mlir/IR/Dialect.h"
@@ -141,33 +142,6 @@ static bool hasLive(ValueRange values, const DenseSet<Value> &nonLiveSet,
141142 return false ;
142143}
143144
144- // / Return true iff at least one value in `values` is dead, given the liveness
145- // / information in `la`.
146- static bool hasDead (ValueRange values, const DenseSet<Value> &nonLiveSet,
147- RunLivenessAnalysis &la) {
148- for (Value value : values) {
149- if (nonLiveSet.contains (value)) {
150- LDBG () << " Value " << value << " is already marked non-live (dead)" ;
151- return true ;
152- }
153-
154- const Liveness *liveness = la.getLiveness (value);
155- if (!liveness) {
156- LDBG () << " Value " << value
157- << " has no liveness info, conservatively considered live" ;
158- continue ;
159- }
160- if (liveness->isLive ) {
161- LDBG () << " Value " << value << " is live according to liveness analysis" ;
162- continue ;
163- } else {
164- LDBG () << " Value " << value << " is dead according to liveness analysis" ;
165- return true ;
166- }
167- }
168- return false ;
169- }
170-
171145// / Return a BitVector of size `values.size()` where its i-th bit is 1 iff the
172146// / i-th value in `values` is live, given the liveness information in `la`.
173147static BitVector markLives (ValueRange values, const DenseSet<Value> &nonLiveSet,
@@ -287,7 +261,12 @@ static SmallVector<OpOperand *> operandsToOpOperands(OperandRange operands) {
287261static void processSimpleOp (Operation *op, RunLivenessAnalysis &la,
288262 DenseSet<Value> &nonLiveSet,
289263 RDVFinalCleanupList &cl) {
290- if (hasDead (op->getOperands (), nonLiveSet, la)) {
264+ // Operations that have dead operands can be erased regardless of their
265+ // side effects. The liveness analysis would not have marked an SSA value as
266+ // "dead" if it had a side-effecting user that is reachable.
267+ bool hasDeadOperand =
268+ markLives (op->getOperands (), nonLiveSet, la).flip ().any ();
269+ if (hasDeadOperand) {
291270 LDBG () << " Simple op has dead operands, so the op must be dead: "
292271 << OpWithFlags (op, OpPrintingFlags ().skipRegions ());
293272 assert (!hasLive (op->getResults (), nonLiveSet, la) &&
@@ -399,6 +378,8 @@ static void processFuncOp(FunctionOpInterface funcOp, Operation *module,
399378 // block other than the entry block, because every block has a terminator.
400379 for (Block &block : funcOp.getBlocks ()) {
401380 Operation *returnOp = block.getTerminator ();
381+ if (!returnOp->hasTrait <OpTrait::ReturnLike>())
382+ continue ;
402383 if (returnOp && returnOp->getNumOperands () == numReturns)
403384 cl.operands .push_back ({returnOp, nonLiveRets});
404385 }
@@ -738,7 +719,11 @@ static void processRegionBranchOp(RegionBranchOpInterface regionBranchOp,
738719}
739720
740721// / Steps to process a `BranchOpInterface` operation:
741- // / Iterate through each successor block of `branchOp`.
722+ // /
723+ // / When a non-forwarded operand is dead (e.g., the condition value of a
724+ // / conditional branch op), the entire operation is dead.
725+ // /
726+ // / Otherwise, iterate through each successor block of `branchOp`.
742727// / (1) For each successor block, gather all operands from all successors.
743728// / (2) Fetch their associated liveness analysis data and collect for future
744729// / removal.
@@ -749,7 +734,22 @@ static void processBranchOp(BranchOpInterface branchOp, RunLivenessAnalysis &la,
749734 DenseSet<Value> &nonLiveSet,
750735 RDVFinalCleanupList &cl) {
751736 LDBG () << " Processing branch op: " << *branchOp;
737+
738+ // Check for dead non-forwarded operands.
739+ BitVector deadNonForwardedOperands =
740+ markLives (branchOp->getOperands (), nonLiveSet, la).flip ();
752741 unsigned numSuccessors = branchOp->getNumSuccessors ();
742+ for (unsigned succIdx = 0 ; succIdx < numSuccessors; ++succIdx) {
743+ SuccessorOperands successorOperands =
744+ branchOp.getSuccessorOperands (succIdx);
745+ // Remove all non-forwarded operands from the bit vector.
746+ for (OpOperand &opOperand : successorOperands.getMutableForwardedOperands ())
747+ deadNonForwardedOperands[opOperand.getOperandNumber ()] = false ;
748+ }
749+ if (deadNonForwardedOperands.any ()) {
750+ cl.operations .push_back (branchOp.getOperation ());
751+ return ;
752+ }
753753
754754 for (unsigned succIdx = 0 ; succIdx < numSuccessors; ++succIdx) {
755755 Block *successorBlock = branchOp->getSuccessor (succIdx);
@@ -824,9 +824,14 @@ static void cleanUpDeadVals(RDVFinalCleanupList &list) {
824824
825825 // 3. Operations
826826 LDBG () << " Cleaning up " << list.operations .size () << " operations" ;
827- for (auto & op : list.operations ) {
827+ for (Operation * op : list.operations ) {
828828 LDBG () << " Erasing operation: "
829829 << OpWithFlags (op, OpPrintingFlags ().skipRegions ());
830+ if (op->hasTrait <OpTrait::IsTerminator>()) {
831+ // When erasing a terminator, insert an unreachable op in its place.
832+ OpBuilder b (op);
833+ ub::UnreachableOp::create (b, op->getLoc ());
834+ }
830835 op->dropAllUses ();
831836 op->erase ();
832837 }
0 commit comments