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 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()) { + 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(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 }