[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