[flang-commits] [flang] 5cfd02f - [flang] change yielded iv value to be `iv + step` (#174124)
via flang-commits
flang-commits at lists.llvm.org
Mon Jan 5 04:31:15 PST 2026
Author: Susan Tan (ス-ザン タン)
Date: 2026-01-05T07:31:11-05:00
New Revision: 5cfd02f44a43a2e2a085a633b022a62f64ba2b93
URL: https://github.com/llvm/llvm-project/commit/5cfd02f44a43a2e2a085a633b022a62f64ba2b93
DIFF: https://github.com/llvm/llvm-project/commit/5cfd02f44a43a2e2a085a633b022a62f64ba2b93.diff
LOG: [flang] change yielded iv value to be `iv + step` (#174124)
In cases where induction variables are used after the loop, like
```
write(*,*) (a(j),j=1,10)
print *, j
```
the incremented value should be used. Updating the FIRToSCF pass to
support this.
Added:
Modified:
flang/lib/Optimizer/Transforms/FIRToSCF.cpp
flang/test/Fir/FirToSCF/do-loop.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
index d38bedcf10e87..04ba0537a6434 100644
--- a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
+++ b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
@@ -89,12 +89,36 @@ struct DoLoopConversion : public mlir::OpRewritePattern<fir::DoLoopOp> {
mlir::Value iv = mlir::arith::MulIOp::create(
rewriter, loc, scfLoopLikeOp.getSingleInductionVar().value(), step);
iv = mlir::arith::AddIOp::create(rewriter, loc, low, iv);
+ mlir::Value firIV = doLoopOp.getInductionVar();
+ firIV.replaceAllUsesWith(iv);
+
+ mlir::Value finalValue;
+ if (hasFinalValue) {
+ // Prefer re-using an existing `arith.addi` in the moved loop body if it
+ // already computes the next `iv + step`.
+ if (!results.empty()) {
+ if (auto addOp = results.front().getDefiningOp<mlir::arith::AddIOp>()) {
+ mlir::Value lhs = addOp.getLhs();
+ mlir::Value rhs = addOp.getRhs();
+ if ((lhs == iv && rhs == step) || (lhs == step && rhs == iv))
+ finalValue = results.front();
+ }
+ }
+ if (!finalValue)
+ finalValue = mlir::arith::AddIOp::create(rewriter, loc, iv, step);
+ }
- if (!results.empty()) {
+ if (hasFinalValue || !results.empty()) {
rewriter.setInsertionPointToEnd(&scfLoopBody);
- mlir::scf::YieldOp::create(rewriter, resultOp->getLoc(), results);
+ llvm::SmallVector<mlir::Value> yieldOperands;
+ if (hasFinalValue) {
+ yieldOperands.push_back(finalValue);
+ llvm::append_range(yieldOperands, results.drop_front());
+ } else {
+ llvm::append_range(yieldOperands, results);
+ }
+ mlir::scf::YieldOp::create(rewriter, resultOp->getLoc(), yieldOperands);
}
- doLoopOp.getInductionVar().replaceAllUsesWith(iv);
rewriter.replaceAllUsesWith(
doLoopOp.getRegionIterArgs(),
hasFinalValue ? scfLoopLikeOp.getRegionIterArgs().drop_front()
diff --git a/flang/test/Fir/FirToSCF/do-loop.fir b/flang/test/Fir/FirToSCF/do-loop.fir
index 8862a4c2969e8..b61d4230b57fd 100644
--- a/flang/test/Fir/FirToSCF/do-loop.fir
+++ b/flang/test/Fir/FirToSCF/do-loop.fir
@@ -155,6 +155,56 @@ func.func @loop_with_final_value(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !f
// -----
+// CHECK-LABEL: func.func @loop_with_final_value_yielding_iv() {
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK: %[[TRIP:.*]] = arith.divsi
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[ONE:.*]] = arith.constant 1 : index
+// CHECK: %[[FOR:.*]] = scf.for %{{.*}} = %[[C0]] to %[[TRIP]] step %[[ONE]] iter_args(%{{.*}} = %[[C1]]) -> (index) {
+// CHECK: %[[NEXT:.*]] = arith.addi %{{.*}}, %[[C1]]
+// CHECK: scf.yield %[[NEXT]] : index
+// CHECK: }
+// CHECK: return
+// CHECK: }
+func.func @loop_with_final_value_yielding_iv() {
+ %c1 = arith.constant 1 : index
+ %c10 = arith.constant 10 : index
+ %0:1 = fir.do_loop %i = %c1 to %c10 step %c1 -> index {
+ fir.result %i : index
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func.func @loop_with_final_value_and_result() {
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[C0I32:.*]] = arith.constant 0 : i32
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK: %[[TRIP:.*]] = arith.divsi
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[ONE:.*]] = arith.constant 1 : index
+// CHECK: %[[LOOP:.*]]:2 = scf.for %{{.*}} = %[[C0]] to %[[TRIP]] step %[[ONE]] iter_args(%[[IVIN:.*]] = %[[C1]], %[[ACCIN:.*]] = %[[C0I32]]) -> (index, i32) {
+// CHECK: %[[IVNEXT:.*]] = arith.addi %{{.*}}, %[[C1]] : index
+// CHECK: %[[ACCOUT:.*]] = arith.addi %[[ACCIN]], %[[ACCIN]] : i32
+// CHECK: scf.yield %[[IVNEXT]], %[[ACCOUT]] : index, i32
+// CHECK: }
+// CHECK: return
+// CHECK: }
+func.func @loop_with_final_value_and_result() {
+ %c1 = arith.constant 1 : index
+ %c0_i32 = arith.constant 0 : i32
+ %c10 = arith.constant 10 : index
+ %0:2 = fir.do_loop %i = %c1 to %c10 step %c1 iter_args(%acc = %c0_i32) -> (index, i32) {
+ %acc2 = arith.addi %acc, %acc : i32
+ fir.result %i, %acc2 : index, i32
+ }
+ return
+}
+
+// -----
+
// CHECK-LABEL: func.func @loop_with_unordered_attr(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>) {
// CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
More information about the flang-commits
mailing list