[flang-commits] [flang] [flang][fir] Convert `fir.do_loop` with the unordered attribute to `scf.parallel`. (PR #168510)
Ming Yan via flang-commits
flang-commits at lists.llvm.org
Tue Nov 18 02:35:51 PST 2025
https://github.com/NexMing created https://github.com/llvm/llvm-project/pull/168510
None
>From 316714ce0ea992d738371bedafa1bee6c6aae9ba Mon Sep 17 00:00:00 2001
From: yanming <ming.yan at terapines.com>
Date: Tue, 18 Nov 2025 18:15:16 +0800
Subject: [PATCH 1/2] [flang][fir] Convert `fir.do_loop` with the unordered
attribute to `scf.parallel`.
---
flang/lib/Optimizer/Transforms/FIRToSCF.cpp | 41 +++++++++++++--------
flang/test/Fir/FirToSCF/do-loop.fir | 32 ++++++++++++++++
2 files changed, 58 insertions(+), 15 deletions(-)
diff --git a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
index 70d6ebbcb039c..291147886a75e 100644
--- a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
+++ b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
@@ -30,6 +30,7 @@ struct DoLoopConversion : public mlir::OpRewritePattern<fir::DoLoopOp> {
mlir::PatternRewriter &rewriter) const override {
mlir::Location loc = doLoopOp.getLoc();
bool hasFinalValue = doLoopOp.getFinalValue().has_value();
+ bool isUnordered = doLoopOp.getUnordered().has_value();
// Get loop values from the DoLoopOp
mlir::Value low = doLoopOp.getLowerBound();
@@ -53,37 +54,47 @@ struct DoLoopConversion : public mlir::OpRewritePattern<fir::DoLoopOp> {
mlir::arith::DivSIOp::create(rewriter, loc, distance, step);
auto zero = mlir::arith::ConstantIndexOp::create(rewriter, loc, 0);
auto one = mlir::arith::ConstantIndexOp::create(rewriter, loc, 1);
- auto scfForOp =
- mlir::scf::ForOp::create(rewriter, loc, zero, tripCount, one, iterArgs);
+ // Create the scf.for or scf.parallel operation
+ mlir::Operation *scfLoopOp = nullptr;
+ if (isUnordered) {
+ scfLoopOp = mlir::scf::ParallelOp::create(rewriter, loc, {zero},
+ {tripCount}, {one}, iterArgs);
+ } else {
+ scfLoopOp = mlir::scf::ForOp::create(rewriter, loc, zero, tripCount, one,
+ iterArgs);
+ }
+
+ // Move the body of the fir.do_loop to the scf.for or scf.parallel
auto &loopOps = doLoopOp.getBody()->getOperations();
auto resultOp =
mlir::cast<fir::ResultOp>(doLoopOp.getBody()->getTerminator());
auto results = resultOp.getOperands();
- mlir::Block *loweredBody = scfForOp.getBody();
+ auto scfLoopLikeOp = mlir::cast<mlir::LoopLikeOpInterface>(scfLoopOp);
+ mlir::Block &scfLoopBody = scfLoopLikeOp.getLoopRegions().front()->front();
- loweredBody->getOperations().splice(loweredBody->begin(), loopOps,
- loopOps.begin(),
- std::prev(loopOps.end()));
+ scfLoopBody.getOperations().splice(scfLoopBody.begin(), loopOps,
+ loopOps.begin(),
+ std::prev(loopOps.end()));
- rewriter.setInsertionPointToStart(loweredBody);
+ rewriter.setInsertionPointToStart(&scfLoopBody);
mlir::Value iv = mlir::arith::MulIOp::create(
- rewriter, loc, scfForOp.getInductionVar(), step);
+ rewriter, loc, scfLoopLikeOp.getSingleInductionVar().value(), step);
iv = mlir::arith::AddIOp::create(rewriter, loc, low, iv);
if (!results.empty()) {
- rewriter.setInsertionPointToEnd(loweredBody);
+ rewriter.setInsertionPointToEnd(&scfLoopBody);
mlir::scf::YieldOp::create(rewriter, resultOp->getLoc(), results);
}
doLoopOp.getInductionVar().replaceAllUsesWith(iv);
- rewriter.replaceAllUsesWith(doLoopOp.getRegionIterArgs(),
- hasFinalValue
- ? scfForOp.getRegionIterArgs().drop_front()
- : scfForOp.getRegionIterArgs());
+ rewriter.replaceAllUsesWith(
+ doLoopOp.getRegionIterArgs(),
+ hasFinalValue ? scfLoopLikeOp.getRegionIterArgs().drop_front()
+ : scfLoopLikeOp.getRegionIterArgs());
// Copy all the attributes from the old to new op.
- scfForOp->setAttrs(doLoopOp->getAttrs());
- rewriter.replaceOp(doLoopOp, scfForOp);
+ scfLoopOp->setAttrs(doLoopOp->getAttrs());
+ rewriter.replaceOp(doLoopOp, scfLoopOp);
return mlir::success();
}
};
diff --git a/flang/test/Fir/FirToSCF/do-loop.fir b/flang/test/Fir/FirToSCF/do-loop.fir
index 812497c8d0c74..bb245bf06ac3e 100644
--- a/flang/test/Fir/FirToSCF/do-loop.fir
+++ b/flang/test/Fir/FirToSCF/do-loop.fir
@@ -146,6 +146,38 @@ func.func @loop_with_final_value(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !f
return
}
+// CHECK-LABEL: func.func @loop_with_unordered_attr(
+// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>) {
+// CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
+// CHECK: %[[CONSTANT_1:.*]] = arith.constant 100 : index
+// CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_1]] : (index) -> !fir.shape<1>
+// CHECK: %[[CONSTANT_2:.*]] = arith.constant 1 : i32
+// CHECK: %[[SUBI_0:.*]] = arith.subi %[[CONSTANT_1]], %[[CONSTANT_0]] : index
+// CHECK: %[[ADDI_0:.*]] = arith.addi %[[SUBI_0]], %[[CONSTANT_0]] : index
+// CHECK: %[[DIVSI_0:.*]] = arith.divsi %[[ADDI_0]], %[[CONSTANT_0]] : index
+// CHECK: %[[CONSTANT_3:.*]] = arith.constant 0 : index
+// CHECK: %[[CONSTANT_4:.*]] = arith.constant 1 : index
+// CHECK: scf.parallel (%[[VAL_0:.*]]) = (%[[CONSTANT_3]]) to (%[[DIVSI_0]]) step (%[[CONSTANT_4]]) {
+// CHECK: %[[MULI_0:.*]] = arith.muli %[[VAL_0]], %[[CONSTANT_0]] : index
+// CHECK: %[[ADDI_1:.*]] = arith.addi %[[CONSTANT_0]], %[[MULI_0]] : index
+// CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[ARG0]](%[[SHAPE_0]]) %[[ADDI_1]] : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
+// CHECK: fir.store %[[CONSTANT_2]] to %[[ARRAY_COOR_0]] : !fir.ref<i32>
+// CHECK: scf.reduce
+// CHECK: } {unordered}
+// CHECK: return
+// CHECK: }
+func.func @loop_with_unordered_attr(%arg0: !fir.ref<!fir.array<100xi32>>) {
+ %c1 = arith.constant 1 : index
+ %c100 = arith.constant 100 : index
+ %0 = fir.shape %c100 : (index) -> !fir.shape<1>
+ %c1_i32 = arith.constant 1 : i32
+ fir.do_loop %arg1 = %c1 to %c100 step %c1 unordered {
+ %1 = fir.array_coor %arg0(%0) %arg1 : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
+ fir.store %c1_i32 to %1 : !fir.ref<i32>
+ }
+ return
+}
+
// CHECK-LABEL: func.func @loop_with_attribute(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>,
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>) {
>From 45a330f3fdebd42310e7b5cde31f63bcae14c20d Mon Sep 17 00:00:00 2001
From: yanming <ming.yan at terapines.com>
Date: Tue, 18 Nov 2025 18:31:57 +0800
Subject: [PATCH 2/2] Only keep attributes that are valid for scf loop op.
---
flang/lib/Optimizer/Transforms/FIRToSCF.cpp | 6 +++--
flang/test/Fir/FirToSCF/do-loop.fir | 25 +++++++++++++++++----
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
index 291147886a75e..662bdbf28a6dc 100644
--- a/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
+++ b/flang/lib/Optimizer/Transforms/FIRToSCF.cpp
@@ -92,8 +92,10 @@ struct DoLoopConversion : public mlir::OpRewritePattern<fir::DoLoopOp> {
hasFinalValue ? scfLoopLikeOp.getRegionIterArgs().drop_front()
: scfLoopLikeOp.getRegionIterArgs());
- // Copy all the attributes from the old to new op.
- scfLoopOp->setAttrs(doLoopOp->getAttrs());
+ // Copy loop annotations from the fir.do_loop to scf loop op.
+ if (auto ann = doLoopOp.getLoopAnnotation())
+ scfLoopOp->setAttr("loop_annotation", *ann);
+
rewriter.replaceOp(doLoopOp, scfLoopOp);
return mlir::success();
}
diff --git a/flang/test/Fir/FirToSCF/do-loop.fir b/flang/test/Fir/FirToSCF/do-loop.fir
index bb245bf06ac3e..aa8526febeefc 100644
--- a/flang/test/Fir/FirToSCF/do-loop.fir
+++ b/flang/test/Fir/FirToSCF/do-loop.fir
@@ -1,4 +1,4 @@
-// RUN: fir-opt %s --fir-to-scf | FileCheck %s
+// RUN: fir-opt %s --fir-to-scf --split-input-file | FileCheck %s
// CHECK-LABEL: func.func @simple_loop(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>) {
@@ -31,6 +31,8 @@ func.func @simple_loop(%arg0: !fir.ref<!fir.array<100xi32>>) {
return
}
+// -----
+
// CHECK-LABEL: func.func @loop_with_negtive_step(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>) {
// CHECK: %[[VAL_0:.*]] = arith.constant 100 : index
@@ -64,6 +66,8 @@ func.func @loop_with_negtive_step(%arg0: !fir.ref<!fir.array<100xi32>>) {
return
}
+// -----
+
// CHECK-LABEL: func.func @loop_with_results(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>,
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>) {
@@ -102,6 +106,8 @@ func.func @loop_with_results(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !fir.r
return
}
+// -----
+
// CHECK-LABEL: func.func @loop_with_final_value(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>,
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>) {
@@ -146,6 +152,8 @@ func.func @loop_with_final_value(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !f
return
}
+// -----
+
// CHECK-LABEL: func.func @loop_with_unordered_attr(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>) {
// CHECK: %[[CONSTANT_0:.*]] = arith.constant 1 : index
@@ -163,7 +171,7 @@ func.func @loop_with_final_value(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !f
// CHECK: %[[ARRAY_COOR_0:.*]] = fir.array_coor %[[ARG0]](%[[SHAPE_0]]) %[[ADDI_1]] : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
// CHECK: fir.store %[[CONSTANT_2]] to %[[ARRAY_COOR_0]] : !fir.ref<i32>
// CHECK: scf.reduce
-// CHECK: } {unordered}
+// CHECK: }
// CHECK: return
// CHECK: }
func.func @loop_with_unordered_attr(%arg0: !fir.ref<!fir.array<100xi32>>) {
@@ -178,6 +186,10 @@ func.func @loop_with_unordered_attr(%arg0: !fir.ref<!fir.array<100xi32>>) {
return
}
+// -----
+
+// CHECK: #[[$ATTR_0:.+]] = #llvm.loop_vectorize<disable = false>
+// CHECK: #[[$ATTR_1:.+]] = #llvm.loop_annotation<vectorize = #[[$ATTR_0]]>
// CHECK-LABEL: func.func @loop_with_attribute(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xi32>>,
// CHECK-SAME: %[[ARG1:.*]]: !fir.ref<i32>) {
@@ -199,16 +211,19 @@ func.func @loop_with_unordered_attr(%arg0: !fir.ref<!fir.array<100xi32>>) {
// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
// CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_15]], %[[VAL_14]] : i32
// CHECK: fir.store %[[VAL_16]] to %[[VAL_3]] : !fir.ref<i32>
-// CHECK: } {operandSegmentSizes = array<i32: 1, 1, 1, 1, 0>, reduceAttrs = [#fir.reduce_attr<add>]}
+// CHECK: } {loop_annotation = #[[$ATTR_1]]}
// CHECK: return
// CHECK: }
+
+#loop_vectorize = #llvm.loop_vectorize<disable = false>
+#loop_annotation = #llvm.loop_annotation<vectorize = #loop_vectorize>
func.func @loop_with_attribute(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !fir.ref<i32>) {
%c1 = arith.constant 1 : index
%c0_i32 = arith.constant 0 : i32
%c100 = arith.constant 100 : index
%0 = fir.alloca i32
%1 = fir.shape %c100 : (index) -> !fir.shape<1>
- fir.do_loop %arg2 = %c1 to %c100 step %c1 reduce(#fir.reduce_attr<add> -> %0 : !fir.ref<i32>) {
+ fir.do_loop %arg2 = %c1 to %c100 step %c1 attributes {loopAnnotation = #loop_annotation} {
%2 = fir.array_coor %arg0(%1) %arg2 : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
%3 = fir.load %2 : !fir.ref<i32>
%4 = fir.load %0 : !fir.ref<i32>
@@ -219,6 +234,8 @@ func.func @loop_with_attribute(%arg0: !fir.ref<!fir.array<100xi32>>, %arg1: !fir
return
}
+// -----
+
// CHECK-LABEL: func.func @nested_loop(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100x100xi32>>) {
// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index
More information about the flang-commits
mailing list