From 55321b8a9389d7ebf236819c8cfcd77df479aeef Mon Sep 17 00:00:00 2001 From: linuxlonelyeagle <2020382038@qq.com> Date: Mon, 29 Sep 2025 02:42:42 +0000 Subject: [PATCH 1/7] fix liveness-analysis in the loop ivs case. --- .../Analysis/DataFlow/LivenessAnalysis.cpp | 23 +++++++++++++++---- mlir/test/Transforms/remove-dead-values.mlir | 13 +++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index d705d8d4c7819..f540870113e3f 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -309,15 +310,29 @@ RunLivenessAnalysis::RunLivenessAnalysis(Operation *op) { << " has no liveness info (unreachable), mark dead"; solver.getOrCreateState(result.value()); } + SmallVector mustLiveValues; + if (auto loopOp = dyn_cast(op)) { + std::optional> ivs = loopOp.getLoopInductionVars(); + if (ivs.has_value()) + mustLiveValues.append(*ivs); + } for (auto ®ion : op->getRegions()) { for (auto &block : region) { for (auto blockArg : llvm::enumerate(block.getArguments())) { if (getLiveness(blockArg.value())) continue; - LDBG() << "Block argument: " << blockArg.index() << " of " - << OpWithFlags(op, OpPrintingFlags().skipRegions()) - << " has no liveness info, mark dead"; - solver.getOrCreateState(blockArg.value()); + if (llvm::find(mustLiveValues, blockArg.value())) { + LDBG() << "Block argument: " << blockArg.index() << " of " + << OpWithFlags(op, OpPrintingFlags().skipRegions()) + << " is must value, mark live"; + (void)solver.getOrCreateState(blockArg.value()) + ->markLive(); + } else { + LDBG() << "Block argument: " << blockArg.index() << " of " + << OpWithFlags(op, OpPrintingFlags().skipRegions()) + << " has no liveness info, mark dead"; + solver.getOrCreateState(blockArg.value()); + } } } } diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir index 56449469dc29f..979851bc3162d 100644 --- a/mlir/test/Transforms/remove-dead-values.mlir +++ b/mlir/test/Transforms/remove-dead-values.mlir @@ -649,3 +649,16 @@ func.func @callee(%arg0: index, %arg1: index, %arg2: index) -> index { %res = call @mutl_parameter(%arg0, %arg1, %arg2) : (index, index, index) -> (index) return %res : index } + +// ----- + +// This test verifies that the induction variables in loops are not deleted. + +// CHECK-LABEL: func @dead_value_loop_ivs +func.func @dead_value_loop_ivs(%lb: index, %ub: index, %step: index, %b : i1) -> i1 { + %loop_ret = scf.for %iv = %lb to %ub step %step iter_args(%iter = %b) -> (i1) { + cf.assert %b, "loop not dead" + scf.yield %b : i1 + } + return %loop_ret : i1 +} From 1bf4f12940d8e2fbdb925393c97e734088ca7946 Mon Sep 17 00:00:00 2001 From: linuxlonelyeagle <2020382038@qq.com> Date: Thu, 2 Oct 2025 02:56:13 +0000 Subject: [PATCH 2/7] add LoopLikeOpInterface visit logic in the visit function. --- .../Analysis/DataFlow/LivenessAnalysis.cpp | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index f540870113e3f..3611d07695bf9 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -196,6 +196,18 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { break; } } + + // If the parentOp is live and it implements the LoopLiveOpInterface, then + // set its IV as live. + if (mayLive && isa(parentOp)) { + auto loopOp = cast(parentOp); + std::optional> ivs = loopOp.getLoopInductionVars(); + if (ivs.has_value()) { + for (auto iv : *ivs) { + getLatticeElement(iv)->markLive(); + } + } + } } else { // When the op is a `RegionBranchTerminatorOpInterface`, like an // `scf.condition` op or return-like, like an `scf.yield` op, its branch @@ -310,29 +322,16 @@ RunLivenessAnalysis::RunLivenessAnalysis(Operation *op) { << " has no liveness info (unreachable), mark dead"; solver.getOrCreateState(result.value()); } - SmallVector mustLiveValues; - if (auto loopOp = dyn_cast(op)) { - std::optional> ivs = loopOp.getLoopInductionVars(); - if (ivs.has_value()) - mustLiveValues.append(*ivs); - } + for (auto ®ion : op->getRegions()) { for (auto &block : region) { for (auto blockArg : llvm::enumerate(block.getArguments())) { if (getLiveness(blockArg.value())) continue; - if (llvm::find(mustLiveValues, blockArg.value())) { - LDBG() << "Block argument: " << blockArg.index() << " of " - << OpWithFlags(op, OpPrintingFlags().skipRegions()) - << " is must value, mark live"; - (void)solver.getOrCreateState(blockArg.value()) - ->markLive(); - } else { - LDBG() << "Block argument: " << blockArg.index() << " of " - << OpWithFlags(op, OpPrintingFlags().skipRegions()) - << " has no liveness info, mark dead"; - solver.getOrCreateState(blockArg.value()); - } + LDBG() << "Block argument: " << blockArg.index() << " of " + << OpWithFlags(op, OpPrintingFlags().skipRegions()) + << " has no liveness info, mark dead"; + solver.getOrCreateState(blockArg.value()); } } } From e1cfe4ddc616e6cc45408a61aa3dc2f2234f36fe Mon Sep 17 00:00:00 2001 From: linuxlonelyeagle <2020382038@qq.com> Date: Thu, 2 Oct 2025 16:35:01 +0000 Subject: [PATCH 3/7] use RegionBranchOpInterface fix the bug. --- .../Analysis/DataFlow/LivenessAnalysis.cpp | 35 ++++++++++++------- mlir/test/Transforms/remove-dead-values.mlir | 16 +++++++-- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index 3611d07695bf9..b66072fd8c6ad 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -166,6 +165,28 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { blocks.push_back(&block); } } + + // In the block of the successor block argument of RegionBranchOpInterface, + // there may be arguments of RegionBranchOpInterface, such as the IV of + // scf.forOp. Explicitly set this argument to live. + auto regionBranchOp = cast(op); + for (size_t i = 0, e = op->getNumRegions(); i < e; ++i) { + SmallVector successors; + regionBranchOp.getSuccessorRegions(op->getRegion(i), successors); + for (RegionSuccessor successor : successors) { + if (successor.isParent()) + continue; + auto arguments = successor.getSuccessor()->getArguments(); + ValueRange regionInputs = successor.getSuccessorInputs(); + for (auto argument : arguments) { + if (llvm::find(regionInputs, argument) == regionInputs.end()) { + (void)getLatticeElement(argument)->markLive(); + LDBG() << "Marking RegionBranchOp's success argument live: " + << argument; + } + } + } + } } else if (isa(op)) { // We cannot track all successor blocks of the branch operation(More // specifically, it's the successor's successor). Additionally, different @@ -196,18 +217,6 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { break; } } - - // If the parentOp is live and it implements the LoopLiveOpInterface, then - // set its IV as live. - if (mayLive && isa(parentOp)) { - auto loopOp = cast(parentOp); - std::optional> ivs = loopOp.getLoopInductionVars(); - if (ivs.has_value()) { - for (auto iv : *ivs) { - getLatticeElement(iv)->markLive(); - } - } - } } else { // When the op is a `RegionBranchTerminatorOpInterface`, like an // `scf.condition` op or return-like, like an `scf.yield` op, its branch diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir index 979851bc3162d..e7304505c809e 100644 --- a/mlir/test/Transforms/remove-dead-values.mlir +++ b/mlir/test/Transforms/remove-dead-values.mlir @@ -652,13 +652,25 @@ func.func @callee(%arg0: index, %arg1: index, %arg2: index) -> index { // ----- -// This test verifies that the induction variables in loops are not deleted. +// This test verifies that the induction variables in loops are not deleted, the loop has results. // CHECK-LABEL: func @dead_value_loop_ivs -func.func @dead_value_loop_ivs(%lb: index, %ub: index, %step: index, %b : i1) -> i1 { +func.func @dead_value_loop_ivs_has_result(%lb: index, %ub: index, %step: index, %b: i1) -> i1 { %loop_ret = scf.for %iv = %lb to %ub step %step iter_args(%iter = %b) -> (i1) { cf.assert %b, "loop not dead" scf.yield %b : i1 } return %loop_ret : i1 } + +// ----- + +// This test verifies that the induction variables in loops are not deleted, the loop has no results. + +// CHECK-LABEL: func @dead_value_loop_ivs_no_result +func.func @dead_value_loop_ivs_no_result(%lb: index, %ub: index, %step: index, %input: memref, %value: f32, %pos: index) { + scf.for %iv = %lb to %ub step %step { + memref.store %value, %input[%pos] : memref + } + return +} From d81f19ed46ee659aa9da7f23fc33b86c66a3352e Mon Sep 17 00:00:00 2001 From: linuxlonelyeagle <2020382038@qq.com> Date: Mon, 20 Oct 2025 16:50:27 +0000 Subject: [PATCH 4/7] update code. --- .../Analysis/DataFlow/LivenessAnalysis.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index b66072fd8c6ad..d8c324cff4c19 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -137,7 +137,8 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { // Populating such blocks in `blocks`. bool mayLive = false; SmallVector blocks; - if (isa(op)) { + SmallVector argumentNotOperand; + if (auto regionBranchOp = dyn_cast(op)) { if (op->getNumResults() != 0) { // This mark value of type 1.c liveness as may live, because the region // branch operation has a return value, and the non-forwarded operand can @@ -169,10 +170,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { // In the block of the successor block argument of RegionBranchOpInterface, // there may be arguments of RegionBranchOpInterface, such as the IV of // scf.forOp. Explicitly set this argument to live. - auto regionBranchOp = cast(op); - for (size_t i = 0, e = op->getNumRegions(); i < e; ++i) { + for (Region ®ion : op->getRegions()) { SmallVector successors; - regionBranchOp.getSuccessorRegions(op->getRegion(i), successors); + regionBranchOp.getSuccessorRegions(region, successors); for (RegionSuccessor successor : successors) { if (successor.isParent()) continue; @@ -180,9 +180,7 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { ValueRange regionInputs = successor.getSuccessorInputs(); for (auto argument : arguments) { if (llvm::find(regionInputs, argument) == regionInputs.end()) { - (void)getLatticeElement(argument)->markLive(); - LDBG() << "Marking RegionBranchOp's success argument live: " - << argument; + argumentNotOperand.push_back(argument); } } } @@ -246,6 +244,11 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { Liveness *operandLiveness = getLatticeElement(operand.get()); LDBG() << "Marking branch operand live: " << operand.get(); propagateIfChanged(operandLiveness, operandLiveness->markLive()); + for (BlockArgument argument : argumentNotOperand) { + Liveness *argumentLiveness = getLatticeElement(argument); + LDBG() << "Marking RegionBranchOp's argument live: " << argument; + propagateIfChanged(argumentLiveness, argumentLiveness->markLive()); + } } // Now that we have checked for memory-effecting ops in the blocks of concern, @@ -253,6 +256,8 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { // mark it "live" due to type (1.a/3) liveness. SmallVector operandLiveness; operandLiveness.push_back(getLatticeElement(operand.get())); + for (BlockArgument argument : argumentNotOperand) + operandLiveness.push_back(getLatticeElement(argument)); SmallVector resultsLiveness; for (const Value result : op->getResults()) resultsLiveness.push_back(getLatticeElement(result)); From 46cdb02db00436ccc48ff713aa6034e15dd39e4c Mon Sep 17 00:00:00 2001 From: lonely eagle <2020382038@qq.com> Date: Tue, 21 Oct 2025 18:28:08 +0800 Subject: [PATCH 5/7] Update mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp Co-authored-by: Mehdi Amini --- mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index d8c324cff4c19..70e058d2bc2b4 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -247,6 +247,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { for (BlockArgument argument : argumentNotOperand) { Liveness *argumentLiveness = getLatticeElement(argument); LDBG() << "Marking RegionBranchOp's argument live: " << argument; + // TODO: this is overly conservative: we should be able to eliminate unused + // values in a RegionBranchOpInterface operation but that may requires removing + // operation results which is beyond current capabilities of this pass right now. propagateIfChanged(argumentLiveness, argumentLiveness->markLive()); } } From fca73127940eef1899642020931e138a103a4ec9 Mon Sep 17 00:00:00 2001 From: lonely eagle <2020382038@qq.com> Date: Tue, 21 Oct 2025 18:28:19 +0800 Subject: [PATCH 6/7] Update mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp Co-authored-by: Mehdi Amini --- mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index 70e058d2bc2b4..312fe12960368 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -339,7 +339,6 @@ RunLivenessAnalysis::RunLivenessAnalysis(Operation *op) { << " has no liveness info (unreachable), mark dead"; solver.getOrCreateState(result.value()); } - for (auto ®ion : op->getRegions()) { for (auto &block : region) { for (auto blockArg : llvm::enumerate(block.getArguments())) { From efa8008edd5427decd9e87dd2517111528ba12bc Mon Sep 17 00:00:00 2001 From: linuxlonelyeagle <2020382038@qq.com> Date: Tue, 21 Oct 2025 10:30:09 +0000 Subject: [PATCH 7/7] use clang-format. --- mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp index 312fe12960368..20be50c8e8a5b 100644 --- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp +++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp @@ -247,9 +247,10 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) { for (BlockArgument argument : argumentNotOperand) { Liveness *argumentLiveness = getLatticeElement(argument); LDBG() << "Marking RegionBranchOp's argument live: " << argument; - // TODO: this is overly conservative: we should be able to eliminate unused - // values in a RegionBranchOpInterface operation but that may requires removing - // operation results which is beyond current capabilities of this pass right now. + // TODO: this is overly conservative: we should be able to eliminate + // unused values in a RegionBranchOpInterface operation but that may + // requires removing operation results which is beyond current + // capabilities of this pass right now. propagateIfChanged(argumentLiveness, argumentLiveness->markLive()); } }