[Mlir-commits] [mlir] [mlir][dataflow] Add new visitNonControlFlowArgumentst API to SparseDataFlowAnalysis and apply it in LivenessAnalysis/RemoveDeadValues/IntegerRangeAnalysis (PR #169816)
lonely eagle
llvmlistbot at llvm.org
Thu Jan 1 09:36:32 PST 2026
https://github.com/linuxlonelyeagle updated https://github.com/llvm/llvm-project/pull/169816
>From 1cf22bfef3b24cd1a9414398f6f217321eb4c35c Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Thu, 27 Nov 2025 13:56:51 +0000
Subject: [PATCH] add visitNonControlFlowArguments API to
AbstractSparseBackwardDataFlowAnalysis and use it in the LivenessAnalysis.
---
.../mlir/Analysis/DataFlow/LivenessAnalysis.h | 3 +
.../mlir/Analysis/DataFlow/SparseAnalysis.h | 6 ++
.../Analysis/DataFlow/LivenessAnalysis.cpp | 55 ++++++++-----------
mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp | 22 +++++++-
.../XeGPU/Transforms/XeGPUPropagateLayout.cpp | 4 ++
.../DataFlow/test-liveness-analysis.mlir | 42 ++++++++++++++
mlir/test/Transforms/remove-dead-values.mlir | 17 ++++++
.../TestSparseBackwardDataFlowAnalysis.cpp | 4 ++
8 files changed, 121 insertions(+), 32 deletions(-)
diff --git a/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h b/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
index cf1fd6e2d48ca..90947d06e7999 100644
--- a/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
+++ b/mlir/include/mlir/Analysis/DataFlow/LivenessAnalysis.h
@@ -87,6 +87,9 @@ class LivenessAnalysis : public SparseBackwardDataFlowAnalysis<Liveness> {
void visitCallOperand(OpOperand &operand) override;
void setToExitState(Liveness *lattice) override;
+
+ void visitNonControlFlowArguments(RegionSuccessor &successor,
+ ArrayRef<BlockArgument> arguments) override;
};
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h b/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
index 360d3c7e62000..1bb42a246b701 100644
--- a/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
+++ b/mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h
@@ -431,6 +431,12 @@ class AbstractSparseBackwardDataFlowAnalysis : public DataFlowAnalysis {
// Visit operands on branch instructions that are not forwarded.
virtual void visitBranchOperand(OpOperand &operand) = 0;
+ // Visit the non-forwarded arguments of a region, such as the
+ // induction variables of a loop.
+ virtual void
+ visitNonControlFlowArguments(RegionSuccessor &successor,
+ ArrayRef<BlockArgument> arguments) = 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..ec7fec86f0c51 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 ®ion : 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,15 +224,6 @@ 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,
@@ -260,8 +231,6 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
// 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));
@@ -303,6 +272,30 @@ void LivenessAnalysis::visitCallOperand(OpOperand &operand) {
propagateIfChanged(operandLiveness, operandLiveness->markLive());
}
+void LivenessAnalysis::visitNonControlFlowArguments(
+ RegionSuccessor &successor, ArrayRef<BlockArgument> arguments) {
+ Operation *parentOp = successor.getSuccessor()->getParentOp();
+ LDBG() << "visitNonControlFlowArguments visit the region # "
+ << successor.getSuccessor()->getRegionNumber() << "of "
+ << OpWithFlags(parentOp, OpPrintingFlags().skipRegions());
+ auto valuesToLattices = [&](Value value) { return getLatticeElement(value); };
+ SmallVector<Liveness *> argumentLattices =
+ llvm::map_to_vector(arguments, valuesToLattices);
+ SmallVector<Liveness *> parentResultLattices =
+ llvm::map_to_vector(parentOp->getResults(), valuesToLattices);
+
+ for (Liveness *resultLattice : parentResultLattices) {
+ if (resultLattice->isLive) {
+ for (Liveness *argumentLattice : argumentLattices) {
+ LDBG() << "make lattice: " << argumentLattice << " live";
+ propagateIfChanged(argumentLattice, argumentLattice->markLive());
+ }
+ return;
+ }
+ }
+ (void)visitOperation(parentOp, argumentLattices, parentResultLattices);
+}
+
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 64adb8cf00ba7..b9d861830dd38 100644
--- a/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp
@@ -594,7 +594,6 @@ void AbstractSparseBackwardDataFlowAnalysis::visitRegionSuccessors(
// Not all operands are forwarded to a successor. This set can be
// non-contiguous in the presence of multiple successors.
BitVector unaccounted(branch->getNumOperands(), true);
-
RegionBranchSuccessorMapping mapping;
branch.getSuccessorOperandInputMapping(mapping, RegionBranchPoint::parent());
for (const auto &[operand, inputs] : mapping) {
@@ -605,6 +604,27 @@ void AbstractSparseBackwardDataFlowAnalysis::visitRegionSuccessors(
}
}
+ Operation *op = branch.getOperation();
+ SmallVector<RegionSuccessor> successors;
+ SmallVector<Attribute> operands(op->getNumOperands(), nullptr);
+ branch.getEntrySuccessorRegions(operands, successors);
+ for (RegionSuccessor &successor : successors) {
+ if (successor.isParent())
+ continue;
+ SmallVector<BlockArgument> noControlFlowArguments;
+ MutableArrayRef<BlockArgument> arguments =
+ successor.getSuccessor()->getArguments();
+ ValueRange inputs = successor.getSuccessorInputs();
+ for (BlockArgument argument : arguments) {
+ // Visit blockArgument of RegionBranchOp which isn't "control
+ // flow block arguments". For example, the IV of a loop.
+ if (!llvm::is_contained(inputs, argument)) {
+ noControlFlowArguments.push_back(argument);
+ }
+ }
+ visitNonControlFlowArguments(successor, noControlFlowArguments);
+ }
+
// 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()) {
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
index 60fb13c7c2cd7..3ac23f348f8a9 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
@@ -449,6 +449,10 @@ class LayoutInfoPropagation
void visitCallOperand(OpOperand &operand) override {};
+ void
+ visitNonControlFlowArguments(RegionSuccessor &successor,
+ ArrayRef<BlockArgument> arguments) override {};
+
void visitExternalCall(CallOpInterface call,
ArrayRef<LayoutInfoLattice *> operands,
ArrayRef<const LayoutInfoLattice *> results) override {
diff --git a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
index 768f1cfcb3d02..171a35fdeafb9 100644
--- a/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
+++ b/mlir/test/Analysis/DataFlow/test-liveness-analysis.mlir
@@ -315,3 +315,45 @@ 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
+}
+
+// -----
+
+// CHECK-LABEL: test_tag: forall:
+// CHECK-NEXT: operand #0: live
+// CHECK-NEXT: region: #0:
+// CHECK-NEXT: argument: #0: live
+
+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>
+ scf.forall (%e2) in (%idx2) {
+ %a = memref.load %r[%idx2] : memref<10xf32>
+ } {tag = "forall"}
+ }
+ return
+}
diff --git a/mlir/test/Transforms/remove-dead-values.mlir b/mlir/test/Transforms/remove-dead-values.mlir
index 71306676d48e9..bd730915c6dcd 100644
--- a/mlir/test/Transforms/remove-dead-values.mlir
+++ b/mlir/test/Transforms/remove-dead-values.mlir
@@ -714,3 +714,20 @@ func.func private @remove_dead_branch_op(%c: i1, %arg0: i64, %arg1: i64) -> (i64
^bb2:
return %arg1 : i64
}
+
+// -----
+
+// 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
+}
diff --git a/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp b/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
index 0bdb7c25c3b5f..86d4b972de953 100644
--- a/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
+++ b/mlir/test/lib/Analysis/DataFlow/TestSparseBackwardDataFlowAnalysis.cpp
@@ -82,6 +82,10 @@ class WrittenToAnalysis : public SparseBackwardDataFlowAnalysis<WrittenTo> {
void visitCallOperand(OpOperand &operand) override;
+ void
+ visitNonControlFlowArguments(RegionSuccessor &successor,
+ ArrayRef<BlockArgument> arguments) override {}
+
void visitExternalCall(CallOpInterface call, ArrayRef<WrittenTo *> operands,
ArrayRef<const WrittenTo *> results) override;
More information about the Mlir-commits
mailing list