[Mlir-commits] [mlir] 8475e5c - [mlir] Use wouldOpBeTriviallyDead in LivenessAnalysis (#174362)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Jan 5 17:03:33 PST 2026
Author: neildhar
Date: 2026-01-05T17:03:28-08:00
New Revision: 8475e5c5089f51bbb5479e60c2118ca8e5ed0357
URL: https://github.com/llvm/llvm-project/commit/8475e5c5089f51bbb5479e60c2118ca8e5ed0357
DIFF: https://github.com/llvm/llvm-project/commit/8475e5c5089f51bbb5479e60c2118ca8e5ed0357.diff
LOG: [mlir] Use wouldOpBeTriviallyDead in LivenessAnalysis (#174362)
Note: This is a "stacked PR" and depends on #174356. The intention is to
merge that PR first.
`wouldOpBeTriviallyDead` is closer to the intended purpose here, and
aligns the code with how the greedy pattern rewriter identifies dead
operations.
Importantly, it allows us to identify unused read-only memory
operations, which would previously have failed the `isMemoryEffectFree`
check.
Added:
Modified:
mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
index fff39affd284c..11fcc2a4d00d7 100644
--- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
@@ -82,7 +82,7 @@ LivenessAnalysis::visitOperation(Operation *op, ArrayRef<Liveness *> operands,
LDBG() << "[visitOperation] Enter: "
<< OpWithFlags(op, OpPrintingFlags().skipRegions());
// This marks values of type (1.a) and (4) liveness as "live".
- if (!isMemoryEffectFree(op) || op->hasTrait<OpTrait::ReturnLike>()) {
+ if (!wouldOpBeTriviallyDead(op)) {
LDBG() << "[visitOperation] Operation has memory effects or is "
"return-like, marking operands live";
for (auto *operand : operands) {
@@ -131,18 +131,9 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
// the forwarded branch operands or the non-branch operands. Thus they need
// to be handled separately. This is where we handle them.
- if (isa<BranchOpInterface>(op)) {
- // 1. BranchOpInterface: We cannot track all successor blocks. Therefore, we
- // conservatively consider the non-forwarded operand of the branch operation
- // live.
- LDBG() << "[visitBranchOperand] Non-forwarded branch operand may "
- "be live due to branch op interface"
- << operand.get();
- Liveness *operandLiveness = getLatticeElement(operand.get());
- propagateIfChanged(operandLiveness, operandLiveness->markLive());
- return;
- }
-
+ // 1. BranchOpInterface: We cannot track all successor blocks. Therefore, we
+ // conservatively consider the non-forwarded operand of the branch operation
+ // live. We can just call visitOperation, which treats any terminator as live.
// 2. RegionBranchOpInterface: We can simply visit it as a normal operation
// with this operand. The operand is live if the results of the op are used,
// or if it has any recursive memory side effects (which visitOperation will
diff --git a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
index 171a35fdeafb9..a3cd10f785b1d 100644
--- a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
+++ b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
@@ -336,7 +336,7 @@ func.func @affine_loop_no_use_iv_has_side_effect_op() {
// CHECK-NEXT: region: #0:
// CHECK-NEXT: argument: #0: not live
func.func @affine_loop_no_use_iv() {
- affine.for %arg0 = 0 to 79 {
+ affine.for %arg0 = 0 to 79 {
} {tag = "for"}
return
}
@@ -351,9 +351,29 @@ func.func @affine_loop_no_use_iv() {
func.func @forall_no_use_iv_has_side_effect_op(%idx1: index, %idx2: index) {
scf.parallel (%i) = (%idx1) to (%idx2) step (%idx2) {
%r = memref.alloca() : memref<10xf32>
+ %cst = arith.constant 0.0 : f32
scf.forall (%e2) in (%idx2) {
- %a = memref.load %r[%idx2] : memref<10xf32>
+ memref.store %cst, %r[%idx2] : memref<10xf32>
} {tag = "forall"}
- }
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: for:
+// CHECK-NEXT: operand #0: not live
+// CHECK-NEXT: operand #1: not live
+// CHECK-NEXT: operand #2: not live
+// CHECK-NEXT: operand #3: not live
+
+func.func @test_for_loop_read_only(%arg0: memref<10xindex>) {
+ %c0 = arith.constant 0 : index
+ %c10 = arith.constant 10 : index
+ %c1 = arith.constant 1 : index
+ %0 = scf.for %iv = %c0 to %c10 step %c1 iter_args(%idx = %c0) -> (index) {
+ %loaded = memref.load %arg0[%idx] : memref<10xindex>
+ scf.yield %loaded : index
+ } {tag = "for"}
return
}
More information about the Mlir-commits
mailing list