[flang-commits] [flang] [flang] Option to drop iter_arg for do-concurrent nested loops (PR #207816)
via flang-commits
flang-commits at lists.llvm.org
Tue Jul 7 13:46:48 PDT 2026
https://github.com/khaki3 updated https://github.com/llvm/llvm-project/pull/207816
>From 00e51f198a85d024e3675129025cda7e028d550b Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 29 Jun 2026 14:15:31 -0700
Subject: [PATCH 1/9] [flang] Option to drop iter_arg for do-concurrent nested
loops
Add the DoConcurrentCleanNestedLoops lowering option. When set, plain DO
loops nested inside a DO CONCURRENT body are lowered without the
secondary-induction iter_arg: the DO variable is recomputed from the
induction variable. This keeps the loop body free of a loop-carried value
that hides memory recurrences (e.g. reductions) from later analyses,
matching how loops in OpenACC regions are lowered.
The post-loop final value of the DO variable is not preserved, so the
option is only valid where those loop variables are effectively private
(the parallel do-concurrent path). Off by default.
---
flang/include/flang/Lower/LoweringOptions.def | 9 +++++
flang/lib/Lower/Bridge.cpp | 40 +++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index e89ad75704609..203aba9969ddb 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -89,5 +89,14 @@ ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0)
/// Portable, Extremum, ExtremeNum). Default: Legacy.
ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0)
+/// If true, lower plain DO loops nested inside a DO CONCURRENT body without the
+/// secondary-induction iter_arg: the DO variable is recomputed from the
+/// induction variable. This keeps the loop body free of a loop-carried value
+/// that would otherwise hide memory recurrences (e.g. reductions) from later
+/// analyses. The post-loop final value of the DO variable is not preserved, so
+/// this is only valid where those loop variables are effectively private (the
+/// parallel do-concurrent path). Off by default.
+ENUM_LOWERINGOPT(DoConcurrentCleanNestedLoops, unsigned, 1, 0)
+
#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 27fa06362a1a8..4344105105ef2 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2903,6 +2903,18 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
+ /// Return true if the builder's current insertion point is within a
+ /// `fir.do_concurrent.loop` region (i.e. a plain DO loop being lowered here
+ /// is nested inside a DO CONCURRENT body).
+ bool isInsideDoConcurrentLoop() {
+ mlir::Block *block = builder->getInsertionBlock();
+ if (!block)
+ return false;
+ mlir::Operation *parentOp = block->getParentOp();
+ return parentOp && (mlir::isa<fir::DoConcurrentLoopOp>(parentOp) ||
+ parentOp->getParentOfType<fir::DoConcurrentLoopOp>());
+ }
+
/// Generate FIR to begin a structured or unstructured increment loop nest.
void genFIRIncrementLoopBegin(
IncrementLoopNestInfo &incrementLoopNestInfo,
@@ -2957,6 +2969,27 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// The loop variable is a doLoop op argument.
mlir::Type loopVarType = info.getLoopVariableType();
+
+ // Plain DO loops nested in a DO CONCURRENT body can be lowered without
+ // the secondary-induction iter_arg: recompute the DO variable from the
+ // induction variable. This keeps the body free of a loop-carried value
+ // that would hide memory recurrences (e.g. reductions) from later
+ // analyses, matching how loops in OpenACC regions are lowered.
+ if (getLoweringOptions().getDoConcurrentCleanNestedLoops() &&
+ isInsideDoConcurrentLoop()) {
+ auto loopOp = fir::DoLoopOp::create(
+ *builder, loc, lowerValue, upperValue, stepValue,
+ /*unordered=*/false, /*finalCountValue=*/false,
+ /*iterArgs=*/mlir::ValueRange{});
+ info.loopOp = loopOp;
+ builder->setInsertionPointToStart(loopOp.getBody());
+ mlir::Value loopValue = builder->createConvert(
+ loc, loopVarType, loopOp.getInductionVar());
+ fir::StoreOp::create(*builder, loc, loopValue, info.loopVariable);
+ addLoopAnnotationAttr(info, dirs);
+ continue;
+ }
+
auto loopOp = fir::DoLoopOp::create(
*builder, loc, lowerValue, upperValue, stepValue,
/*unordered=*/false,
@@ -3111,6 +3144,13 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// End fir.do_loop.
// Decrement tripVariable.
auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp);
+ // A clean iter_arg-free loop (DoConcurrentCleanNestedLoops) has no
+ // loop-carried DO variable to step or write back; its terminator is
+ // already in place.
+ if (doLoopOp.getNumRegionIterArgs() == 0) {
+ builder->setInsertionPointAfter(doLoopOp);
+ continue;
+ }
builder->setInsertionPointToEnd(doLoopOp.getBody());
// Step loopVariable to help optimizations such as vectorization.
// Induction variable elimination will clean up as necessary.
>From bceeb714cf89a832f6579fd182b20d4e09c4ca89 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 29 Jun 2026 14:43:08 -0700
Subject: [PATCH 2/9] [flang][bbc] Add -fdo-concurrent-clean-nested-loops flag
and test
Expose the DoConcurrentCleanNestedLoops lowering option in bbc and add a
Lower test verifying that a plain DO loop nested in a DO CONCURRENT body
is emitted without the secondary-induction iter_arg when the option is set.
---
.../do_concurrent_clean_nested_loops.f90 | 31 +++++++++++++++++++
flang/tools/bbc/bbc.cpp | 8 +++++
2 files changed, 39 insertions(+)
create mode 100644 flang/test/Lower/do_concurrent_clean_nested_loops.f90
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
new file mode 100644
index 0000000000000..04f53362b6b41
--- /dev/null
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -0,0 +1,31 @@
+! Test that -fdo-concurrent-clean-nested-loops lowers a plain DO loop nested in
+! a DO CONCURRENT body without the secondary-induction iter_arg: the DO variable
+! is recomputed from the induction variable instead.
+
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s --check-prefixes=CHECK,DEFAULT
+! RUN: bbc -emit-hlfir -fdo-concurrent-clean-nested-loops -o - %s | FileCheck %s --check-prefixes=CHECK,CLEAN
+
+subroutine nested(a, n)
+ implicit none
+ integer :: n, i, j
+ integer :: a(n, n)
+ do concurrent (j=1:n)
+ do i = 1, n
+ a(i, j) = i
+ end do
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPnested
+! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnestedEi"}
+! CHECK: fir.do_concurrent
+! CHECK: fir.do_concurrent.loop (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
+
+! The nested plain DO loop:
+! DEFAULT: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[IV:.*]] = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
+
+! CLEAN: fir.do_loop %[[IV:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CLEAN-NOT: iter_args
+! CLEAN: %[[IV_CVT:.*]] = fir.convert %[[IV]] : (index) -> i32
+! CLEAN: fir.store %[[IV_CVT]] to %[[I_DECL]]#0 : !fir.ref<i32>
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 23e7af238198f..4fcddb9154397 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -226,6 +226,13 @@ static llvm::cl::opt<bool> enableCUDA("fcuda",
llvm::cl::desc("enable CUDA Fortran"),
llvm::cl::init(false));
+static llvm::cl::opt<bool> doConcurrentCleanNestedLoops(
+ "fdo-concurrent-clean-nested-loops",
+ llvm::cl::desc(
+ "lower plain DO loops nested in DO CONCURRENT bodies without "
+ "the secondary-induction iter_arg"),
+ llvm::cl::init(false));
+
static llvm::cl::opt<bool>
enableDoConcurrentOffload("fdoconcurrent-offload",
llvm::cl::desc("enable do concurrent offload"),
@@ -477,6 +484,7 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
loweringOptions.setRepackArrays(repackArrays);
loweringOptions.setRepackArraysWhole(repackArraysWhole);
loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition);
+ loweringOptions.setDoConcurrentCleanNestedLoops(doConcurrentCleanNestedLoops);
if (enableCUDA)
loweringOptions.setCUDARuntimeCheck(true);
if (complexRange == "improved" || complexRange == "basic")
>From 08b6070179029a4ec923e012428ecb3340913c84 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 30 Jun 2026 13:37:46 -0700
Subject: [PATCH 3/9] [flang] Preserve DO variable post-loop value for clean
nested loops
Materialize the Fortran post-loop value (lb + tripCount*step) after the
iter_arg-free nested loop so uses of the DO variable after the loop stay
correct. The value is computed outside the loop body, so it does not
reintroduce a loop-carried recurrence. Makes the lowering option fully
semantics-preserving; updates the test to cover the post-loop use.
---
flang/include/flang/Lower/LoweringOptions.def | 10 ++--
flang/lib/Lower/Bridge.cpp | 35 ++++++++++----
.../do_concurrent_clean_nested_loops.f90 | 47 ++++++++++++-------
3 files changed, 61 insertions(+), 31 deletions(-)
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 203aba9969ddb..7fa295d74c75c 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -91,11 +91,11 @@ ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0)
/// If true, lower plain DO loops nested inside a DO CONCURRENT body without the
/// secondary-induction iter_arg: the DO variable is recomputed from the
-/// induction variable. This keeps the loop body free of a loop-carried value
-/// that would otherwise hide memory recurrences (e.g. reductions) from later
-/// analyses. The post-loop final value of the DO variable is not preserved, so
-/// this is only valid where those loop variables are effectively private (the
-/// parallel do-concurrent path). Off by default.
+/// induction variable in the body. This keeps the loop body free of a
+/// loop-carried value that would otherwise hide memory recurrences (e.g.
+/// reductions) from later analyses. The Fortran post-loop value of the DO
+/// variable is still materialized after the loop, so the lowering is
+/// semantics-preserving. Off by default.
ENUM_LOWERINGOPT(DoConcurrentCleanNestedLoops, unsigned, 1, 0)
#undef LOWERINGOPT
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 4344105105ef2..dad978cc3f3aa 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2970,11 +2970,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// The loop variable is a doLoop op argument.
mlir::Type loopVarType = info.getLoopVariableType();
- // Plain DO loops nested in a DO CONCURRENT body can be lowered without
- // the secondary-induction iter_arg: recompute the DO variable from the
- // induction variable. This keeps the body free of a loop-carried value
- // that would hide memory recurrences (e.g. reductions) from later
- // analyses, matching how loops in OpenACC regions are lowered.
+ // Lower the loop without the secondary-induction iter_arg so memory
+ // recurrences (e.g. reductions) stay visible to later analyses. The DO
+ // variable is recomputed from the induction variable in the body; its
+ // post-loop value is materialized in genFIRIncrementLoopEnd.
if (getLoweringOptions().getDoConcurrentCleanNestedLoops() &&
isInsideDoConcurrentLoop()) {
auto loopOp = fir::DoLoopOp::create(
@@ -3144,11 +3143,31 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// End fir.do_loop.
// Decrement tripVariable.
auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp);
- // A clean iter_arg-free loop (DoConcurrentCleanNestedLoops) has no
- // loop-carried DO variable to step or write back; its terminator is
- // already in place.
+ // Iter_arg-free loop (DoConcurrentCleanNestedLoops): nothing to step in
+ // the body. Materialize the Fortran post-loop value lb + tripCount*step
+ // after the loop so later uses of the DO variable stay correct.
if (doLoopOp.getNumRegionIterArgs() == 0) {
builder->setInsertionPointAfter(doLoopOp);
+ mlir::Type type = info.getLoopVariableType();
+ mlir::Value lb =
+ builder->createConvert(loc, type, doLoopOp.getLowerBound());
+ mlir::Value ub =
+ builder->createConvert(loc, type, doLoopOp.getUpperBound());
+ mlir::Value st =
+ builder->createConvert(loc, type, doLoopOp.getStep());
+ mlir::Value zero = builder->createIntegerConstant(loc, type, 0);
+ mlir::Value trip =
+ mlir::arith::SubIOp::create(*builder, loc, ub, lb, iofAttr);
+ trip = mlir::arith::AddIOp::create(*builder, loc, trip, st, iofAttr);
+ trip = mlir::arith::DivSIOp::create(*builder, loc, trip, st);
+ mlir::Value empty = mlir::arith::CmpIOp::create(
+ *builder, loc, mlir::arith::CmpIPredicate::slt, trip, zero);
+ trip =
+ mlir::arith::SelectOp::create(*builder, loc, empty, zero, trip);
+ mlir::Value last =
+ mlir::arith::MulIOp::create(*builder, loc, trip, st, iofAttr);
+ last = mlir::arith::AddIOp::create(*builder, loc, lb, last, iofAttr);
+ fir::StoreOp::create(*builder, loc, last, info.loopVariable);
continue;
}
builder->setInsertionPointToEnd(doLoopOp.getBody());
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index 04f53362b6b41..6dfe9a58992c7 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -1,6 +1,7 @@
-! Test that -fdo-concurrent-clean-nested-loops lowers a plain DO loop nested in
-! a DO CONCURRENT body without the secondary-induction iter_arg: the DO variable
-! is recomputed from the induction variable instead.
+! Test -fdo-concurrent-clean-nested-loops: a plain DO loop nested in a DO
+! CONCURRENT body is lowered without the secondary-induction iter_arg (the DO
+! variable is recomputed from the induction variable), while the Fortran
+! post-loop value of the DO variable is still materialized after the loop.
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s --check-prefixes=CHECK,DEFAULT
! RUN: bbc -emit-hlfir -fdo-concurrent-clean-nested-loops -o - %s | FileCheck %s --check-prefixes=CHECK,CLEAN
@@ -8,24 +9,34 @@
subroutine nested(a, n)
implicit none
integer :: n, i, j
- integer :: a(n, n)
- do concurrent (j=1:n)
- do i = 1, n
- a(i, j) = i
+ integer :: a(n)
+ do concurrent (i=1:n)
+ do j = 1, 3
end do
+ a(i) = j
end do
end subroutine
-! CHECK-LABEL: func.func @_QPnested
-! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnestedEi"}
-! CHECK: fir.do_concurrent
-! CHECK: fir.do_concurrent.loop (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}})
+! CHECK-LABEL: func.func @_QPnested
+! CHECK: %[[J_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnestedEj"}
+! CHECK: fir.do_concurrent
+! CHECK: fir.do_concurrent.loop
-! The nested plain DO loop:
-! DEFAULT: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[IV:.*]] = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
+! Default lowering: nested loop carries the DO variable as an iter_arg and the
+! post-loop value is the loop result.
+! DEFAULT: %[[RES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[RES]] to %[[J_DECL]]#0 : !fir.ref<i32>
-! CLEAN: fir.do_loop %[[IV:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
-! CLEAN-NOT: iter_args
-! CLEAN: %[[IV_CVT:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CLEAN: fir.store %[[IV_CVT]] to %[[I_DECL]]#0 : !fir.ref<i32>
+! Clean lowering: nested loop has no iter_arg; the post-loop value is computed
+! as lb + tripCount*step after the loop and stored to the DO variable.
+! CLEAN: fir.do_loop %{{.*}} = %[[LB:.*]] to %[[UB:.*]] step %[[ST:.*]] {
+! CLEAN-NOT: iter_args
+! CLEAN: }
+! CLEAN: %[[DIFF:.*]] = arith.subi %{{.*}}, %{{.*}} overflow<nsw> : i32
+! CLEAN: %[[ADD:.*]] = arith.addi %[[DIFF]], %{{.*}} overflow<nsw> : i32
+! CLEAN: %[[TRIP:.*]] = arith.divsi %[[ADD]], %{{.*}} : i32
+! CLEAN: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %{{.*}} : i32
+! CLEAN: %[[SEL:.*]] = arith.select %[[CMP]], %{{.*}}, %[[TRIP]] : i32
+! CLEAN: %[[MUL:.*]] = arith.muli %[[SEL]], %{{.*}} overflow<nsw> : i32
+! CLEAN: %[[LAST:.*]] = arith.addi %{{.*}}, %[[MUL]] overflow<nsw> : i32
+! CLEAN: fir.store %[[LAST]] to %[[J_DECL]]#0 : !fir.ref<i32>
>From 2f62e846a4366f3183ff55fb1d647fa15d6bf855 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 30 Jun 2026 14:27:53 -0700
Subject: [PATCH 4/9] [flang][test] Tighten checks and add non-nested negative
case
Chain the post-loop value operands through captured SSA names instead of
wildcards, and add a plain DO loop outside any DO CONCURRENT to confirm it
keeps its iter_arg when the option is enabled.
---
.../do_concurrent_clean_nested_loops.f90 | 43 ++++++++++++++-----
1 file changed, 32 insertions(+), 11 deletions(-)
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index 6dfe9a58992c7..eee4b26117e65 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -1,7 +1,8 @@
! Test -fdo-concurrent-clean-nested-loops: a plain DO loop nested in a DO
! CONCURRENT body is lowered without the secondary-induction iter_arg (the DO
! variable is recomputed from the induction variable), while the Fortran
-! post-loop value of the DO variable is still materialized after the loop.
+! post-loop value of the DO variable is still materialized after the loop. A
+! plain DO loop that is not nested in a DO CONCURRENT body is unaffected.
! RUN: bbc -emit-hlfir -o - %s | FileCheck %s --check-prefixes=CHECK,DEFAULT
! RUN: bbc -emit-hlfir -fdo-concurrent-clean-nested-loops -o - %s | FileCheck %s --check-prefixes=CHECK,CLEAN
@@ -27,16 +28,36 @@ subroutine nested(a, n)
! DEFAULT: %[[RES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
! DEFAULT: fir.store %[[RES]] to %[[J_DECL]]#0 : !fir.ref<i32>
-! Clean lowering: nested loop has no iter_arg; the post-loop value is computed
-! as lb + tripCount*step after the loop and stored to the DO variable.
-! CLEAN: fir.do_loop %{{.*}} = %[[LB:.*]] to %[[UB:.*]] step %[[ST:.*]] {
+! Clean lowering: nested loop has no iter_arg and the body recomputes the DO
+! variable from the induction variable; the post-loop value is computed as
+! lb + tripCount*step after the loop and stored to the DO variable.
+! CLEAN: fir.do_loop %{{.*}} = %[[LB:[^ ]+]] to %[[UB:[^ ]+]] step %[[ST:[^ ]+]] {
! CLEAN-NOT: iter_args
+! CLEAN: %[[IV:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CLEAN: fir.store %[[IV]] to %[[J_DECL]]#0 : !fir.ref<i32>
! CLEAN: }
-! CLEAN: %[[DIFF:.*]] = arith.subi %{{.*}}, %{{.*}} overflow<nsw> : i32
-! CLEAN: %[[ADD:.*]] = arith.addi %[[DIFF]], %{{.*}} overflow<nsw> : i32
-! CLEAN: %[[TRIP:.*]] = arith.divsi %[[ADD]], %{{.*}} : i32
-! CLEAN: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %{{.*}} : i32
-! CLEAN: %[[SEL:.*]] = arith.select %[[CMP]], %{{.*}}, %[[TRIP]] : i32
-! CLEAN: %[[MUL:.*]] = arith.muli %[[SEL]], %{{.*}} overflow<nsw> : i32
-! CLEAN: %[[LAST:.*]] = arith.addi %{{.*}}, %[[MUL]] overflow<nsw> : i32
+! CLEAN: %[[LBI:.*]] = fir.convert %[[LB]] : (index) -> i32
+! CLEAN: %[[UBI:.*]] = fir.convert %[[UB]] : (index) -> i32
+! CLEAN: %[[STI:.*]] = fir.convert %[[ST]] : (index) -> i32
+! CLEAN: %[[C0:.*]] = arith.constant 0 : i32
+! CLEAN: %[[DIFF:.*]] = arith.subi %[[UBI]], %[[LBI]] overflow<nsw> : i32
+! CLEAN: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STI]] overflow<nsw> : i32
+! CLEAN: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STI]] : i32
+! CLEAN: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CLEAN: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CLEAN: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STI]] overflow<nsw> : i32
+! CLEAN: %[[LAST:.*]] = arith.addi %[[LBI]], %[[MUL]] overflow<nsw> : i32
! CLEAN: fir.store %[[LAST]] to %[[J_DECL]]#0 : !fir.ref<i32>
+
+! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
+! when the option is enabled.
+subroutine not_nested(x)
+ implicit none
+ integer :: x, j
+ do j = 1, 3
+ end do
+ x = j
+end subroutine
+
+! CHECK-LABEL: func.func @_QPnot_nested
+! CLEAN: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
>From f514139fcc18fb7e1d075b12b47187eaf98fbf3c Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 30 Jun 2026 14:37:18 -0700
Subject: [PATCH 5/9] [flang][test] Add non-unit lower-bound/step nested case
Cover do j=2,8,2 so the post-loop value check exercises lb + tripCount*step
rather than an lb=1/step=1 special case.
---
.../do_concurrent_clean_nested_loops.f90 | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index eee4b26117e65..87b25aa0002e1 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -49,6 +49,37 @@ subroutine nested(a, n)
! CLEAN: %[[LAST:.*]] = arith.addi %[[LBI]], %[[MUL]] overflow<nsw> : i32
! CLEAN: fir.store %[[LAST]] to %[[J_DECL]]#0 : !fir.ref<i32>
+! Non-unit lower bound and step: the post-loop value must still be lb +
+! tripCount*step (here 2 + 4*2 = 10), not a hard-coded lb=1/step=1 form.
+subroutine nested_stride(a, n)
+ implicit none
+ integer :: n, i, j
+ integer :: a(n)
+ do concurrent (i=1:n)
+ do j = 2, 8, 2
+ end do
+ a(i) = j
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPnested_stride
+! CHECK: %[[SJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_strideEj"}
+! CLEAN: fir.do_loop %{{.*}} = %[[SLB:[^ ]+]] to %[[SUB:[^ ]+]] step %[[SST:[^ ]+]] {
+! CLEAN-NOT: iter_args
+! CLEAN: }
+! CLEAN: %[[SLBI:.*]] = fir.convert %[[SLB]] : (index) -> i32
+! CLEAN: %[[SUBI:.*]] = fir.convert %[[SUB]] : (index) -> i32
+! CLEAN: %[[SSTI:.*]] = fir.convert %[[SST]] : (index) -> i32
+! CLEAN: %[[SC0:.*]] = arith.constant 0 : i32
+! CLEAN: %[[SDIFF:.*]] = arith.subi %[[SUBI]], %[[SLBI]] overflow<nsw> : i32
+! CLEAN: %[[SADD:.*]] = arith.addi %[[SDIFF]], %[[SSTI]] overflow<nsw> : i32
+! CLEAN: %[[STRIP:.*]] = arith.divsi %[[SADD]], %[[SSTI]] : i32
+! CLEAN: %[[SCMP:.*]] = arith.cmpi slt, %[[STRIP]], %[[SC0]] : i32
+! CLEAN: %[[SSEL:.*]] = arith.select %[[SCMP]], %[[SC0]], %[[STRIP]] : i32
+! CLEAN: %[[SMUL:.*]] = arith.muli %[[SSEL]], %[[SSTI]] overflow<nsw> : i32
+! CLEAN: %[[SLAST:.*]] = arith.addi %[[SLBI]], %[[SMUL]] overflow<nsw> : i32
+! CLEAN: fir.store %[[SLAST]] to %[[SJ_DECL]]#0 : !fir.ref<i32>
+
! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
! when the option is enabled.
subroutine not_nested(x)
>From b6b64b4a7ac2468018e6259568c939f233cea7b0 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 30 Jun 2026 15:00:24 -0700
Subject: [PATCH 6/9] [flang][test] Add descending-step case and DEFAULT stride
checks
Cover do j=8,2,-2 (final j = 0) for the step<0 post-loop value, and add
DEFAULT (option-off) iter_arg checks for the non-unit-step cases so a
regression that applied clean lowering by default would be caught.
---
.../do_concurrent_clean_nested_loops.f90 | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index 87b25aa0002e1..416bf9d38f041 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -64,6 +64,8 @@ subroutine nested_stride(a, n)
! CHECK-LABEL: func.func @_QPnested_stride
! CHECK: %[[SJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_strideEj"}
+! DEFAULT: %[[SRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[SRES]] to %[[SJ_DECL]]#0 : !fir.ref<i32>
! CLEAN: fir.do_loop %{{.*}} = %[[SLB:[^ ]+]] to %[[SUB:[^ ]+]] step %[[SST:[^ ]+]] {
! CLEAN-NOT: iter_args
! CLEAN: }
@@ -80,6 +82,39 @@ subroutine nested_stride(a, n)
! CLEAN: %[[SLAST:.*]] = arith.addi %[[SLBI]], %[[SMUL]] overflow<nsw> : i32
! CLEAN: fir.store %[[SLAST]] to %[[SJ_DECL]]#0 : !fir.ref<i32>
+! Descending loop (step < 0): the same lb + tripCount*step formula must hold
+! (here 8 + 4*(-2) = 0).
+subroutine nested_stride_neg(a, n)
+ implicit none
+ integer :: n, i, j
+ integer :: a(n)
+ do concurrent (i=1:n)
+ do j = 8, 2, -2
+ end do
+ a(i) = j
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPnested_stride_neg
+! CHECK: %[[NJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_stride_negEj"}
+! DEFAULT: %[[NRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[NRES]] to %[[NJ_DECL]]#0 : !fir.ref<i32>
+! CLEAN: fir.do_loop %{{.*}} = %[[NLB:[^ ]+]] to %[[NUB:[^ ]+]] step %[[NST:[^ ]+]] {
+! CLEAN-NOT: iter_args
+! CLEAN: }
+! CLEAN: %[[NLBI:.*]] = fir.convert %[[NLB]] : (index) -> i32
+! CLEAN: %[[NUBI:.*]] = fir.convert %[[NUB]] : (index) -> i32
+! CLEAN: %[[NSTI:.*]] = fir.convert %[[NST]] : (index) -> i32
+! CLEAN: %[[NC0:.*]] = arith.constant 0 : i32
+! CLEAN: %[[NDIFF:.*]] = arith.subi %[[NUBI]], %[[NLBI]] overflow<nsw> : i32
+! CLEAN: %[[NADD:.*]] = arith.addi %[[NDIFF]], %[[NSTI]] overflow<nsw> : i32
+! CLEAN: %[[NTRIP:.*]] = arith.divsi %[[NADD]], %[[NSTI]] : i32
+! CLEAN: %[[NCMP:.*]] = arith.cmpi slt, %[[NTRIP]], %[[NC0]] : i32
+! CLEAN: %[[NSEL:.*]] = arith.select %[[NCMP]], %[[NC0]], %[[NTRIP]] : i32
+! CLEAN: %[[NMUL:.*]] = arith.muli %[[NSEL]], %[[NSTI]] overflow<nsw> : i32
+! CLEAN: %[[NLAST:.*]] = arith.addi %[[NLBI]], %[[NMUL]] overflow<nsw> : i32
+! CLEAN: fir.store %[[NLAST]] to %[[NJ_DECL]]#0 : !fir.ref<i32>
+
! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
! when the option is enabled.
subroutine not_nested(x)
>From 1a8a18038c3700d798570c589c3fef821e716e76 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 6 Jul 2026 13:54:19 -0700
Subject: [PATCH 7/9] [flang][test] Add multi-IV do concurrent nested loop case
Confirm a DO CONCURRENT with multiple induction variables lowers to a
single fir.do_concurrent.loop (unaffected) while the nested plain DO loop
is still cleaned.
---
.../do_concurrent_clean_nested_loops.f90 | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index 416bf9d38f041..205f53ce00c9d 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -115,6 +115,41 @@ subroutine nested_stride_neg(a, n)
! CLEAN: %[[NLAST:.*]] = arith.addi %[[NLBI]], %[[NMUL]] overflow<nsw> : i32
! CLEAN: fir.store %[[NLAST]] to %[[NJ_DECL]]#0 : !fir.ref<i32>
+! A DO CONCURRENT with multiple induction variables is lowered as a single
+! fir.do_concurrent.loop carrying all the IVs (unaffected by the option); only
+! the nested plain DO loop is cleaned.
+subroutine multi_iv(a, n, m)
+ implicit none
+ integer :: n, m, i, j, k
+ integer :: a(n, m)
+ do concurrent (i=1:n, j=1:m)
+ do k = 1, 3
+ a(i, j) = a(i, j) + k
+ end do
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmulti_iv
+! CHECK: %[[MK_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFmulti_ivEk"}
+! CHECK: fir.do_concurrent.loop (%{{[^)]*}}, %{{[^)]*}}) = (%{{[^)]*}}, %{{[^)]*}}) to (%{{[^)]*}}, %{{[^)]*}}) step (%{{[^)]*}}, %{{[^)]*}}) {
+! DEFAULT: %[[MRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[MRES]] to %[[MK_DECL]]#0 : !fir.ref<i32>
+! CLEAN: fir.do_loop %{{.*}} = %[[MLB:[^ ]+]] to %[[MUB:[^ ]+]] step %[[MST:[^ ]+]] {
+! CLEAN-NOT: iter_args
+! CLEAN: }
+! CLEAN: %[[MLBI:.*]] = fir.convert %[[MLB]] : (index) -> i32
+! CLEAN: %[[MUBI:.*]] = fir.convert %[[MUB]] : (index) -> i32
+! CLEAN: %[[MSTI:.*]] = fir.convert %[[MST]] : (index) -> i32
+! CLEAN: %[[MC0:.*]] = arith.constant 0 : i32
+! CLEAN: %[[MDIFF:.*]] = arith.subi %[[MUBI]], %[[MLBI]] overflow<nsw> : i32
+! CLEAN: %[[MADD:.*]] = arith.addi %[[MDIFF]], %[[MSTI]] overflow<nsw> : i32
+! CLEAN: %[[MTRIP:.*]] = arith.divsi %[[MADD]], %[[MSTI]] : i32
+! CLEAN: %[[MCMP:.*]] = arith.cmpi slt, %[[MTRIP]], %[[MC0]] : i32
+! CLEAN: %[[MSEL:.*]] = arith.select %[[MCMP]], %[[MC0]], %[[MTRIP]] : i32
+! CLEAN: %[[MMUL:.*]] = arith.muli %[[MSEL]], %[[MSTI]] overflow<nsw> : i32
+! CLEAN: %[[MLAST:.*]] = arith.addi %[[MLBI]], %[[MMUL]] overflow<nsw> : i32
+! CLEAN: fir.store %[[MLAST]] to %[[MK_DECL]]#0 : !fir.ref<i32>
+
! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
! when the option is enabled.
subroutine not_nested(x)
>From 9c01b4f9bd91698553969c6c99ffdfb5a49616ff Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Mon, 6 Jul 2026 13:59:33 -0700
Subject: [PATCH 8/9] [flang][test] Cover DO CONCURRENT nested within cleaned
loops
Add cases for a DO CONCURRENT nested inside a cleaned plain DO loop, and a
plain DO loop nested inside such an inner DO CONCURRENT, confirming each
concurrent header is preserved and every sequential loop is cleaned.
---
.../do_concurrent_clean_nested_loops.f90 | 51 +++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
index 205f53ce00c9d..decc6724a2c1b 100644
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
@@ -150,6 +150,57 @@ subroutine multi_iv(a, n, m)
! CLEAN: %[[MLAST:.*]] = arith.addi %[[MLBI]], %[[MMUL]] overflow<nsw> : i32
! CLEAN: fir.store %[[MLAST]] to %[[MK_DECL]]#0 : !fir.ref<i32>
+! A DO CONCURRENT nested inside one of the cleaned plain DO loops is still
+! lowered as its own fir.do_concurrent.loop; the enclosing plain DO stays clean
+! and its post-loop value is materialized.
+subroutine dc_in_clean_loop(a, n, m)
+ implicit none
+ integer :: n, m, i, j, k
+ integer :: a(n)
+ do concurrent (i=1:n)
+ do j = 1, 3
+ do concurrent (k=1:m)
+ a(i) = a(i) + j*k
+ end do
+ end do
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdc_in_clean_loop
+! CHECK: %[[DJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdc_in_clean_loopEj"}
+! CHECK: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
+! DEFAULT: %[[DJRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.store %[[DJRES]] to %[[DJ_DECL]]#0 : !fir.ref<i32>
+! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
+! CLEAN: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
+! CLEAN: %{{.*}} = arith.divsi %{{.*}}, %{{.*}} : i32
+! CLEAN: fir.store %{{.*}} to %[[DJ_DECL]]#0 : !fir.ref<i32>
+
+! Plain DO loops inside a DO CONCURRENT that is itself nested in the body are
+! cleaned at any depth.
+subroutine loop_in_nested_dc(a, n, m, p)
+ implicit none
+ integer :: n, m, p, i, j, k, l
+ integer :: a(n)
+ do concurrent (i=1:n)
+ do j = 1, 3
+ do concurrent (k=1:m)
+ do l = 1, 4
+ a(i) = a(i) + j*k*l
+ end do
+ end do
+ end do
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPloop_in_nested_dc
+! CHECK: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
+! DEFAULT: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! DEFAULT: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
+! CLEAN: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
+! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
+
! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
! when the option is enabled.
subroutine not_nested(x)
>From 165951cf567f150e209c0c6a4f95232fe2c529d4 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 7 Jul 2026 13:44:30 -0700
Subject: [PATCH 9/9] [flang] Lower all plain DO loops without
secondary-induction iter_arg
Generalize the clean lowering to every structured DO loop: recompute the DO
variable from the induction variable in the body and materialize the Fortran
post-loop value after the loop. This removes the redundant loop-carried value
that hid memory recurrences from later analyses. Drops the now-unnecessary
DoConcurrentCleanNestedLoops option and regenerates the affected FIR goldens.
---
flang/include/flang/Lower/LoweringOptions.def | 9 -
flang/lib/Lower/Bridge.cpp | 100 ++------
flang/test/Integration/ivdep.f90 | 6 -
flang/test/Lower/OpenACC/acc-cache.f90 | 5 +-
flang/test/Lower/OpenACC/acc-declare.f90 | 18 +-
flang/test/Lower/OpenMP/default-clause.f90 | 4 +-
.../Lower/OpenMP/hlfir-seqloop-parallel.f90 | 60 ++++-
.../OpenMP/parallel-private-clause-fixes.f90 | 21 +-
.../OpenMP/sections-predetermined-private.f90 | 34 ++-
flang/test/Lower/OpenMP/shared-loop.f90 | 67 ++++--
...oop-reduction-allocatable-array-minmax.f90 | 21 +-
flang/test/Lower/OpenMP/wsloop-variable.f90 | 21 +-
flang/test/Lower/allocatable-polymorphic.f90 | 4 +-
flang/test/Lower/dispatch.f90 | 14 +-
.../do_concurrent_clean_nested_loops.f90 | 215 ------------------
.../do_concurrent_loop_in_nested_block.f90 | 5 +-
flang/test/Lower/do_loop.f90 | 170 ++++++++------
flang/test/Lower/do_loop_unstructured.f90 | 20 +-
flang/test/Lower/infinite_loop.f90 | 23 +-
flang/test/Lower/inline_directive.f90 | 4 +-
flang/test/Lower/ivdep.f90 | 12 -
flang/test/Lower/loops.f90 | 4 +-
flang/test/Lower/loops2.f90 | 32 ++-
flang/test/Lower/mixed_loops.f90 | 21 +-
flang/test/Lower/nsw.f90 | 3 +-
.../DoConcurrent/skip_all_nested_loops.f90 | 7 +-
flang/tools/bbc/bbc.cpp | 8 -
27 files changed, 407 insertions(+), 501 deletions(-)
delete mode 100644 flang/test/Lower/do_concurrent_clean_nested_loops.f90
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 7fa295d74c75c..e89ad75704609 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -89,14 +89,5 @@ ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0)
/// Portable, Extremum, ExtremeNum). Default: Legacy.
ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0)
-/// If true, lower plain DO loops nested inside a DO CONCURRENT body without the
-/// secondary-induction iter_arg: the DO variable is recomputed from the
-/// induction variable in the body. This keeps the loop body free of a
-/// loop-carried value that would otherwise hide memory recurrences (e.g.
-/// reductions) from later analyses. The Fortran post-loop value of the DO
-/// variable is still materialized after the loop, so the lowering is
-/// semantics-preserving. Off by default.
-ENUM_LOWERINGOPT(DoConcurrentCleanNestedLoops, unsigned, 1, 0)
-
#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index dad978cc3f3aa..ca587749da657 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2903,18 +2903,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
- /// Return true if the builder's current insertion point is within a
- /// `fir.do_concurrent.loop` region (i.e. a plain DO loop being lowered here
- /// is nested inside a DO CONCURRENT body).
- bool isInsideDoConcurrentLoop() {
- mlir::Block *block = builder->getInsertionBlock();
- if (!block)
- return false;
- mlir::Operation *parentOp = block->getParentOp();
- return parentOp && (mlir::isa<fir::DoConcurrentLoopOp>(parentOp) ||
- parentOp->getParentOfType<fir::DoConcurrentLoopOp>());
- }
-
/// Generate FIR to begin a structured or unstructured increment loop nest.
void genFIRIncrementLoopBegin(
IncrementLoopNestInfo &incrementLoopNestInfo,
@@ -2974,31 +2962,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// recurrences (e.g. reductions) stay visible to later analyses. The DO
// variable is recomputed from the induction variable in the body; its
// post-loop value is materialized in genFIRIncrementLoopEnd.
- if (getLoweringOptions().getDoConcurrentCleanNestedLoops() &&
- isInsideDoConcurrentLoop()) {
- auto loopOp = fir::DoLoopOp::create(
- *builder, loc, lowerValue, upperValue, stepValue,
- /*unordered=*/false, /*finalCountValue=*/false,
- /*iterArgs=*/mlir::ValueRange{});
- info.loopOp = loopOp;
- builder->setInsertionPointToStart(loopOp.getBody());
- mlir::Value loopValue = builder->createConvert(
- loc, loopVarType, loopOp.getInductionVar());
- fir::StoreOp::create(*builder, loc, loopValue, info.loopVariable);
- addLoopAnnotationAttr(info, dirs);
- continue;
- }
-
auto loopOp = fir::DoLoopOp::create(
*builder, loc, lowerValue, upperValue, stepValue,
- /*unordered=*/false,
- /*finalCountValue=*/false,
- builder->createConvert(loc, loopVarType, lowerValue));
+ /*unordered=*/false, /*finalCountValue=*/false,
+ /*iterArgs=*/mlir::ValueRange{});
info.loopOp = loopOp;
builder->setInsertionPointToStart(loopOp.getBody());
- mlir::Value loopValue = loopOp.getRegionIterArgs()[0];
-
- // Update the loop variable value in case it has non-index references.
+ mlir::Value loopValue =
+ builder->createConvert(loc, loopVarType, loopOp.getInductionVar());
fir::StoreOp::create(*builder, loc, loopValue, info.loopVariable);
addLoopAnnotationAttr(info, dirs);
continue;
@@ -3140,50 +3111,29 @@ class FirConverter : public Fortran::lower::AbstractConverter {
continue;
}
- // End fir.do_loop.
- // Decrement tripVariable.
+ // End fir.do_loop. The loop carries no secondary-induction iter_arg, so
+ // materialize the Fortran post-loop value lb + tripCount*step after the
+ // loop for later uses of the DO variable.
auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp);
- // Iter_arg-free loop (DoConcurrentCleanNestedLoops): nothing to step in
- // the body. Materialize the Fortran post-loop value lb + tripCount*step
- // after the loop so later uses of the DO variable stay correct.
- if (doLoopOp.getNumRegionIterArgs() == 0) {
- builder->setInsertionPointAfter(doLoopOp);
- mlir::Type type = info.getLoopVariableType();
- mlir::Value lb =
- builder->createConvert(loc, type, doLoopOp.getLowerBound());
- mlir::Value ub =
- builder->createConvert(loc, type, doLoopOp.getUpperBound());
- mlir::Value st =
- builder->createConvert(loc, type, doLoopOp.getStep());
- mlir::Value zero = builder->createIntegerConstant(loc, type, 0);
- mlir::Value trip =
- mlir::arith::SubIOp::create(*builder, loc, ub, lb, iofAttr);
- trip = mlir::arith::AddIOp::create(*builder, loc, trip, st, iofAttr);
- trip = mlir::arith::DivSIOp::create(*builder, loc, trip, st);
- mlir::Value empty = mlir::arith::CmpIOp::create(
- *builder, loc, mlir::arith::CmpIPredicate::slt, trip, zero);
- trip =
- mlir::arith::SelectOp::create(*builder, loc, empty, zero, trip);
- mlir::Value last =
- mlir::arith::MulIOp::create(*builder, loc, trip, st, iofAttr);
- last = mlir::arith::AddIOp::create(*builder, loc, lb, last, iofAttr);
- fir::StoreOp::create(*builder, loc, last, info.loopVariable);
- continue;
- }
- builder->setInsertionPointToEnd(doLoopOp.getBody());
- // Step loopVariable to help optimizations such as vectorization.
- // Induction variable elimination will clean up as necessary.
- mlir::Value step = builder->createConvert(
- loc, info.getLoopVariableType(), doLoopOp.getStep());
- mlir::Value loopVar =
- fir::LoadOp::create(*builder, loc, info.loopVariable);
- mlir::Value loopVarInc =
- mlir::arith::AddIOp::create(*builder, loc, loopVar, step, iofAttr);
- fir::ResultOp::create(*builder, loc, loopVarInc);
builder->setInsertionPointAfter(doLoopOp);
- // The loop control variable may be used after the loop.
- fir::StoreOp::create(*builder, loc, doLoopOp.getResult(0),
- info.loopVariable);
+ mlir::Type type = info.getLoopVariableType();
+ mlir::Value lb =
+ builder->createConvert(loc, type, doLoopOp.getLowerBound());
+ mlir::Value ub =
+ builder->createConvert(loc, type, doLoopOp.getUpperBound());
+ mlir::Value st = builder->createConvert(loc, type, doLoopOp.getStep());
+ mlir::Value zero = builder->createIntegerConstant(loc, type, 0);
+ mlir::Value trip =
+ mlir::arith::SubIOp::create(*builder, loc, ub, lb, iofAttr);
+ trip = mlir::arith::AddIOp::create(*builder, loc, trip, st, iofAttr);
+ trip = mlir::arith::DivSIOp::create(*builder, loc, trip, st);
+ mlir::Value empty = mlir::arith::CmpIOp::create(
+ *builder, loc, mlir::arith::CmpIPredicate::slt, trip, zero);
+ trip = mlir::arith::SelectOp::create(*builder, loc, empty, zero, trip);
+ mlir::Value last =
+ mlir::arith::MulIOp::create(*builder, loc, trip, st, iofAttr);
+ last = mlir::arith::AddIOp::create(*builder, loc, lb, last, iofAttr);
+ fir::StoreOp::create(*builder, loc, last, info.loopVariable);
continue;
}
diff --git a/flang/test/Integration/ivdep.f90 b/flang/test/Integration/ivdep.f90
index d72ab23af7ad2..9882fe148262f 100644
--- a/flang/test/Integration/ivdep.f90
+++ b/flang/test/Integration/ivdep.f90
@@ -16,8 +16,6 @@ subroutine ivdep_test1
!CHECK: %[[VAL_13:.*]] = add nuw nsw i64 %[[VAL_12]], 0
!CHECK: %[[VAL_14:.*]] = getelementptr nusw nuw i32, ptr {{.*}}, i64 %[[VAL_13]]
!CHECK: store i32 %[[VAL_8]], ptr %[[VAL_14]], align 4, !llvm.access.group [[DISTRINCT]]
- !CHECK: %[[VAL_15:.*]] = load i32, ptr {{.*}}, align 4, !llvm.access.group [[DISTRINCT]]
- !CHECK: %[[VAL_16:.*]] = add nsw i32 %[[VAL_15]], 1
!CHECK: %[[VAL_17:.*]] = sub i64 {{.*}}, 1
!CHECK: br label {{.*}}, !llvm.loop ![[ANNOTATION:.*]]
end do
@@ -54,8 +52,6 @@ subroutine ivdep_test2
!CHECK: %[[VAL_28:.*]] = add nuw nsw i64 %[[VAL_27]], 0
!CHECK: %[[VAL_29:.*]] = getelementptr nusw nuw i32, ptr {{.*}}, i64 %[[VAL_28]]
!CHECK: store i32 %[[VAL_24]], ptr %[[VAL_29]], align 4, !llvm.access.group [[DISTRINCT1]]
- !CHECK: %[[VAL_30:.*]] = load i32, ptr {{.*}}, align 4, !llvm.access.group [[DISTRINCT1]]
- !CHECK: %[[VAL_31:.*]] = add nsw i32 %[[VAL_30]], 1
!CHECK: %[[VAL_32:.*]] = sub i64 {{.*}}, 1
!CHECK: br label {{.*}}, !llvm.loop ![[ANNOTATION1:.*]]
end do
@@ -93,8 +89,6 @@ subroutine ivdep_test3
!CHECK: %[[VAL_29:.*]] = getelementptr nusw nuw i32, ptr {{.*}}, i64 %[[VAL_28]]
!CHECK: store i32 %[[VAL_24]], ptr %[[VAL_29]], align 4, !llvm.access.group [[DISTRINCT2]]
!CHECK: call void @_QFivdep_test3Pfoo(), !llvm.access.group [[DISTRINCT2]]
- !CHECK: %[[VAL_30:.*]] = load i32, ptr {{.*}}, align 4, !llvm.access.group [[DISTRINCT2]]
- !CHECK: %[[VAL_31:.*]] = add nsw i32 %[[VAL_30]], 1
!CHECK: %[[VAL_32:.*]] = sub i64 {{.*}}, 1
!CHECK: br label {{.*}}, !llvm.loop ![[ANNOTATION2:.*]]
end do
diff --git a/flang/test/Lower/OpenACC/acc-cache.f90 b/flang/test/Lower/OpenACC/acc-cache.f90
index eb32f3b704198..03e06467f694d 100644
--- a/flang/test/Lower/OpenACC/acc-cache.f90
+++ b/flang/test/Lower/OpenACC/acc-cache.f90
@@ -242,9 +242,10 @@ subroutine test_cache_2d_loop_vars()
! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_cache_2d_loop_varsEi"}
! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
! Inner loop j (non-acc loop, fir.do_loop)
-! CHECK: fir.do_loop %[[J_IV:.*]] = {{.*}} iter_args(%[[J_ITER:.*]] = {{.*}})
+! CHECK: fir.do_loop %[[J_IV:.*]] = {{.*}} to {{.*}} step {{.*}} {
! Inner loop iterator j is stored to j variable
-! CHECK: fir.store %[[J_ITER]] to %[[J_REF:.*]] : !fir.ref<i32>
+! CHECK: %[[J_CONV:.*]] = fir.convert %[[J_IV]] : (index) -> i32
+! CHECK: fir.store %[[J_CONV]] to %[[J_REF:.*]] : !fir.ref<i32>
! Dimension 1 bounds from j: lowerbound = j-1, upperbound = j
! CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%{{.*}} : index) upperbound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) startIdx(%{{.*}} : index)
! Dimension 2 bounds from i: lowerbound = i-1, upperbound = i
diff --git a/flang/test/Lower/OpenACC/acc-declare.f90 b/flang/test/Lower/OpenACC/acc-declare.f90
index 3339fa31c3d27..bda234a29b104 100644
--- a/flang/test/Lower/OpenACC/acc-declare.f90
+++ b/flang/test/Lower/OpenACC/acc-declare.f90
@@ -20,7 +20,7 @@ subroutine acc_declare_copy()
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOCA]](%{{.*}}) {acc.declare = #acc.declare<dataClause = acc_copy>, uniq_name = "_QMacc_declareFacc_declare_copyEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[COPYIN:.*]] = acc.copyin varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {dataClause = #acc<data_clause acc_copy>, name = "a"}
! CHECK: %[[TOKEN:.*]] = acc.declare_enter dataOperands(%[[COPYIN]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: }
! CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[COPYIN]] : !fir.ref<!fir.array<100xi32>>)
! CHECK: acc.copyout accPtr(%[[COPYIN]] : !fir.ref<!fir.array<100xi32>>) to varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) {dataClause = #acc<data_clause acc_copy>, name = "a"}
@@ -40,7 +40,7 @@ subroutine acc_declare_create()
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOCA]](%{{.*}}) {acc.declare = #acc.declare<dataClause = acc_create>, uniq_name = "_QMacc_declareFacc_declare_createEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: %[[TOKEN:.*]] = acc.declare_enter dataOperands(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: }
! CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>)
! CHECK: acc.delete accPtr(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>) {dataClause = #acc<data_clause acc_create>, name = "a"}
@@ -60,7 +60,7 @@ subroutine acc_declare_present(a)
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {acc.declare = #acc.declare<dataClause = acc_present>, uniq_name = "_QMacc_declareFacc_declare_presentEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: %[[TOKEN:.*]] = acc.declare_enter dataOperands(%[[PRESENT]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[PRESENT]] : !fir.ref<!fir.array<100xi32>>)
! CHECK: acc.delete accPtr(%[[PRESENT]] : !fir.ref<!fir.array<100xi32>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
@@ -98,7 +98,7 @@ subroutine acc_declare_copyin()
! CHECK: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[ADECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: %[[COPYIN_B:.*]] = acc.copyin varPtr(%[[BDECL]]#0 : !fir.ref<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>> {dataClause = #acc<data_clause acc_copyin_readonly>, name = "b"}
! CHECK: acc.declare_enter dataOperands(%[[COPYIN_A]], %[[COPYIN_B]] : !fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<10xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: acc.delete accPtr(%[[COPYIN_A]] : !fir.ref<!fir.array<100xi32>>) {dataClause = #acc<data_clause acc_copyin>, name = "a"}
! CHECK: acc.delete accPtr(%[[COPYIN_B]] : !fir.ref<!fir.array<10xi32>>) {dataClause = #acc<data_clause acc_copyin_readonly>, name = "b"}
@@ -116,7 +116,7 @@ subroutine acc_declare_copyout()
! CHECK: %[[ADECL:.*]]:2 = hlfir.declare %[[A]](%{{.*}}) {acc.declare = #acc.declare<dataClause = acc_copyout>, uniq_name = "_QMacc_declareFacc_declare_copyoutEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[ADECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {dataClause = #acc<data_clause acc_copyout>, name = "a"}
! CHECK: %[[TOKEN:.*]] = acc.declare_enter dataOperands(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>)
! CHECK: acc.copyout accPtr(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>) to varPtr(%[[ADECL]]#0 : !fir.ref<!fir.array<100xi32>>) {name = "a"}
! CHECK: return
@@ -135,7 +135,7 @@ subroutine acc_declare_deviceptr(a)
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {acc.declare = #acc.declare<dataClause = acc_deviceptr>, uniq_name = "_QMacc_declareFacc_declare_deviceptrEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[DEVICEPTR:.*]] = acc.deviceptr varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: acc.declare_enter dataOperands(%[[DEVICEPTR]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
subroutine acc_declare_link(a)
integer :: a(100), i
@@ -151,7 +151,7 @@ subroutine acc_declare_link(a)
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {acc.declare = #acc.declare<dataClause = acc_declare_link>, uniq_name = "_QMacc_declareFacc_declare_linkEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[LINK:.*]] = acc.declare_link varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: acc.declare_enter dataOperands(%[[LINK]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
subroutine acc_declare_device_resident(a)
integer :: a(100), i
@@ -167,7 +167,7 @@ subroutine acc_declare_device_resident(a)
! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {acc.declare = #acc.declare<dataClause = acc_declare_device_resident>, uniq_name = "_QMacc_declareFacc_declare_device_residentEa"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
! CHECK: %[[DEVICERES:.*]] = acc.declare_device_resident varPtr(%[[DECL]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {name = "a"}
! CHECK: %[[TOKEN:.*]] = acc.declare_enter dataOperands(%[[DEVICERES]] : !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%arg{{.*}} = %{{.*}}) -> (i32)
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[DEVICERES]] : !fir.ref<!fir.array<100xi32>>)
! CHECK: acc.delete accPtr(%[[DEVICERES]] : !fir.ref<!fir.array<100xi32>>) {dataClause = #acc<data_clause acc_declare_device_resident>, name = "a"}
@@ -296,7 +296,7 @@ subroutine acc_declare_multiple_directive(a, b)
! CHECK: %[[COPYIN:.*]] = acc.copyin varPtr(%[[DECL_A]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {dataClause = #acc<data_clause acc_copy>, name = "a"}
! CHECK: %[[CREATE:.*]] = acc.create varPtr(%[[DECL_B]]#0 : !fir.ref<!fir.array<100xi32>>) -> !fir.ref<!fir.array<100xi32>> {dataClause = #acc<data_clause acc_copyout>, name = "b"}
! CHECK: acc.declare_enter dataOperands(%[[COPYIN]], %[[CREATE]] : !fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
-! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
! CHECK: acc.copyout accPtr(%[[CREATE]] : !fir.ref<!fir.array<100xi32>>) to varPtr(%[[DECL_B]]#0 : !fir.ref<!fir.array<100xi32>>) {name = "b"}
diff --git a/flang/test/Lower/OpenMP/default-clause.f90 b/flang/test/Lower/OpenMP/default-clause.f90
index c16d19c129b8f..511abf64c202f 100644
--- a/flang/test/Lower/OpenMP/default-clause.f90
+++ b/flang/test/Lower/OpenMP/default-clause.f90
@@ -463,12 +463,12 @@ subroutine nested_constructs
!CHECK: %[[INNER_J_DECL:.*]]:2 = hlfir.declare %[[INNER_J]] {{.*}}
!$omp parallel default(private) firstprivate(y)
-!CHECK: {{.*}} = fir.do_loop {{.*}} {
+!CHECK: fir.do_loop {{.*}} {
do i = 1, 10
!CHECK: %[[CONST_1:.*]] = arith.constant 1 : i32
!CHECK: hlfir.assign %[[CONST_1]] to %[[INNER_Y_DECL]]#0 : i32, !fir.ref<i32>
y = 1
-!CHECK: {{.*}} = fir.do_loop {{.*}} {
+!CHECK: fir.do_loop {{.*}} {
do j = 1, 10
!CHECK: %[[CONST_20:.*]] = arith.constant 20 : i32
!CHECK: hlfir.assign %[[CONST_20]] to %[[INNER_Z_DECL]]#0 : i32, !fir.ref<i32>
diff --git a/flang/test/Lower/OpenMP/hlfir-seqloop-parallel.f90 b/flang/test/Lower/OpenMP/hlfir-seqloop-parallel.f90
index 7324b3c49fd6f..4b73ce2fd1016 100644
--- a/flang/test/Lower/OpenMP/hlfir-seqloop-parallel.f90
+++ b/flang/test/Lower/OpenMP/hlfir-seqloop-parallel.f90
@@ -22,9 +22,21 @@ subroutine sb1
!CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_ADDR]] {uniq_name = "_QFsb1Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.parallel private({{.*}} %[[I_DECL]]#0 -> %[[I_PVT_ADDR:.*]] : {{.*}}) {
!CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_ADDR]] {uniq_name = "_QFsb1Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[I_FINAL_VAL:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[I_VAL:.*]] = %{{.*}}) -> (i32) {
+!CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
+!CHECK: %[[I_VAL:.*]] = fir.convert %{{.*}} : (index) -> i32
!CHECK: fir.store %[[I_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: }
+!CHECK: %[[I_LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_ST:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_C0:.*]] = arith.constant 0 : i32
+!CHECK: %[[I_D:.*]] = arith.subi %[[I_UB]], %[[I_LB]] overflow<nsw> : i32
+!CHECK: %[[I_A:.*]] = arith.addi %[[I_D]], %[[I_ST]] overflow<nsw> : i32
+!CHECK: %[[I_TR:.*]] = arith.divsi %[[I_A]], %[[I_ST]] : i32
+!CHECK: %[[I_CMP:.*]] = arith.cmpi slt, %[[I_TR]], %[[I_C0]] : i32
+!CHECK: %[[I_SEL:.*]] = arith.select %[[I_CMP]], %[[I_C0]], %[[I_TR]] : i32
+!CHECK: %[[I_M:.*]] = arith.muli %[[I_SEL]], %[[I_ST]] overflow<nsw> : i32
+!CHECK: %[[I_FINAL_VAL:.*]] = arith.addi %[[I_LB]], %[[I_M]] overflow<nsw> : i32
!CHECK: fir.store %[[I_FINAL_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: omp.terminator
!CHECK: }
@@ -58,19 +70,55 @@ subroutine sb2
!CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_ADDR]] {uniq_name = "_QFsb2Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[FINAL_J_VAL:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[J_VAL:.*]] = %{{.*}}) -> (i32) {
+!CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
+!CHECK: %[[J_VAL:.*]] = fir.convert %{{.*}} : (index) -> i32
!CHECK: fir.store %[[J_VAL]] to %[[J_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: fir.if %{{.*}} {
-!CHECK: %[[FINAL_I_VAL:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[I_VAL:.*]] = %{{.*}}) -> (i32) {
+!CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
+!CHECK: %[[I_VAL:.*]] = fir.convert %{{.*}} : (index) -> i32
!CHECK: fir.store %[[I_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: }
+!CHECK: %[[I_LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_ST:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I_C0:.*]] = arith.constant 0 : i32
+!CHECK: %[[I_D:.*]] = arith.subi %[[I_UB]], %[[I_LB]] overflow<nsw> : i32
+!CHECK: %[[I_A:.*]] = arith.addi %[[I_D]], %[[I_ST]] overflow<nsw> : i32
+!CHECK: %[[I_TR:.*]] = arith.divsi %[[I_A]], %[[I_ST]] : i32
+!CHECK: %[[I_CMP:.*]] = arith.cmpi slt, %[[I_TR]], %[[I_C0]] : i32
+!CHECK: %[[I_SEL:.*]] = arith.select %[[I_CMP]], %[[I_C0]], %[[I_TR]] : i32
+!CHECK: %[[I_M:.*]] = arith.muli %[[I_SEL]], %[[I_ST]] overflow<nsw> : i32
+!CHECK: %[[FINAL_I_VAL:.*]] = arith.addi %[[I_LB]], %[[I_M]] overflow<nsw> : i32
!CHECK: fir.store %[[FINAL_I_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: }
-!CHECK: %[[FINAL_I_VAL:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[I_VAL:.*]] = %{{.*}}) -> (i32) {
-!CHECK: fir.store %[[I_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
+!CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
+!CHECK: %[[I_VAL2:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: fir.store %[[I_VAL2]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: }
-!CHECK: fir.store %[[FINAL_I_VAL]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
+!CHECK: %[[I2_LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I2_UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I2_ST:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[I2_C0:.*]] = arith.constant 0 : i32
+!CHECK: %[[I2_D:.*]] = arith.subi %[[I2_UB]], %[[I2_LB]] overflow<nsw> : i32
+!CHECK: %[[I2_A:.*]] = arith.addi %[[I2_D]], %[[I2_ST]] overflow<nsw> : i32
+!CHECK: %[[I2_TR:.*]] = arith.divsi %[[I2_A]], %[[I2_ST]] : i32
+!CHECK: %[[I2_CMP:.*]] = arith.cmpi slt, %[[I2_TR]], %[[I2_C0]] : i32
+!CHECK: %[[I2_SEL:.*]] = arith.select %[[I2_CMP]], %[[I2_C0]], %[[I2_TR]] : i32
+!CHECK: %[[I2_M:.*]] = arith.muli %[[I2_SEL]], %[[I2_ST]] overflow<nsw> : i32
+!CHECK: %[[FINAL_I_VAL2:.*]] = arith.addi %[[I2_LB]], %[[I2_M]] overflow<nsw> : i32
+!CHECK: fir.store %[[FINAL_I_VAL2]] to %[[I_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: }
+!CHECK: %[[J_LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[J_UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[J_ST:.*]] = fir.convert %{{.*}} : (index) -> i32
+!CHECK: %[[J_C0:.*]] = arith.constant 0 : i32
+!CHECK: %[[J_D:.*]] = arith.subi %[[J_UB]], %[[J_LB]] overflow<nsw> : i32
+!CHECK: %[[J_A:.*]] = arith.addi %[[J_D]], %[[J_ST]] overflow<nsw> : i32
+!CHECK: %[[J_TR:.*]] = arith.divsi %[[J_A]], %[[J_ST]] : i32
+!CHECK: %[[J_CMP:.*]] = arith.cmpi slt, %[[J_TR]], %[[J_C0]] : i32
+!CHECK: %[[J_SEL:.*]] = arith.select %[[J_CMP]], %[[J_C0]], %[[J_TR]] : i32
+!CHECK: %[[J_M:.*]] = arith.muli %[[J_SEL]], %[[J_ST]] overflow<nsw> : i32
+!CHECK: %[[FINAL_J_VAL:.*]] = arith.addi %[[J_LB]], %[[J_M]] overflow<nsw> : i32
!CHECK: fir.store %[[FINAL_J_VAL]] to %[[J_PVT_DECL]]#0 : !fir.ref<i32>
!CHECK: omp.terminator
!CHECK: }
diff --git a/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90 b/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90
index e2fbd8b7d1ac9..a061d897456bd 100644
--- a/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90
+++ b/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90
@@ -58,20 +58,25 @@
! CHECK: %[[VAL_9:.*]] = fir.load %[[GAMA_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index
! CHECK: %[[VAL_11:.*]] = arith.constant 1 : index
-! CHECK: %[[LB:.*]] = fir.convert %[[VAL_8]] : (index) -> i32
-! CHECK: %[[VAL_12:.*]] = fir.do_loop %[[VAL_13:[^ ]*]] =
-! CHECK-SAME: %[[VAL_8]] to %[[VAL_10]] step %[[VAL_11]]
-! CHECK-SAME: iter_args(%[[IV:.*]] = %[[LB]]) -> (i32) {
+! CHECK: fir.do_loop %[[VAL_13:[^ ]*]] = %[[VAL_8]] to %[[VAL_10]] step %[[VAL_11]] {
+! CHECK: %[[IV:.*]] = fir.convert %[[VAL_13]] : (index) -> i32
! CHECK: fir.store %[[IV]] to %[[PRIV_J_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[LOAD:.*]] = fir.load %[[PRIV_I_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_15:.*]] = fir.load %[[PRIV_J_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_16:.*]] = arith.addi %[[LOAD]], %[[VAL_15]] : i32
! CHECK: hlfir.assign %[[VAL_16]] to %[[PRIV_X_DECL]]#0 : i32, !fir.ref<i32>
-! CHECK: %[[STEPCAST:.*]] = fir.convert %[[VAL_11]] : (index) -> i32
-! CHECK: %[[IVLOAD:.*]] = fir.load %[[PRIV_J_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[IVINC:.*]] = arith.addi %[[IVLOAD]], %[[STEPCAST]] overflow<nsw> :
-! CHECK: fir.result %[[IVINC]] : i32
! CHECK: }
+! CHECK: %[[LB:.*]] = fir.convert %[[VAL_8]] : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %[[VAL_10]] : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %[[VAL_11]] : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[VAL_12:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
! CHECK: fir.store %[[VAL_12]] to %[[PRIV_J_DECL]]#0 : !fir.ref<i32>
! CHECK: omp.yield
! CHECK: }
diff --git a/flang/test/Lower/OpenMP/sections-predetermined-private.f90 b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
index 3313feb3d7021..aaf7c125e1b95 100644
--- a/flang/test/Lower/OpenMP/sections-predetermined-private.f90
+++ b/flang/test/Lower/OpenMP/sections-predetermined-private.f90
@@ -15,15 +15,41 @@
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: omp.sections {
! CHECK: omp.section {
-! CHECK: %[[VAL_11:.*]] = fir.do_loop %[[VAL_12:.*]] = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}} -> (i32) {
+! CHECK: fir.do_loop %[[VAL_12:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CHECK: %[[VAL_IV:.*]] = fir.convert %[[VAL_12]] : (index) -> i32
+! CHECK: fir.store %[[VAL_IV]] to %[[VAL_4]]#0 : !fir.ref<i32>
! CHECK: }
-! CHECK: fir.store %[[VAL_11]] to %[[VAL_4]]#0 : !fir.ref<i32>
+! CHECK: %[[LB1:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB1:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[ST1:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C01:.*]] = arith.constant 0 : i32
+! CHECK: %[[D1:.*]] = arith.subi %[[UB1]], %[[LB1]] overflow<nsw> : i32
+! CHECK: %[[A1:.*]] = arith.addi %[[D1]], %[[ST1]] overflow<nsw> : i32
+! CHECK: %[[TR1:.*]] = arith.divsi %[[A1]], %[[ST1]] : i32
+! CHECK: %[[CMP1:.*]] = arith.cmpi slt, %[[TR1]], %[[C01]] : i32
+! CHECK: %[[SEL1:.*]] = arith.select %[[CMP1]], %[[C01]], %[[TR1]] : i32
+! CHECK: %[[M1:.*]] = arith.muli %[[SEL1]], %[[ST1]] overflow<nsw> : i32
+! CHECK: %[[LAST1:.*]] = arith.addi %[[LB1]], %[[M1]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST1]] to %[[VAL_4]]#0 : !fir.ref<i32>
! CHECK: omp.terminator
! CHECK: }
! CHECK: omp.section {
-! CHECK: %[[VAL_25:.*]] = fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
+! CHECK: fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CHECK: %[[VAL_IV2:.*]] = fir.convert %[[VAL_26]] : (index) -> i32
+! CHECK: fir.store %[[VAL_IV2]] to %[[VAL_4]]#0 : !fir.ref<i32>
! CHECK: }
-! CHECK: fir.store %[[VAL_25]] to %[[VAL_4]]#0 : !fir.ref<i32>
+! CHECK: %[[LB2:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB2:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[ST2:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C02:.*]] = arith.constant 0 : i32
+! CHECK: %[[D2:.*]] = arith.subi %[[UB2]], %[[LB2]] overflow<nsw> : i32
+! CHECK: %[[A2:.*]] = arith.addi %[[D2]], %[[ST2]] overflow<nsw> : i32
+! CHECK: %[[TR2:.*]] = arith.divsi %[[A2]], %[[ST2]] : i32
+! CHECK: %[[CMP2:.*]] = arith.cmpi slt, %[[TR2]], %[[C02]] : i32
+! CHECK: %[[SEL2:.*]] = arith.select %[[CMP2]], %[[C02]], %[[TR2]] : i32
+! CHECK: %[[M2:.*]] = arith.muli %[[SEL2]], %[[ST2]] overflow<nsw> : i32
+! CHECK: %[[LAST2:.*]] = arith.addi %[[LB2]], %[[M2]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST2]] to %[[VAL_4]]#0 : !fir.ref<i32>
! CHECK: omp.terminator
! CHECK: }
! CHECK: omp.terminator
diff --git a/flang/test/Lower/OpenMP/shared-loop.f90 b/flang/test/Lower/OpenMP/shared-loop.f90
index eb277efb2d3de..42aefc932e54f 100644
--- a/flang/test/Lower/OpenMP/shared-loop.f90
+++ b/flang/test/Lower/OpenMP/shared-loop.f90
@@ -9,14 +9,23 @@
! CHECK: omp.parallel {
! CHECK: omp.sections {
! CHECK: omp.section {
-! CHECK: %[[RES:.*]] = fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[ARG1:.*]] =
-! CHECK: fir.store %[[ARG1]] to %[[DECL_I]]#0
+! CHECK: fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CHECK: %[[IV:.*]] = fir.convert %[[ARG0]] : (index) -> i32
+! CHECK: fir.store %[[IV]] to %[[DECL_I]]#0
! CHECK: hlfir.assign
-! CHECK: %[[LOAD_I:.*]] = fir.load %[[DECL_I]]#0
-! CHECK: %[[RES_I:.*]] = arith.addi %[[LOAD_I]], %{{.*}}
-! CHECK: fir.result %[[RES_I]]
! CHECK: }
-! CHECK: fir.store %[[RES]] to %[[DECL_I]]#0
+! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADDT:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADDT]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[DECL_I]]#0
! CHECK: omp.terminator
! CHECK: }
! CHECK: omp.terminator
@@ -47,15 +56,24 @@ subroutine omploop
! CHECK: %[[DECL_PRIV_I:.*]]:2 = hlfir.declare %[[ALLOC_PRIV_I]]
! CHECK: omp.sections {
! CHECK: omp.section {
-! CHECK: %[[RES:.*]] = fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[ARG1:.*]] =
-! CHECK-NOT: fir.store %[[ARG1]] to %[[DECL_I]]#1
-! CHECK: fir.store %[[ARG1]] to %[[DECL_PRIV_I]]#0
+! CHECK: fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CHECK: %[[IV:.*]] = fir.convert %[[ARG0]] : (index) -> i32
+! CHECK-NOT: fir.store %{{.*}} to %[[DECL_I]]#1
+! CHECK: fir.store %[[IV]] to %[[DECL_PRIV_I]]#0
! CHECK: hlfir.assign
-! CHECK: %[[LOAD_I:.*]] = fir.load %[[DECL_PRIV_I]]#0
-! CHECK: %[[RES_I:.*]] = arith.addi %[[LOAD_I]], %{{.*}}
-! CHECK: fir.result %[[RES_I]]
! CHECK: }
-! CHECK: fir.store %[[RES]] to %[[DECL_PRIV_I]]#0
+! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADDT:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADDT]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[DECL_PRIV_I]]#0
! CHECK: omp.terminator
! CHECK: }
! CHECK: omp.terminator
@@ -87,15 +105,24 @@ subroutine omploop2
! CHECK: %[[DECL_PRIV_I:.*]]:2 = hlfir.declare %[[ALLOC_PRIV_I]]
! CHECK: omp.sections {
! CHECK: omp.section {
-! CHECK: %[[RES:.*]] = fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%[[ARG1:.*]] =
-! CHECK-NOT: fir.store %[[ARG1]] to %[[DECL_I]]#1
-! CHECK: fir.store %[[ARG1]] to %[[DECL_PRIV_I]]#0
+! CHECK: fir.do_loop %[[ARG0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+! CHECK: %[[IV:.*]] = fir.convert %[[ARG0]] : (index) -> i32
+! CHECK-NOT: fir.store %{{.*}} to %[[DECL_I]]#1
+! CHECK: fir.store %[[IV]] to %[[DECL_PRIV_I]]#0
! CHECK: hlfir.assign
-! CHECK: %[[LOAD_I:.*]] = fir.load %[[DECL_PRIV_I]]#0
-! CHECK: %[[RES_I:.*]] = arith.addi %[[LOAD_I]], %{{.*}}
-! CHECK: fir.result %[[RES_I]]
! CHECK: }
-! CHECK: fir.store %[[RES]] to %[[DECL_PRIV_I]]#0
+! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADDT:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADDT]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[DECL_PRIV_I]]#0
! CHECK: omp.terminator
! CHECK: }
! CHECK: omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
index 630bd46863c0e..58b8f7a6e3c47 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
@@ -201,8 +201,8 @@ program reduce15
! CHECK: %[[VAL_38:.*]] = arith.constant 10 : i32
! CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (i32) -> index
! CHECK: %[[VAL_40:.*]] = arith.constant 1 : index
-! CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_37]] : (index) -> i32
-! CHECK: %[[VAL_42:.*]] = fir.do_loop %[[VAL_43:.*]] = %[[VAL_37]] to %[[VAL_39]] step %[[VAL_40]] iter_args(%[[VAL_44:.*]] = %[[VAL_41]]) -> (i32) {
+! CHECK: fir.do_loop %[[VAL_43:.*]] = %[[VAL_37]] to %[[VAL_39]] step %[[VAL_40]] {
+! CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_43]] : (index) -> i32
! CHECK: fir.store %[[VAL_44]] to %[[VAL_3]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_45:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_46:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
@@ -210,12 +210,19 @@ program reduce15
! CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (i32) -> i64
! CHECK: %[[VAL_49:.*]] = hlfir.designate %[[VAL_46]] (%[[VAL_48]]) : (!fir.box<!fir.heap<!fir.array<?xi32>>>, i64) -> !fir.ref<i32>
! CHECK: hlfir.assign %[[VAL_45]] to %[[VAL_49]] : i32, !fir.ref<i32>
-! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_40]] : (index) -> i32
-! CHECK: %[[VAL_52:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
-! CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_52]], %[[VAL_51]] overflow<nsw> : i32
-! CHECK: fir.result %[[VAL_53]] : i32
! CHECK: }
-! CHECK: fir.store %[[VAL_54:.*]] to %[[VAL_3]]#0 : !fir.ref<i32>
+! CHECK: %[[VAL_LB:.*]] = fir.convert %[[VAL_37]] : (index) -> i32
+! CHECK: %[[VAL_UB:.*]] = fir.convert %[[VAL_39]] : (index) -> i32
+! CHECK: %[[VAL_ST:.*]] = fir.convert %[[VAL_40]] : (index) -> i32
+! CHECK: %[[VAL_C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[VAL_DIFF:.*]] = arith.subi %[[VAL_UB]], %[[VAL_LB]] overflow<nsw> : i32
+! CHECK: %[[VAL_ADD:.*]] = arith.addi %[[VAL_DIFF]], %[[VAL_ST]] overflow<nsw> : i32
+! CHECK: %[[VAL_TRIP:.*]] = arith.divsi %[[VAL_ADD]], %[[VAL_ST]] : i32
+! CHECK: %[[VAL_CMP:.*]] = arith.cmpi slt, %[[VAL_TRIP]], %[[VAL_C0]] : i32
+! CHECK: %[[VAL_SEL:.*]] = arith.select %[[VAL_CMP]], %[[VAL_C0]], %[[VAL_TRIP]] : i32
+! CHECK: %[[VAL_MUL:.*]] = arith.muli %[[VAL_SEL]], %[[VAL_ST]] overflow<nsw> : i32
+! CHECK: %[[VAL_54:.*]] = arith.addi %[[VAL_LB]], %[[VAL_MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[VAL_54]] to %[[VAL_3]]#0 : !fir.ref<i32>
! CHECK: omp.parallel {
! CHECK: %[[VAL_57:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_58:.*]] = arith.constant 10 : i32
diff --git a/flang/test/Lower/OpenMP/wsloop-variable.f90 b/flang/test/Lower/OpenMP/wsloop-variable.f90
index 60d970f3f0bac..02e47f7aa212e 100644
--- a/flang/test/Lower/OpenMP/wsloop-variable.f90
+++ b/flang/test/Lower/OpenMP/wsloop-variable.f90
@@ -138,8 +138,8 @@ subroutine wsloop_variable_sub
!CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (i32) -> index
!CHECK: %[[VAL_33:.*]] = fir.load %[[VAL_15]]#0 : !fir.ref<i32>
!CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_33]] : (i32) -> index
-!CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_30]] : (index) -> i64
-!CHECK: %[[VAL_36:.*]] = fir.do_loop %[[VAL_37:.*]] = %[[VAL_30]] to %[[VAL_32]] step %[[VAL_34]] iter_args(%[[VAL_38:.*]] = %[[VAL_35]]) -> (i64) {
+!CHECK: fir.do_loop %[[VAL_37:.*]] = %[[VAL_30]] to %[[VAL_32]] step %[[VAL_34]] {
+!CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (index) -> i64
!CHECK: fir.store %[[VAL_38]] to %[[VAL_17]]#0 : !fir.ref<i64>
!CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i16>
!CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_39]] : (i16) -> i64
@@ -147,12 +147,19 @@ subroutine wsloop_variable_sub
!CHECK: %[[VAL_42:.*]] = arith.addi %[[VAL_40]], %[[VAL_41]] : i64
!CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_42]] : (i64) -> f32
!CHECK: hlfir.assign %[[VAL_43]] to %[[VAL_21]]#0 : f32, !fir.ref<f32>
-!CHECK: %[[VAL_45:.*]] = fir.convert %[[VAL_34]] : (index) -> i64
-!CHECK: %[[VAL_46:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref<i64>
-!CHECK: %[[VAL_47:.*]] = arith.addi %[[VAL_46]], %[[VAL_45]] overflow<nsw> : i64
-!CHECK: fir.result %[[VAL_47]] : i64
!CHECK: }
-!CHECK: fir.store %[[VAL_48:.*]] to %[[VAL_17]]#0 : !fir.ref<i64>
+!CHECK: %[[VAL_LB:.*]] = fir.convert %[[VAL_30]] : (index) -> i64
+!CHECK: %[[VAL_UB:.*]] = fir.convert %[[VAL_32]] : (index) -> i64
+!CHECK: %[[VAL_ST:.*]] = fir.convert %[[VAL_34]] : (index) -> i64
+!CHECK: %[[VAL_C0:.*]] = arith.constant 0 : i64
+!CHECK: %[[VAL_DIFF:.*]] = arith.subi %[[VAL_UB]], %[[VAL_LB]] overflow<nsw> : i64
+!CHECK: %[[VAL_ADD:.*]] = arith.addi %[[VAL_DIFF]], %[[VAL_ST]] overflow<nsw> : i64
+!CHECK: %[[VAL_TRIP:.*]] = arith.divsi %[[VAL_ADD]], %[[VAL_ST]] : i64
+!CHECK: %[[VAL_CMP:.*]] = arith.cmpi slt, %[[VAL_TRIP]], %[[VAL_C0]] : i64
+!CHECK: %[[VAL_SEL:.*]] = arith.select %[[VAL_CMP]], %[[VAL_C0]], %[[VAL_TRIP]] : i64
+!CHECK: %[[VAL_MUL:.*]] = arith.muli %[[VAL_SEL]], %[[VAL_ST]] overflow<nsw> : i64
+!CHECK: %[[VAL_48:.*]] = arith.addi %[[VAL_LB]], %[[VAL_MUL]] overflow<nsw> : i64
+!CHECK: fir.store %[[VAL_48]] to %[[VAL_17]]#0 : !fir.ref<i64>
!CHECK: omp.yield
!CHECK: }
!CHECK: }
diff --git a/flang/test/Lower/allocatable-polymorphic.f90 b/flang/test/Lower/allocatable-polymorphic.f90
index 9e4f04b45516e..8a0cb1bbc7033 100644
--- a/flang/test/Lower/allocatable-polymorphic.f90
+++ b/flang/test/Lower/allocatable-polymorphic.f90
@@ -332,12 +332,12 @@ subroutine test_allocatable()
! CHECK: %[[C2_REBOX:.*]] = fir.rebox %[[C2_LOAD2]] : (!fir.class<!fir.heap<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>) -> !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "proc2"(%[[C2_REBOX]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) (%[[C2_REBOX]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
-! CHECK-LABEL: %{{.*}} = fir.do_loop
+! CHECK-LABEL: fir.do_loop
! CHECK: %[[C3_LOAD:.*]] = fir.load %[[C3_DECL]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE_C3:.*]] = hlfir.designate %[[C3_LOAD]] (%{{.*}}) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>, i64) -> !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "proc2"(%[[DESIGNATE_C3]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) (%[[DESIGNATE_C3]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
-! CHECK-LABEL: %{{.*}} = fir.do_loop
+! CHECK-LABEL: fir.do_loop
! CHECK: %[[C4_LOAD:.*]] = fir.load %[[C4_DECL]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE_C4:.*]] = hlfir.designate %[[C4_LOAD]] (%{{.*}}) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>, i64) -> !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "proc2"(%[[DESIGNATE_C4]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) (%[[DESIGNATE_C4]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
diff --git a/flang/test/Lower/dispatch.f90 b/flang/test/Lower/dispatch.f90
index 7692bd31d4533..63b16aeadb69e 100644
--- a/flang/test/Lower/dispatch.f90
+++ b/flang/test/Lower/dispatch.f90
@@ -250,11 +250,11 @@ subroutine check_dispatch_dynamic_array(p, t)
! CHECK-SAME: %[[ARG1:.*]]: !fir.box<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>> {fir.bindc_name = "t"}) {
! CHECK: %[[ARG0_DECL:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {uniq_name = "_QMcall_dispatchFcheck_dispatch_dynamic_arrayEp"} : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.dscope) -> (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>)
! CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {uniq_name = "_QMcall_dispatchFcheck_dispatch_dynamic_arrayEt"} : (!fir.box<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.box<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>)
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[ARG0_DECL]]#0 (%{{.*}}) : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, i64) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "tbp_pass"(%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) (%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[ARG1_DECL]]#0 (%{{.*}}) : (!fir.box<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, i64) -> !fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: %[[EMBOX:.*]] = fir.embox %[[DESIGNATE]] : (!fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) -> !fir.box<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: %[[CONV:.*]] = fir.convert %[[EMBOX]] : (!fir.box<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
@@ -278,12 +278,12 @@ subroutine check_dispatch_allocatable_array(p, t)
! CHECK-SAME: %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>> {fir.bindc_name = "t"}) {
! CHECK: %[[ARG0_DECL:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMcall_dispatchFcheck_dispatch_allocatable_arrayEp"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.dscope) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>)
! CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMcall_dispatchFcheck_dispatch_allocatable_arrayEt"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>)
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[LOAD_ARG0:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[LOAD_ARG0]] (%{{.*}}) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>, i64) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "tbp_pass"(%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) (%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[LOAD_ARG1:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[LOAD_ARG1]] (%{{.*}}) : (!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>, i64) -> !fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: %[[EMBOX:.*]] = fir.embox %[[DESIGNATE]] : (!fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) -> !fir.box<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
@@ -309,12 +309,12 @@ subroutine check_dispatch_pointer_array(p, t)
! CHECK: %[[ARG0_DECL:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMcall_dispatchFcheck_dispatch_pointer_arrayEp"} : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.dscope) -> (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>)
! CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMcall_dispatchFcheck_dispatch_pointer_arrayEt"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>)
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[LOAD_ARG0:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[LOAD_ARG0]] (%{{.*}}) : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>, i64) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "tbp_pass"(%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) (%[[DESIGNATE]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[LOAD_ARG1:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>>
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[LOAD_ARG1]] (%{{.*}}) : (!fir.box<!fir.ptr<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>>, i64) -> !fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: %[[EMBOX:.*]] = fir.embox %[[DESIGNATE]] : (!fir.ref<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) -> !fir.box<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
@@ -337,7 +337,7 @@ subroutine check_dispatch_dynamic_array_copy(p, o)
! CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {uniq_name = "_QMcall_dispatchFcheck_dispatch_dynamic_array_copyEo"} : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.dscope) -> (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>)
! CHECK: %[[ARG0_DECL:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {uniq_name = "_QMcall_dispatchFcheck_dispatch_dynamic_array_copyEp"} : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.dscope) -> (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, !fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>)
-! CHECK: %{{.*}} = fir.do_loop {{.*}} {
+! CHECK: fir.do_loop {{.*}} {
! CHECK: %[[DESIGNATE0:.*]] = hlfir.designate %[[ARG0_DECL]]#0 (%{{.*}}) : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, i64) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: %[[DESIGNATE1:.*]] = hlfir.designate %[[ARG1_DECL]]#0 (%{{.*}}) : (!fir.class<!fir.array<?x!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>>, i64) -> !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>
! CHECK: fir.dispatch "pass_with_class_arg"(%[[DESIGNATE0]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) (%[[DESIGNATE0]], %[[DESIGNATE1]] : !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>, !fir.class<!fir.type<_QMcall_dispatchTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
diff --git a/flang/test/Lower/do_concurrent_clean_nested_loops.f90 b/flang/test/Lower/do_concurrent_clean_nested_loops.f90
deleted file mode 100644
index decc6724a2c1b..0000000000000
--- a/flang/test/Lower/do_concurrent_clean_nested_loops.f90
+++ /dev/null
@@ -1,215 +0,0 @@
-! Test -fdo-concurrent-clean-nested-loops: a plain DO loop nested in a DO
-! CONCURRENT body is lowered without the secondary-induction iter_arg (the DO
-! variable is recomputed from the induction variable), while the Fortran
-! post-loop value of the DO variable is still materialized after the loop. A
-! plain DO loop that is not nested in a DO CONCURRENT body is unaffected.
-
-! RUN: bbc -emit-hlfir -o - %s | FileCheck %s --check-prefixes=CHECK,DEFAULT
-! RUN: bbc -emit-hlfir -fdo-concurrent-clean-nested-loops -o - %s | FileCheck %s --check-prefixes=CHECK,CLEAN
-
-subroutine nested(a, n)
- implicit none
- integer :: n, i, j
- integer :: a(n)
- do concurrent (i=1:n)
- do j = 1, 3
- end do
- a(i) = j
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPnested
-! CHECK: %[[J_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnestedEj"}
-! CHECK: fir.do_concurrent
-! CHECK: fir.do_concurrent.loop
-
-! Default lowering: nested loop carries the DO variable as an iter_arg and the
-! post-loop value is the loop result.
-! DEFAULT: %[[RES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[RES]] to %[[J_DECL]]#0 : !fir.ref<i32>
-
-! Clean lowering: nested loop has no iter_arg and the body recomputes the DO
-! variable from the induction variable; the post-loop value is computed as
-! lb + tripCount*step after the loop and stored to the DO variable.
-! CLEAN: fir.do_loop %{{.*}} = %[[LB:[^ ]+]] to %[[UB:[^ ]+]] step %[[ST:[^ ]+]] {
-! CLEAN-NOT: iter_args
-! CLEAN: %[[IV:.*]] = fir.convert %{{.*}} : (index) -> i32
-! CLEAN: fir.store %[[IV]] to %[[J_DECL]]#0 : !fir.ref<i32>
-! CLEAN: }
-! CLEAN: %[[LBI:.*]] = fir.convert %[[LB]] : (index) -> i32
-! CLEAN: %[[UBI:.*]] = fir.convert %[[UB]] : (index) -> i32
-! CLEAN: %[[STI:.*]] = fir.convert %[[ST]] : (index) -> i32
-! CLEAN: %[[C0:.*]] = arith.constant 0 : i32
-! CLEAN: %[[DIFF:.*]] = arith.subi %[[UBI]], %[[LBI]] overflow<nsw> : i32
-! CLEAN: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STI]] overflow<nsw> : i32
-! CLEAN: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STI]] : i32
-! CLEAN: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
-! CLEAN: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
-! CLEAN: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STI]] overflow<nsw> : i32
-! CLEAN: %[[LAST:.*]] = arith.addi %[[LBI]], %[[MUL]] overflow<nsw> : i32
-! CLEAN: fir.store %[[LAST]] to %[[J_DECL]]#0 : !fir.ref<i32>
-
-! Non-unit lower bound and step: the post-loop value must still be lb +
-! tripCount*step (here 2 + 4*2 = 10), not a hard-coded lb=1/step=1 form.
-subroutine nested_stride(a, n)
- implicit none
- integer :: n, i, j
- integer :: a(n)
- do concurrent (i=1:n)
- do j = 2, 8, 2
- end do
- a(i) = j
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPnested_stride
-! CHECK: %[[SJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_strideEj"}
-! DEFAULT: %[[SRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[SRES]] to %[[SJ_DECL]]#0 : !fir.ref<i32>
-! CLEAN: fir.do_loop %{{.*}} = %[[SLB:[^ ]+]] to %[[SUB:[^ ]+]] step %[[SST:[^ ]+]] {
-! CLEAN-NOT: iter_args
-! CLEAN: }
-! CLEAN: %[[SLBI:.*]] = fir.convert %[[SLB]] : (index) -> i32
-! CLEAN: %[[SUBI:.*]] = fir.convert %[[SUB]] : (index) -> i32
-! CLEAN: %[[SSTI:.*]] = fir.convert %[[SST]] : (index) -> i32
-! CLEAN: %[[SC0:.*]] = arith.constant 0 : i32
-! CLEAN: %[[SDIFF:.*]] = arith.subi %[[SUBI]], %[[SLBI]] overflow<nsw> : i32
-! CLEAN: %[[SADD:.*]] = arith.addi %[[SDIFF]], %[[SSTI]] overflow<nsw> : i32
-! CLEAN: %[[STRIP:.*]] = arith.divsi %[[SADD]], %[[SSTI]] : i32
-! CLEAN: %[[SCMP:.*]] = arith.cmpi slt, %[[STRIP]], %[[SC0]] : i32
-! CLEAN: %[[SSEL:.*]] = arith.select %[[SCMP]], %[[SC0]], %[[STRIP]] : i32
-! CLEAN: %[[SMUL:.*]] = arith.muli %[[SSEL]], %[[SSTI]] overflow<nsw> : i32
-! CLEAN: %[[SLAST:.*]] = arith.addi %[[SLBI]], %[[SMUL]] overflow<nsw> : i32
-! CLEAN: fir.store %[[SLAST]] to %[[SJ_DECL]]#0 : !fir.ref<i32>
-
-! Descending loop (step < 0): the same lb + tripCount*step formula must hold
-! (here 8 + 4*(-2) = 0).
-subroutine nested_stride_neg(a, n)
- implicit none
- integer :: n, i, j
- integer :: a(n)
- do concurrent (i=1:n)
- do j = 8, 2, -2
- end do
- a(i) = j
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPnested_stride_neg
-! CHECK: %[[NJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_stride_negEj"}
-! DEFAULT: %[[NRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[NRES]] to %[[NJ_DECL]]#0 : !fir.ref<i32>
-! CLEAN: fir.do_loop %{{.*}} = %[[NLB:[^ ]+]] to %[[NUB:[^ ]+]] step %[[NST:[^ ]+]] {
-! CLEAN-NOT: iter_args
-! CLEAN: }
-! CLEAN: %[[NLBI:.*]] = fir.convert %[[NLB]] : (index) -> i32
-! CLEAN: %[[NUBI:.*]] = fir.convert %[[NUB]] : (index) -> i32
-! CLEAN: %[[NSTI:.*]] = fir.convert %[[NST]] : (index) -> i32
-! CLEAN: %[[NC0:.*]] = arith.constant 0 : i32
-! CLEAN: %[[NDIFF:.*]] = arith.subi %[[NUBI]], %[[NLBI]] overflow<nsw> : i32
-! CLEAN: %[[NADD:.*]] = arith.addi %[[NDIFF]], %[[NSTI]] overflow<nsw> : i32
-! CLEAN: %[[NTRIP:.*]] = arith.divsi %[[NADD]], %[[NSTI]] : i32
-! CLEAN: %[[NCMP:.*]] = arith.cmpi slt, %[[NTRIP]], %[[NC0]] : i32
-! CLEAN: %[[NSEL:.*]] = arith.select %[[NCMP]], %[[NC0]], %[[NTRIP]] : i32
-! CLEAN: %[[NMUL:.*]] = arith.muli %[[NSEL]], %[[NSTI]] overflow<nsw> : i32
-! CLEAN: %[[NLAST:.*]] = arith.addi %[[NLBI]], %[[NMUL]] overflow<nsw> : i32
-! CLEAN: fir.store %[[NLAST]] to %[[NJ_DECL]]#0 : !fir.ref<i32>
-
-! A DO CONCURRENT with multiple induction variables is lowered as a single
-! fir.do_concurrent.loop carrying all the IVs (unaffected by the option); only
-! the nested plain DO loop is cleaned.
-subroutine multi_iv(a, n, m)
- implicit none
- integer :: n, m, i, j, k
- integer :: a(n, m)
- do concurrent (i=1:n, j=1:m)
- do k = 1, 3
- a(i, j) = a(i, j) + k
- end do
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPmulti_iv
-! CHECK: %[[MK_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFmulti_ivEk"}
-! CHECK: fir.do_concurrent.loop (%{{[^)]*}}, %{{[^)]*}}) = (%{{[^)]*}}, %{{[^)]*}}) to (%{{[^)]*}}, %{{[^)]*}}) step (%{{[^)]*}}, %{{[^)]*}}) {
-! DEFAULT: %[[MRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[MRES]] to %[[MK_DECL]]#0 : !fir.ref<i32>
-! CLEAN: fir.do_loop %{{.*}} = %[[MLB:[^ ]+]] to %[[MUB:[^ ]+]] step %[[MST:[^ ]+]] {
-! CLEAN-NOT: iter_args
-! CLEAN: }
-! CLEAN: %[[MLBI:.*]] = fir.convert %[[MLB]] : (index) -> i32
-! CLEAN: %[[MUBI:.*]] = fir.convert %[[MUB]] : (index) -> i32
-! CLEAN: %[[MSTI:.*]] = fir.convert %[[MST]] : (index) -> i32
-! CLEAN: %[[MC0:.*]] = arith.constant 0 : i32
-! CLEAN: %[[MDIFF:.*]] = arith.subi %[[MUBI]], %[[MLBI]] overflow<nsw> : i32
-! CLEAN: %[[MADD:.*]] = arith.addi %[[MDIFF]], %[[MSTI]] overflow<nsw> : i32
-! CLEAN: %[[MTRIP:.*]] = arith.divsi %[[MADD]], %[[MSTI]] : i32
-! CLEAN: %[[MCMP:.*]] = arith.cmpi slt, %[[MTRIP]], %[[MC0]] : i32
-! CLEAN: %[[MSEL:.*]] = arith.select %[[MCMP]], %[[MC0]], %[[MTRIP]] : i32
-! CLEAN: %[[MMUL:.*]] = arith.muli %[[MSEL]], %[[MSTI]] overflow<nsw> : i32
-! CLEAN: %[[MLAST:.*]] = arith.addi %[[MLBI]], %[[MMUL]] overflow<nsw> : i32
-! CLEAN: fir.store %[[MLAST]] to %[[MK_DECL]]#0 : !fir.ref<i32>
-
-! A DO CONCURRENT nested inside one of the cleaned plain DO loops is still
-! lowered as its own fir.do_concurrent.loop; the enclosing plain DO stays clean
-! and its post-loop value is materialized.
-subroutine dc_in_clean_loop(a, n, m)
- implicit none
- integer :: n, m, i, j, k
- integer :: a(n)
- do concurrent (i=1:n)
- do j = 1, 3
- do concurrent (k=1:m)
- a(i) = a(i) + j*k
- end do
- end do
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPdc_in_clean_loop
-! CHECK: %[[DJ_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdc_in_clean_loopEj"}
-! CHECK: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
-! DEFAULT: %[[DJRES:.*]] = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.store %[[DJRES]] to %[[DJ_DECL]]#0 : !fir.ref<i32>
-! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
-! CLEAN: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
-! CLEAN: %{{.*}} = arith.divsi %{{.*}}, %{{.*}} : i32
-! CLEAN: fir.store %{{.*}} to %[[DJ_DECL]]#0 : !fir.ref<i32>
-
-! Plain DO loops inside a DO CONCURRENT that is itself nested in the body are
-! cleaned at any depth.
-subroutine loop_in_nested_dc(a, n, m, p)
- implicit none
- integer :: n, m, p, i, j, k, l
- integer :: a(n)
- do concurrent (i=1:n)
- do j = 1, 3
- do concurrent (k=1:m)
- do l = 1, 4
- a(i) = a(i) + j*k*l
- end do
- end do
- end do
- end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPloop_in_nested_dc
-! CHECK: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
-! DEFAULT: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! DEFAULT: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
-! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
-! CLEAN: fir.do_concurrent.loop (%{{[^)]*}}) = (%{{[^)]*}}) to (%{{[^)]*}}) step (%{{[^)]*}}) {
-! CLEAN: fir.do_loop %{{.*}} = %{{[^ ]+}} to %{{[^ ]+}} step %{{[^ ]+}} {
-
-! A plain DO loop not nested in a DO CONCURRENT body keeps its iter_arg even
-! when the option is enabled.
-subroutine not_nested(x)
- implicit none
- integer :: x, j
- do j = 1, 3
- end do
- x = j
-end subroutine
-
-! CHECK-LABEL: func.func @_QPnot_nested
-! CLEAN: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} iter_args(%{{.*}} = %{{.*}}) -> (i32) {
diff --git a/flang/test/Lower/do_concurrent_loop_in_nested_block.f90 b/flang/test/Lower/do_concurrent_loop_in_nested_block.f90
index 79bde5eed7817..f498c01f3d140 100644
--- a/flang/test/Lower/do_concurrent_loop_in_nested_block.f90
+++ b/flang/test/Lower/do_concurrent_loop_in_nested_block.f90
@@ -17,8 +17,9 @@ subroutine loop_in_nested_block
! CHECK: fir.do_concurrent {
! CHECK: fir.do_concurrent.loop {{.*}} local(@{{.*}} %[[OUTER_J_DECL]]#0 -> %[[LOCAL_J_ARG:.*]] : !fir.ref<i32>) {
! CHECK: %[[LOCAL_J_DECL:.*]]:2 = hlfir.declare %[[LOCAL_J_ARG]]
-! CHECK: fir.do_loop {{.*}} iter_args(%[[NESTED_LOOP_ARG:.*]] = {{.*}}) {
-! CHECK: fir.store %[[NESTED_LOOP_ARG]] to %[[LOCAL_J_DECL]]#0
+! CHECK: fir.do_loop %[[NESTED_IV:.*]] = {{.*}} to {{.*}} step {{.*}} {
+! CHECK: %[[NESTED_J:.*]] = fir.convert %[[NESTED_IV]] : (index) -> i32
+! CHECK: fir.store %[[NESTED_J]] to %[[LOCAL_J_DECL]]#0
! CHECK: }
! CHECK: }
! CHECK: }
diff --git a/flang/test/Lower/do_loop.f90 b/flang/test/Lower/do_loop.f90
index b98a0e7108113..91be10a7d076d 100644
--- a/flang/test/Lower/do_loop.f90
+++ b/flang/test/Lower/do_loop.f90
@@ -2,8 +2,9 @@
! RUN: %flang_fc1 -emit-hlfir -fwrapv -o - %s | FileCheck %s --check-prefix=NO-NSW
! Simple tests for structured ordered loops with loop-control.
-! Tests the structure of the loop, storage to index variable and return and
-! storage of the final value of the index variable.
+! The DO variable is recomputed from the induction variable inside the loop
+! body (no secondary-induction iter_arg), and its Fortran post-loop value is
+! materialized after the loop.
! NO-NSW-NOT: overflow<nsw>
@@ -19,19 +20,24 @@ subroutine simple_loop
! CHECK: %[[C5:.*]] = arith.constant 5 : i32
! CHECK: %[[C5_CVT:.*]] = fir.convert %[[C5]] : (i32) -> index
! CHECK: %[[C1_STEP:.*]] = arith.constant 1 : index
- ! CHECK: %[[LB:.*]] = fir.convert %[[C1_CVT]] : (index) -> i32
- ! CHECK: %[[LI_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
- ! CHECK-SAME: %[[C1_CVT]] to %[[C5_CVT]] step %[[C1_STEP]]
- ! CHECK-SAME: iter_args(%[[IV:.*]] = %[[LB]]) -> (i32) {
+ ! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[C1_CVT]] to %[[C5_CVT]] step %[[C1_STEP]] {
do i=1,5
+ ! CHECK: %[[IV:.*]] = fir.convert %[[LI]] : (index) -> i32
! CHECK: fir.store %[[IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[STEPCAST:.*]] = fir.convert %[[C1_STEP]] : (index) -> i32
- ! CHECK: %[[IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[IVINC:.*]] = arith.addi %[[IVLOAD]], %[[STEPCAST]] overflow<nsw> : i32
- ! CHECK: fir.result %[[IVINC]] : i32
! CHECK: }
end do
- ! CHECK: fir.store %[[LI_RES]] to %[[I_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: %[[LB:.*]] = fir.convert %[[C1_CVT]] : (index) -> i32
+ ! CHECK: %[[UB:.*]] = fir.convert %[[C5_CVT]] : (index) -> i32
+ ! CHECK: %[[STEP:.*]] = fir.convert %[[C1_STEP]] : (index) -> i32
+ ! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+ ! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+ ! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+ ! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+ ! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[LAST]] to %[[I_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[I:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[I]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
print *, i
@@ -56,22 +62,18 @@ subroutine nested_loop
! CHECK: %[[E_I:.*]] = arith.constant 5 : i32
! CHECK: %[[E_I_CVT:.*]] = fir.convert %[[E_I]] : (i32) -> index
! CHECK: %[[ST_I:.*]] = arith.constant 1 : index
- ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_I_CVT]] : (index) -> i32
- ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
- ! CHECK-SAME: %[[S_I_CVT]] to %[[E_I_CVT]] step %[[ST_I]]
- ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) {
+ ! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[S_I_CVT]] to %[[E_I_CVT]] step %[[ST_I]] {
do i=1,5
+ ! CHECK: %[[I_IV:.*]] = fir.convert %[[LI]] : (index) -> i32
! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[S_J:.*]] = arith.constant 1 : i32
! CHECK: %[[S_J_CVT:.*]] = fir.convert %[[S_J]] : (i32) -> index
! CHECK: %[[E_J:.*]] = arith.constant 5 : i32
! CHECK: %[[E_J_CVT:.*]] = fir.convert %[[E_J]] : (i32) -> index
! CHECK: %[[ST_J:.*]] = arith.constant 1 : index
- ! CHECK: %[[J_LB:.*]] = fir.convert %[[S_J_CVT]] : (index) -> i32
- ! CHECK: %[[J_RES:.*]] = fir.do_loop %[[LJ:[^ ]*]] =
- ! CHECK-SAME: %[[S_J_CVT]] to %[[E_J_CVT]] step %[[ST_J]]
- ! CHECK-SAME: iter_args(%[[J_IV:.*]] = %[[J_LB]]) -> (i32) {
+ ! CHECK: fir.do_loop %[[LJ:[^ ]*]] = %[[S_J_CVT]] to %[[E_J_CVT]] step %[[ST_J]] {
do j=1,5
+ ! CHECK: %[[J_IV:.*]] = fir.convert %[[LJ]] : (index) -> i32
! CHECK: fir.store %[[J_IV]] to %[[J_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[ASUM:.*]] = fir.load %[[ASUM_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[I:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
@@ -83,20 +85,34 @@ subroutine nested_loop
! CHECK: %[[ASUM_NEW:.*]] = arith.addi %[[ASUM]], %[[ARR_VAL]] : i32
! CHECK: hlfir.assign %[[ASUM_NEW]] to %[[ASUM_DECL]]#0 : i32, !fir.ref<i32>
asum = asum + arr(i,j)
- ! CHECK: %[[J_STEPCAST:.*]] = fir.convert %[[ST_J]] : (index) -> i32
- ! CHECK: %[[J_IVLOAD:.*]] = fir.load %[[J_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[J_IVINC:.*]] = arith.addi %[[J_IVLOAD]], %[[J_STEPCAST]] overflow<nsw> : i32
- ! CHECK: fir.result %[[J_IVINC]] : i32
! CHECK: }
end do
- ! CHECK: fir.store %[[J_RES]] to %[[J_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_I]] : (index) -> i32
- ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow<nsw> : i32
- ! CHECK: fir.result %[[I_IVINC]] : i32
+ ! CHECK: %[[J_LB:.*]] = fir.convert %[[S_J_CVT]] : (index) -> i32
+ ! CHECK: %[[J_UB:.*]] = fir.convert %[[E_J_CVT]] : (index) -> i32
+ ! CHECK: %[[J_STEP:.*]] = fir.convert %[[ST_J]] : (index) -> i32
+ ! CHECK: %[[J_C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[J_DIFF:.*]] = arith.subi %[[J_UB]], %[[J_LB]] overflow<nsw> : i32
+ ! CHECK: %[[J_ADD:.*]] = arith.addi %[[J_DIFF]], %[[J_STEP]] overflow<nsw> : i32
+ ! CHECK: %[[J_TRIP:.*]] = arith.divsi %[[J_ADD]], %[[J_STEP]] : i32
+ ! CHECK: %[[J_CMP:.*]] = arith.cmpi slt, %[[J_TRIP]], %[[J_C0]] : i32
+ ! CHECK: %[[J_SEL:.*]] = arith.select %[[J_CMP]], %[[J_C0]], %[[J_TRIP]] : i32
+ ! CHECK: %[[J_MUL:.*]] = arith.muli %[[J_SEL]], %[[J_STEP]] overflow<nsw> : i32
+ ! CHECK: %[[J_LAST:.*]] = arith.addi %[[J_LB]], %[[J_MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[J_LAST]] to %[[J_DECL]]#0 : !fir.ref<i32>
! CHECK: }
end do
- ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_I_CVT]] : (index) -> i32
+ ! CHECK: %[[I_UB:.*]] = fir.convert %[[E_I_CVT]] : (index) -> i32
+ ! CHECK: %[[I_STEP:.*]] = fir.convert %[[ST_I]] : (index) -> i32
+ ! CHECK: %[[I_C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[I_DIFF:.*]] = arith.subi %[[I_UB]], %[[I_LB]] overflow<nsw> : i32
+ ! CHECK: %[[I_ADD:.*]] = arith.addi %[[I_DIFF]], %[[I_STEP]] overflow<nsw> : i32
+ ! CHECK: %[[I_TRIP:.*]] = arith.divsi %[[I_ADD]], %[[I_STEP]] : i32
+ ! CHECK: %[[I_CMP:.*]] = arith.cmpi slt, %[[I_TRIP]], %[[I_C0]] : i32
+ ! CHECK: %[[I_SEL:.*]] = arith.select %[[I_CMP]], %[[I_C0]], %[[I_TRIP]] : i32
+ ! CHECK: %[[I_MUL:.*]] = arith.muli %[[I_SEL]], %[[I_STEP]] overflow<nsw> : i32
+ ! CHECK: %[[I_LAST:.*]] = arith.addi %[[I_LB]], %[[I_MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[I_LAST]] to %[[I_DECL]]#0 : !fir.ref<i32>
end subroutine
! Test a downcounting loop
@@ -112,19 +128,24 @@ subroutine down_counting_loop()
! CHECK: %[[C1_CVT:.*]] = fir.convert %[[C1]] : (i32) -> index
! CHECK: %[[CMINUS1:.*]] = arith.constant -1 : i32
! CHECK: %[[CMINUS1_STEP_CVT:.*]] = fir.convert %[[CMINUS1]] : (i32) -> index
- ! CHECK: %[[I_LB:.*]] = fir.convert %[[C5_CVT]] : (index) -> i32
- ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
- ! CHECK-SAME: %[[C5_CVT]] to %[[C1_CVT]] step %[[CMINUS1_STEP_CVT]]
- ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) {
+ ! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[C5_CVT]] to %[[C1_CVT]] step %[[CMINUS1_STEP_CVT]] {
do i=5,1,-1
+ ! CHECK: %[[I_IV:.*]] = fir.convert %[[LI]] : (index) -> i32
! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[CMINUS1_STEP_CVT]] : (index) -> i32
- ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow<nsw> : i32
- ! CHECK: fir.result %[[I_IVINC]] : i32
! CHECK: }
end do
- ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: %[[LB:.*]] = fir.convert %[[C5_CVT]] : (index) -> i32
+ ! CHECK: %[[UB:.*]] = fir.convert %[[C1_CVT]] : (index) -> i32
+ ! CHECK: %[[STEP:.*]] = fir.convert %[[CMINUS1_STEP_CVT]] : (index) -> i32
+ ! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+ ! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+ ! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+ ! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+ ! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[LAST]] to %[[I_DECL]]#0 : !fir.ref<i32>
end subroutine
! Test a general loop with a variable step
@@ -143,19 +164,24 @@ subroutine loop_with_variable_step(s,e,st)
! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index
! CHECK: %[[ST:.*]] = fir.load %[[ST_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
- ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32
- ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
- ! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]]
- ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) {
+ ! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] {
do i=s,e,st
+ ! CHECK: %[[I_IV:.*]] = fir.convert %[[LI]] : (index) -> i32
! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32
- ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow<nsw> : i32
- ! CHECK: fir.result %[[I_IVINC]] : i32
! CHECK: }
end do
- ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: %[[LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32
+ ! CHECK: %[[UB:.*]] = fir.convert %[[E_CVT]] : (index) -> i32
+ ! CHECK: %[[STEP:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32
+ ! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+ ! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+ ! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+ ! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+ ! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[LAST]] to %[[I_DECL]]#0 : !fir.ref<i32>
end subroutine
! Test usage of pointer variables as index, start, end and step variables
@@ -197,19 +223,24 @@ subroutine loop_with_pointer_variables(s,e,st)
! CHECK: %[[ST_PTR:.*]] = fir.box_addr %[[ST_BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
! CHECK: %[[ST:.*]] = fir.load %[[ST_PTR]] : !fir.ptr<i32>
! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
-! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32
-! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
-! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]]
-! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i32) {
+! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] {
do iptr=sptr,eptr,stptr
+! CHECK: %[[I_IV:.*]] = fir.convert %[[LI]] : (index) -> i32
! CHECK: fir.store %[[I_IV]] to %[[I_PTR]] : !fir.ptr<i32>
-! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32
-! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_PTR]] : !fir.ptr<i32>
-! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow<nsw> : i32
-! CHECK: fir.result %[[I_IVINC]] : i32
- end do
! CHECK: }
-! CHECK: fir.store %[[I_RES]] to %[[I_PTR]] : !fir.ptr<i32>
+ end do
+! CHECK: %[[LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %[[E_CVT]] : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %[[ST_CVT]] : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[I_PTR]] : !fir.ptr<i32>
end subroutine
! Test usage of non-default integer kind for loop control and loop index variable
@@ -230,19 +261,24 @@ subroutine loop_with_non_default_integer(s,e,st)
! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i64) -> index
integer(kind=8) :: s, e, st
- ! CHECK: %[[I_LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i64
- ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:[^ ]*]] =
- ! CHECK-SAME: %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]]
- ! CHECK-SAME: iter_args(%[[I_IV:.*]] = %[[I_LB]]) -> (i64) {
+ ! CHECK: fir.do_loop %[[LI:[^ ]*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] {
do i=s,e,st
+ ! CHECK: %[[I_IV:.*]] = fir.convert %[[LI]] : (index) -> i64
! CHECK: fir.store %[[I_IV]] to %[[I_DECL]]#0 : !fir.ref<i64>
- ! CHECK: %[[I_STEPCAST:.*]] = fir.convert %[[ST_CVT]] : (index) -> i64
- ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref<i64>
- ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], %[[I_STEPCAST]] overflow<nsw> : i64
- ! CHECK: fir.result %[[I_IVINC]] : i64
- end do
! CHECK: }
- ! CHECK: fir.store %[[I_RES]] to %[[I_DECL]]#0 : !fir.ref<i64>
+ end do
+ ! CHECK: %[[LB:.*]] = fir.convert %[[S_CVT]] : (index) -> i64
+ ! CHECK: %[[UB:.*]] = fir.convert %[[E_CVT]] : (index) -> i64
+ ! CHECK: %[[STEP:.*]] = fir.convert %[[ST_CVT]] : (index) -> i64
+ ! CHECK: %[[C0:.*]] = arith.constant 0 : i64
+ ! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i64
+ ! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i64
+ ! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i64
+ ! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i64
+ ! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i64
+ ! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i64
+ ! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i64
+ ! CHECK: fir.store %[[LAST]] to %[[I_DECL]]#0 : !fir.ref<i64>
end subroutine
! Test real loop control.
diff --git a/flang/test/Lower/do_loop_unstructured.f90 b/flang/test/Lower/do_loop_unstructured.f90
index 4182ab0b6aefa..89c5a1a476f44 100644
--- a/flang/test/Lower/do_loop_unstructured.f90
+++ b/flang/test/Lower/do_loop_unstructured.f90
@@ -219,13 +219,23 @@ subroutine nested_structured_in_unstructured()
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
! CHECK: ^[[BODY]]:
-! CHECK: %{{.*}} = fir.do_loop %[[J_INDEX:[^ ]*]] =
-! CHECK-SAME: %{{.*}} to %{{.*}} step %[[ST:[^ ]*]]
-! CHECK-SAME: iter_args(%[[J_IV:.*]] = %{{.*}}) -> (i32) {
+! CHECK: fir.do_loop %[[J_INDEX:[^ ]*]] =
+! CHECK-SAME: %{{.*}} to %{{.*}} step %[[ST:[^ ]*]] {
+! CHECK: %[[J_IV:.*]] = fir.convert %[[J_INDEX]] : (index) -> i32
! CHECK: fir.store %[[J_IV]] to %[[LOOP_VAR_J_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %{{[^ ]*}} overflow<nsw> : i32
! CHECK: }
+! CHECK: %[[J_LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[J_UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[J_STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[J_C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[J_DIFF:.*]] = arith.subi %[[J_UB]], %[[J_LB]] overflow<nsw> : i32
+! CHECK: %[[J_ADD:.*]] = arith.addi %[[J_DIFF]], %[[J_STEP]] overflow<nsw> : i32
+! CHECK: %[[J_TRIP:.*]] = arith.divsi %[[J_ADD]], %[[J_STEP]] : i32
+! CHECK: %[[J_CMP:.*]] = arith.cmpi slt, %[[J_TRIP]], %[[J_C0]] : i32
+! CHECK: %[[J_SEL:.*]] = arith.select %[[J_CMP]], %[[J_C0]], %[[J_TRIP]] : i32
+! CHECK: %[[J_MUL:.*]] = arith.muli %[[J_SEL]], %[[J_STEP]] overflow<nsw> : i32
+! CHECK: %[[J_LAST:.*]] = arith.addi %[[J_LB]], %[[J_MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[J_LAST]] to %[[LOOP_VAR_J_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
! CHECK: %[[C1_3:.*]] = arith.constant 1 : i32
! CHECK: %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[C1_3]] : i32
diff --git a/flang/test/Lower/infinite_loop.f90 b/flang/test/Lower/infinite_loop.f90
index 64fe0bc1b965a..c5f2196ff01be 100644
--- a/flang/test/Lower/infinite_loop.f90
+++ b/flang/test/Lower/infinite_loop.f90
@@ -96,17 +96,22 @@ subroutine structured_loop_in_infinite(i)
! CHECK: ^[[BODY2:.*]]:
! CHECK: %[[C1_INDEX:.*]] = fir.convert %[[C1]] : (i32) -> index
! CHECK: %[[C10_INDEX:.*]] = fir.convert %[[C10]] : (i32) -> index
-! CHECK: %[[J_LB:.*]] = fir.convert %[[C1_INDEX]] : (index) -> i32
-! CHECK: %[[J_FINAL:.*]] = fir.do_loop %[[J:[^ ]*]] =
-! CHECK-SAME: %[[C1_INDEX]] to %[[C10_INDEX]] step %[[C1_1]]
-! CHECK-SAME: iter_args(%[[J_IV:.*]] = %[[J_LB]]) -> (i32) {
+! CHECK: fir.do_loop %[[J:[^ ]*]] =
+! CHECK-SAME: %[[C1_INDEX]] to %[[C10_INDEX]] step %[[C1_1]] {
+! CHECK: %[[J_IV:.*]] = fir.convert %[[J]] : (index) -> i32
! CHECK: fir.store %[[J_IV]] to %[[J_DECL]] : !fir.ref<i32>
-! CHECK: %[[J_STEPCAST:.*]] = fir.convert %[[C1_1]] : (index) -> i32
-! CHECK: %[[J_IVLOAD:.*]] = fir.load %[[J_DECL]] : !fir.ref<i32>
-! CHECK: %[[J_IVINC:.*]] = arith.addi %[[J_IVLOAD]], %[[J_STEPCAST]] overflow<nsw> : i32
-! CHECK: fir.result %[[J_IVINC]] : i32
! CHECK: }
-! CHECK: fir.store %[[J_FINAL]] to %[[J_DECL]] : !fir.ref<i32>
+! CHECK: %[[J_LB:.*]] = fir.convert %[[C1_INDEX]] : (index) -> i32
+! CHECK: %[[J_UB:.*]] = fir.convert %[[C10_INDEX]] : (index) -> i32
+! CHECK: %[[J_STEP:.*]] = fir.convert %[[C1_1]] : (index) -> i32
+! CHECK: %[[J_DIFF:.*]] = arith.subi %[[J_UB]], %[[J_LB]] overflow<nsw> : i32
+! CHECK: %[[J_ADD:.*]] = arith.addi %[[J_DIFF]], %[[J_STEP]] overflow<nsw> : i32
+! CHECK: %[[J_TRIP:.*]] = arith.divsi %[[J_ADD]], %[[J_STEP]] : i32
+! CHECK: %[[J_CMP:.*]] = arith.cmpi slt, %[[J_TRIP]], %{{.*}} : i32
+! CHECK: %[[J_SEL:.*]] = arith.select %[[J_CMP]], %{{.*}}, %[[J_TRIP]] : i32
+! CHECK: %[[J_MUL:.*]] = arith.muli %[[J_SEL]], %[[J_STEP]] overflow<nsw> : i32
+! CHECK: %[[J_LAST:.*]] = arith.addi %[[J_LB]], %[[J_MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[J_LAST]] to %[[J_DECL]] : !fir.ref<i32>
! CHECK: cf.br ^[[BODY1]]
! CHECK: ^[[RETURN]]:
! CHECK: return
diff --git a/flang/test/Lower/inline_directive.f90 b/flang/test/Lower/inline_directive.f90
index 5748690d5914d..d77b170780f53 100644
--- a/flang/test/Lower/inline_directive.f90
+++ b/flang/test/Lower/inline_directive.f90
@@ -36,14 +36,14 @@ subroutine test_inline()
!dir$ forceinline
do i = 1, 100
- !CHECK: fir.do_loop %[[ARG_0:.*]] = %[[FROM:.*]] to %[[TO:.*]] step %[[C1:.*]] iter_args(%[[ARG_1:.*]] = {{.*}}) -> (i32) {
+ !CHECK: fir.do_loop %[[ARG_0:.*]] = %[[FROM:.*]] to %[[TO:.*]] step %[[C1:.*]] {
!CHECK: fir.call @_QFtest_inlinePf(%[[VAL_1]], %[[VAL_3]]) fastmath<contract> {inline_attr = #fir.inline_attrs<always_inline>} : (!fir.ref<i32>, !fir.ref<i32>) -> ()
call f(x, y)
enddo
!dir$ inline
do i = 1, 100
- !CHECK: fir.do_loop %[[ARG_0:.*]] = %[[FROM:.*]] to %[[TO:.*]] step %[[C1:.*]] iter_args(%[[ARG_1:.*]] = {{.*}}) -> (i32) {
+ !CHECK: fir.do_loop %[[ARG_0:.*]] = %[[FROM:.*]] to %[[TO:.*]] step %[[C1:.*]] {
!CHECK: fir.call @_QFtest_inlinePf(%[[VAL_1]], %[[VAL_3]]) fastmath<contract> {inline_attr = #fir.inline_attrs<inline_hint>} : (!fir.ref<i32>, !fir.ref<i32>) -> ()
call f(x, y)
enddo
diff --git a/flang/test/Lower/ivdep.f90 b/flang/test/Lower/ivdep.f90
index 69f54cd1b0604..d1ea01425b635 100644
--- a/flang/test/Lower/ivdep.f90
+++ b/flang/test/Lower/ivdep.f90
@@ -23,10 +23,6 @@ subroutine ivdep_test1
!CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> i64
!CHECK: %[[VAL_12:.*]] = hlfir.designate %[[VAL_2:.*]]#0 (%[[VAL_11]]) : (!fir.ref<!fir.array<10xi32>>, i64)
!CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_12]] {access_groups = [#access_group]} : i32, !fir.ref<i32>
- !CHECK: %[[VAL_14:.*]] = fir.convert %[[C1:.*]] : (index) -> i32
- !CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_4]]#0 {accessGroups = [#access_group]}
- !CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_15]], %[[VAL_14]] overflow<nsw> : i32
- !CHECK: fir.result %[[VAL_16]] : i32
end do
end subroutine ivdep_test1
@@ -53,10 +49,6 @@ subroutine ivdep_test2
!CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (i32) -> i64
!CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_2:.*]]#0 (%[[VAL_25]]) : (!fir.ref<!fir.array<10xi32>>, i64)
!CHECK: hlfir.assign %[[VAL_23]] to %[[VAL_26]] {access_groups = [#access_group1]} : i32, !fir.ref<i32>
- !CHECK: %[[VAL_28:.*]] = fir.convert %[[C1:.*]] : (index) -> i32
- !CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_10]]#0 {accessGroups = [#access_group1]}
- !CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_29]], %[[VAL_28]] overflow<nsw> : i32
- !CHECK: fir.result %[[VAL_30]] : i32
end do
end subroutine ivdep_test2
@@ -84,10 +76,6 @@ subroutine ivdep_test3
!CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_2:.*]]#0 (%[[VAL_25]]) : (!fir.ref<!fir.array<10xi32>>, i64)
!CHECK: hlfir.assign %[[VAL_23]] to %[[VAL_26]] {access_groups = [#access_group2]} : i32, !fir.ref<i32>
!CHECK: fir.call @_QFivdep_test3Pfoo() fastmath<contract> {accessGroups = [#access_group2]}
- !CHECK: %[[VAL_28:.*]] = fir.convert %[[C1:.*]] : (index) -> i32
- !CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_10]]#0 {accessGroups = [#access_group2]}
- !CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_29]], %[[VAL_28]] overflow<nsw> : i32
- !CHECK: fir.result %[[VAL_30]] : i32
end do
contains
subroutine foo()
diff --git a/flang/test/Lower/loops.f90 b/flang/test/Lower/loops.f90
index bb66f79d5564a..7c500b7a85199 100644
--- a/flang/test/Lower/loops.f90
+++ b/flang/test/Lower/loops.f90
@@ -31,7 +31,7 @@ subroutine loop_test
a(i,j,k) = a(i,j,k) + 1
enddo
- ! CHECK-COUNT-3: fir.do_loop {{[^un]*}} -> (i32)
+ ! CHECK-COUNT-3: fir.do_loop {{[^un]*}}
asum = 0
do i=1,5
do j=1,5
@@ -118,7 +118,7 @@ subroutine lis(n)
! CHECK: %[[V_P_ALLOC:[0-9]+]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?x?x?xi32>>> {bindc_name = "p", pinned, uniq_name = "_QFlisEp"}
! CHECK: fir.store %{{.*}} to %[[V_P_ALLOC]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?x?xi32>>>>
! CHECK: %[[V_P_DECL:.*]]:2 = hlfir.declare %[[V_P_ALLOC]]
- ! CHECK: fir.do_loop %arg3 = %{{.*}} to %{{.*}} step %c1{{.*}} iter_args(%arg4 = %{{.*}}) -> (i32) {
+ ! CHECK: fir.do_loop %arg3 = %{{.*}} to %{{.*}} step %c1{{.*}} {
! CHECK: fir.do_concurrent {
! CHECK: fir.alloca i32 {bindc_name = "m"}
! CHECK: fir.do_concurrent.loop (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) {
diff --git a/flang/test/Lower/loops2.f90 b/flang/test/Lower/loops2.f90
index b24e8b6401ce6..c925c210d737d 100644
--- a/flang/test/Lower/loops2.f90
+++ b/flang/test/Lower/loops2.f90
@@ -15,9 +15,21 @@ subroutine test_pointer()
! CHECK: %[[PTR:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtest_loop_varEi_pointer"}
! CHECK: %[[BOX:.*]] = fir.load %[[PTR]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
-! CHECK: %[[LOOP:.*]] = fir.do_loop
+! CHECK: fir.do_loop
! CHECK: fir.store %{{.*}} to %[[ADDR]] : !fir.ptr<i32>
-! CHECK: fir.store %[[LOOP]] to %[[ADDR]] : !fir.ptr<i32>
+! CHECK: }
+! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[ADDR]] : !fir.ptr<i32>
end subroutine
! CHECK-LABEL: func.func @_QMtest_loop_varPtest_allocatable
@@ -27,9 +39,21 @@ subroutine test_allocatable()
! CHECK: %[[ALLOC:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMtest_loop_varEi_allocatable"}
! CHECK: %[[BOX:.*]] = fir.load %[[ALLOC]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-! CHECK: %[[LOOP:.*]] = fir.do_loop
+! CHECK: fir.do_loop
! CHECK: fir.store %{{.*}} to %[[ADDR]] : !fir.heap<i32>
-! CHECK: fir.store %[[LOOP]] to %[[ADDR]] : !fir.heap<i32>
+! CHECK: }
+! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+! CHECK: fir.store %[[LAST]] to %[[ADDR]] : !fir.heap<i32>
end subroutine
! CHECK-LABEL: func.func @_QMtest_loop_varPtest_real_pointer
diff --git a/flang/test/Lower/mixed_loops.f90 b/flang/test/Lower/mixed_loops.f90
index 11534ae9490d0..91d13012039a4 100644
--- a/flang/test/Lower/mixed_loops.f90
+++ b/flang/test/Lower/mixed_loops.f90
@@ -90,19 +90,28 @@ subroutine do_inside_while_loop
! CHECK-DAG: %[[C8:.*]] = arith.constant 8 : i32
! CHECK-DAG: %[[C13:.*]] = arith.constant 13 : i32
! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
- ! CHECK: %{{.*}} = fir.do_loop %{{.*}} = {{.*}} to {{.*}} step {{.*}} iter_args(%[[I_IV:.*]] = {{.*}}) -> (i32) {
- ! CHECK: fir.store %[[I_IV]] to %[[I]]#0 : !fir.ref<i32>
+ ! CHECK: fir.do_loop %[[LI:.*]] = %{{.*}} to %{{.*}} step %{{.*}} {
+ ! CHECK: %[[IV:.*]] = fir.convert %[[LI]] : (index) -> i32
+ ! CHECK: fir.store %[[IV]] to %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[J2VAL:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[JINC:.*]] = arith.muli %[[C2]], %[[J2VAL]] : i32
! CHECK: hlfir.assign %[[JINC]] to %[[J]]#0 : i32, !fir.ref<i32>
- ! CHECK: %[[I_IVLOAD:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
- ! CHECK: %[[I_IVINC:.*]] = arith.addi %[[I_IVLOAD]], {{.*}} overflow<nsw> : i32
- ! CHECK: fir.result %[[I_IVINC]] : i32
do i=8,13
j=j*2
- ! CHECK: fir.store %{{.*}} to %[[I]]#0 : !fir.ref<i32>
+ ! CHECK: %[[LB:.*]] = fir.convert %{{.*}} : (index) -> i32
+ ! CHECK: %[[UB:.*]] = fir.convert %{{.*}} : (index) -> i32
+ ! CHECK: %[[STEP:.*]] = fir.convert %{{.*}} : (index) -> i32
+ ! CHECK: %[[C0:.*]] = arith.constant 0 : i32
+ ! CHECK: %[[DIFF:.*]] = arith.subi %[[UB]], %[[LB]] overflow<nsw> : i32
+ ! CHECK: %[[ADD:.*]] = arith.addi %[[DIFF]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[TRIP:.*]] = arith.divsi %[[ADD]], %[[STEP]] : i32
+ ! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[TRIP]], %[[C0]] : i32
+ ! CHECK: %[[SEL:.*]] = arith.select %[[CMP]], %[[C0]], %[[TRIP]] : i32
+ ! CHECK: %[[MUL:.*]] = arith.muli %[[SEL]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: %[[LAST:.*]] = arith.addi %[[LB]], %[[MUL]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[LAST]] to %[[I]]#0 : !fir.ref<i32>
end do
! CHECK: cf.br ^[[HDR1]]
diff --git a/flang/test/Lower/nsw.f90 b/flang/test/Lower/nsw.f90
index e113c26a9dc80..cb972d6ad9755 100644
--- a/flang/test/Lower/nsw.f90
+++ b/flang/test/Lower/nsw.f90
@@ -83,8 +83,7 @@ subroutine loop_params(a,lb,ub,st)
! CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_13]] : !fir.ref<i32>
! CHECK: %[[VAL_30:.*]] = arith.muli %[[VAL_29]], %[[VAL_4]] overflow<nsw> : i32
! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i32) -> index
-! CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_26]] : (index) -> i32
-! CHECK: %[[VAL_33:.*]] = fir.do_loop %[[VAL_34:.*]] = %[[VAL_26]] to %[[VAL_28]] step %[[VAL_31]] iter_args(%[[VAL_35:.*]] = %[[VAL_32]]) -> (i32) {
+! CHECK: fir.do_loop %[[VAL_34:.*]] = %[[VAL_26]] to %[[VAL_28]] step %[[VAL_31]] {
subroutine loop_params2(a,lb,ub,st)
integer :: i, lb, ub, st
diff --git a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
index ebacd0353b90b..790bda5bb7d23 100644
--- a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
+++ b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
@@ -48,9 +48,10 @@ program main
! COMMON: omp.wsloop {
! COMMON: omp.loop_nest ({{[^[:space:]]+}}) {{.*}} {
-! COMMON: fir.do_loop {{.*}} iter_args(%[[J_IV:.*]] = {{.*}}) -> {{.*}} {
-! HOST: fir.store %[[J_IV]] to %[[ORIG_J_DECL]]#0
-! DEVICE: fir.store %[[J_IV]] to %[[TARGET_J_DECL]]#0
+! COMMON: fir.do_loop %[[J_IV:.*]] = {{.*}} to {{.*}} step {{.*}} {
+! COMMON: %[[J_IV_CONV:.*]] = fir.convert %[[J_IV]] : (index) -> i32
+! HOST: fir.store %[[J_IV_CONV]] to %[[ORIG_J_DECL]]#0
+! DEVICE: fir.store %[[J_IV_CONV]] to %[[TARGET_J_DECL]]#0
! COMMON: fir.do_concurrent {
! COMMON: %[[ORIG_K_ALLOC:.*]] = fir.alloca i32 {bindc_name = "k"}
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 4fcddb9154397..23e7af238198f 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -226,13 +226,6 @@ static llvm::cl::opt<bool> enableCUDA("fcuda",
llvm::cl::desc("enable CUDA Fortran"),
llvm::cl::init(false));
-static llvm::cl::opt<bool> doConcurrentCleanNestedLoops(
- "fdo-concurrent-clean-nested-loops",
- llvm::cl::desc(
- "lower plain DO loops nested in DO CONCURRENT bodies without "
- "the secondary-induction iter_arg"),
- llvm::cl::init(false));
-
static llvm::cl::opt<bool>
enableDoConcurrentOffload("fdoconcurrent-offload",
llvm::cl::desc("enable do concurrent offload"),
@@ -484,7 +477,6 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
loweringOptions.setRepackArrays(repackArrays);
loweringOptions.setRepackArraysWhole(repackArraysWhole);
loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition);
- loweringOptions.setDoConcurrentCleanNestedLoops(doConcurrentCleanNestedLoops);
if (enableCUDA)
loweringOptions.setCUDARuntimeCheck(true);
if (complexRange == "improved" || complexRange == "basic")
More information about the flang-commits
mailing list