[Mlir-commits] [mlir] [mlir][dataflow] Add visitBranchRegionArgument interface to SparseBackwardDataFlowAnalysis and apply it in LivenessAnalysis/RemoveDeadValues (PR #169816)

lonely eagle llvmlistbot at llvm.org
Fri Nov 28 00:51:42 PST 2025


https://github.com/linuxlonelyeagle updated https://github.com/llvm/llvm-project/pull/169816

>From 1bce49424b8fa4666b0861c58be85ff5e60b5b70 Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Thu, 27 Nov 2025 13:56:51 +0000
Subject: [PATCH 1/3] add visitBranchRegionArgument interface to sparse
 backward dataflow analysis and apply it to LivenessAnalysis.

---
 .../mlir/Analysis/DataFlow/LivenessAnalysis.h |  2 ++
 .../mlir/Analysis/DataFlow/SparseAnalysis.h   |  2 ++
 .../Analysis/DataFlow/LivenessAnalysis.cpp    | 20 +++++++++++++++++++
 mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp | 14 ++++++++++++-
 .../XeGPU/Transforms/XeGPUPropagateLayout.cpp |  2 ++
 .../TestSparseBackwardDataFlowAnalysis.cpp    |  2 ++
 6 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h b/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
index cf1fd6e2d48ca..80d63ad5715ac 100644
--- a/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
+++ b/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
@@ -87,6 +87,8 @@ class LivenessAnalysis : public SparseBackwardDataFlowAnalysis<Liveness> {
   void visitCallOperand(OpOperand &operand) override;
 
   void setToExitState(Liveness *lattice) override;
+
+  void visitBranchRegionArgument(BlockArgument &argument) override;
 };
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h b/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
index 360d3c7e62000..097da72fb6bb3 100644
--- a/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
+++ b/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
@@ -431,6 +431,8 @@ class AbstractSparseBackwardDataFlowAnalysis : public DataFlowAnalysis {
   // Visit operands on branch instructions that are not forwarded.
   virtual void visitBranchOperand(OpOperand &operand) = 0;
 
+  virtual void visitBranchRegionArgument(BlockArgument &argument) = 0;
+
   // Visit operands on call instructions that are not forwarded.
   virtual void visitCallOperand(OpOperand &operand) = 0;
 
diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
index 20be50c8e8a5b..69c945e83c141 100644
--- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
@@ -303,6 +303,26 @@ void LivenessAnalysis::visitCallOperand(OpOperand &operand) {
   propagateIfChanged(operandLiveness, operandLiveness->markLive());
 }
 
+void LivenessAnalysis::visitBranchRegionArgument(BlockArgument &blockArgument) {
+  Operation *parentOp = blockArgument.getOwner()->getParentOp();
+  LDBG() << "Visiting branch region argument: " << blockArgument
+         << "in op: " << OpWithFlags(parentOp, OpPrintingFlags().skipRegions());
+  Liveness *argumentLiveness = getLatticeElement(blockArgument);
+  SmallVector<Liveness *> parentResultsLiveness;
+  for (Value result : parentOp->getResults())
+    parentResultsLiveness.push_back(getLatticeElement(result));
+
+  for (Liveness *resultLattice : parentResultsLiveness) {
+    if (resultLattice->isLive) {
+      LDBG() << "Marking branch argument live: " << blockArgument;
+      propagateIfChanged(argumentLiveness, argumentLiveness->markLive());
+      return;
+    }
+  }
+  (void)visitOperation(parentOp, ArrayRef<Liveness *>{argumentLiveness},
+                       parentResultsLiveness);
+}
+
 void LivenessAnalysis::setToExitState(Liveness *lattice) {
   LDBG() << "setToExitState for lattice: " << lattice;
   if (lattice->isLive) {
diff --git a/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp b/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp
index 8e63ae86753b4..d442135363392 100644
--- a/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp
@@ -599,7 +599,7 @@ void AbstractSparseBackwardDataFlowAnalysis::visitRegionSuccessors(
   // All operands not forwarded to any successor. This set can be non-contiguous
   // in the presence of multiple successors.
   BitVector unaccounted(op->getNumOperands(), true);
-
+  SmallVector<BlockArgument> regionArguments;
   for (RegionSuccessor &successor : successors) {
     OperandRange operands = branch.getEntrySuccessorOperands(successor);
     MutableArrayRef<OpOperand> opoperands = operandsToOpOperands(operands);
@@ -609,12 +609,24 @@ void AbstractSparseBackwardDataFlowAnalysis::visitRegionSuccessors(
            *getLatticeElementFor(getProgramPointAfter(op), input));
       unaccounted.reset(operand.getOperandNumber());
     }
+
+    if (successor.isParent())
+      continue;
+    auto arguments = successor.getSuccessor()->getArguments();
+    for (BlockArgument argument : arguments) {
+      if (llvm::find(inputs, argument) == inputs.end()) {
+        regionArguments.push_back(argument);
+      }
+    }
   }
   // All operands not forwarded to regions are typically parameters of the
   // branch operation itself (for example the boolean for if/else).
   for (int index : unaccounted.set_bits()) {
     visitBranchOperand(op->getOpOperand(index));
   }
+  for (BlockArgument argument : regionArguments) {
+    visitBranchRegionArgument(argument);
+  }
 }
 
 void AbstractSparseBackwardDataFlowAnalysis::
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
index f2b0e71c9397f..5287ec03055dd 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
@@ -405,6 +405,8 @@ class LayoutInfoPropagation
 
   void visitCallOperand(OpOperand &operand) override {};
 
+  void visitBranchRegionArgument(BlockArgument &argument) override {};
+
   void visitExternalCall(CallOpInterface call,
                          ArrayRef<LayoutInfoLattice *> operands,
                          ArrayRef<const LayoutInfoLattice *> results) override {
diff --git a/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp b/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
index 0bdb7c25c3b5f..c7c2e68e9d95d 100644
--- a/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
+++ b/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
@@ -82,6 +82,8 @@ class WrittenToAnalysis : public SparseBackwardDataFlowAnalysis<WrittenTo> {
 
   void visitCallOperand(OpOperand &operand) override;
 
+  void visitBranchRegionArgument(BlockArgument &argument) override {}
+
   void visitExternalCall(CallOpInterface call, ArrayRef<WrittenTo *> operands,
                          ArrayRef<const WrittenTo *> results) override;
 

>From 8d37523b69c7488a82e3a64130b7523711c6b7ac Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Thu, 27 Nov 2025 14:28:51 +0000
Subject: [PATCH 2/3] rebase main and add test.

---
 .../Analysis/DataFlow/LivenessAnalysis.cpp    | 32 -------------------
 mlir/test/Transforms/remove-dead-values.mlir  | 18 +++++++++++
 2 files changed, 18 insertions(+), 32 deletions(-)

diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
index 69c945e83c141..70ee411b03c99 100644
--- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
@@ -137,7 +137,6 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
   // Populating such blocks in `blocks`.
   bool mayLive = false;
   SmallVector<Block *, 4> blocks;
-  SmallVector<BlockArgument> argumentNotOperand;
   if (auto regionBranchOp = dyn_cast<RegionBranchOpInterface>(op)) {
     if (op->getNumResults() != 0) {
       // This mark value of type 1.c liveness as may live, because the region
@@ -166,25 +165,6 @@ 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.
-    for (Region &region : op->getRegions()) {
-      SmallVector<RegionSuccessor> successors;
-      regionBranchOp.getSuccessorRegions(region, 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()) {
-            argumentNotOperand.push_back(argument);
-          }
-        }
-      }
-    }
   } else if (isa<BranchOpInterface>(op)) {
     // We cannot track all successor blocks of the branch operation(More
     // specifically, it's the successor's successor). Additionally, different
@@ -244,24 +224,12 @@ 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;
-      // 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());
-    }
   }
 
   // Now that we have checked for memory-effecting ops in the blocks of concern,
   // we will simply visit the op with this non-forwarded operand to potentially
   // mark it "live" due to type (1.a/3) liveness.
   SmallVector<Liveness *, 4> operandLiveness;
-  operandLiveness.push_back(getLatticeElement(operand.get()));
-  for (BlockArgument argument : argumentNotOperand)
-    operandLiveness.push_back(getLatticeElement(argument));
   SmallVector<const Liveness *, 4> resultsLiveness;
   for (const Value result : op->getResults())
     resultsLiveness.push_back(getLatticeElement(result));
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 4bae85dcf4f7d..2597a35c898b0 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -687,3 +687,21 @@ func.func @op_block_have_dead_arg(%arg0: index, %arg1: index, %arg2: i1) {
   // CHECK-NEXT: return
   return
 }
+
+// -----
+
+
+// CHECK-LABEL: func @affine_loop_no_use_iv_has_side_effect_op
+func.func @affine_loop_no_use_iv_has_side_effect_op() {
+  %c1 = arith.constant 1 : index
+  %alloc = memref.alloc() : memref<10xindex>
+  affine.for %arg0 = 0 to 79 {
+    memref.store %c1, %alloc[%c1] : memref<10xindex>
+  }
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[ALLOC:.*]] = memref.alloc() : memref<10xindex>
+// CHECK: affine.for %[[VAL_0:.*]] = 0 to 79 {
+// CHECK:   memref.store %[[C1]], %[[ALLOC]]{{\[}}%[[C1]]] : memref<10xindex>
+// CHECK: }
+  return
+}

>From d6a1bd5ea305d20e3b675806a5ed0e8b219befc2 Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Fri, 28 Nov 2025 08:51:21 +0000
Subject: [PATCH 3/3] add test-liveness-analysis test.

---
 .../DataFlow/test-liveness-analysis.mlir      | 25 +++++++++++++++++++
 mlir/test/Transforms/remove-dead-values.mlir  |  1 -
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
index 768f1cfcb3d02..f92c3ff7c46a8 100644
--- a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
+++ b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
@@ -315,3 +315,28 @@ func.func @dead_block() {
   ^bb4:
     return
 }
+
+// -----
+
+// CHECK-LABEL: test_tag: for:
+// CHECK-NEXT: region: #0:
+// CHECK-NEXT:   argument: #0: live
+func.func @affine_loop_no_use_iv_has_side_effect_op() {
+  %c1 = arith.constant 1 : index
+  %alloc = memref.alloc() : memref<10xindex>
+  affine.for %arg0 = 0 to 79 {
+    memref.store %c1, %alloc[%c1] : memref<10xindex>
+  } {tag = "for"}
+  return
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: for:
+// CHECK-NEXT: region: #0:
+// CHECK-NEXT:   argument: #0: not live
+func.func @affine_loop_no_use_iv() {
+  affine.for %arg0 = 0 to 79 { 
+  } {tag = "for"}
+  return
+}
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 2597a35c898b0..17dece2cc0e15 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -690,7 +690,6 @@ func.func @op_block_have_dead_arg(%arg0: index, %arg1: index, %arg2: i1) {
 
 // -----
 
-
 // CHECK-LABEL: func @affine_loop_no_use_iv_has_side_effect_op
 func.func @affine_loop_no_use_iv_has_side_effect_op() {
   %c1 = arith.constant 1 : index



More information about the Mlir-commits mailing list