[flang-commits] [flang] [flang] Generate valid IR on GOTO DO body (PR #66084)

Leandro Lupori via flang-commits flang-commits at lists.llvm.org
Tue Sep 12 06:15:02 PDT 2023


https://github.com/luporl created https://github.com/llvm/llvm-project/pull/66084:

Flang was generating invalid IR when there was a GOTO to the body
of a DO loop. This happened because the value of step, computed at
the beginning of the loop, was being reused at the end of the loop,
that, for unstructured loops, is in another basic block. Because of
this, a GOTO could skip the beginning of the loop, that defined
step, and yet try to use it at the end of the loop, which is
invalid.

Instead of reusing the step value, it can be recomputed if it is a
constant, or stored and loaded to/from a temporary variable, for
non-constant step expressions.

Note that, while this change prevents the generation of invalid IR
on the presence of jumps to DO loop bodies, what happens if the
program reaches the end of a DO loop without ever passing through
its beginning is undefined behavior, as some control variables,
such as trip, will be uninitialized. It doesn't seem worth the
effort and overhead to ensure this legacy extension will behave
correctly in this case. This is consistent with at least gfortran,
that doesn't behave correctly if step is not equal to one.

Fixes: https://github.com/llvm/llvm-project/issues/65036


>From fcb95571e99ce58167fac260e17451ad64ba6d95 Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Wed, 6 Sep 2023 20:32:25 +0000
Subject: [PATCH] [flang] Generate valid IR on GOTO DO body

Flang was generating invalid IR when there was a GOTO to the body
of a DO loop. This happened because the value of step, computed at
the beginning of the loop, was being reused at the end of the loop,
that, for unstructured loops, is in another basic block. Because of
this, a GOTO could skip the beginning of the loop, that defined
step, and yet try to use it at the end of the loop, which is
invalid.

Instead of reusing the step value, it can be recomputed if it is a
constant, or stored and loaded to/from a temporary variable, for
non-constant step expressions.

Note that, while this change prevents the generation of invalid IR
on the presence of jumps to DO loop bodies, what happens if the
program reaches the end of a DO loop without ever passing through
its beginning is undefined behavior, as some control variables,
such as trip, will be uninitialized. It doesn't seem worth the
effort and overhead to ensure this legacy extension will behave
correctly in this case. This is consistent with at least gfortran,
that doesn't behave correctly if step is not equal to one.

Fixes: https://github.com/llvm/llvm-project/issues/65036
---
 flang/lib/Lower/Bridge.cpp                |  70 +++++++-----
 flang/test/Lower/HLFIR/goto-do-body.f90   | 114 ++++++++++++++++++++
 flang/test/Lower/do_loop.f90              |   4 +-
 flang/test/Lower/do_loop_unstructured.f90 |  18 ++--
 flang/test/Lower/goto-do-body.f90         | 125 ++++++++++++++++++++++
 flang/test/Lower/loops2.f90               |  15 +--
 flang/test/Lower/mixed_loops.f90          |   3 +-
 7 files changed, 309 insertions(+), 40 deletions(-)
 create mode 100644 flang/test/Lower/HLFIR/goto-do-body.f90
 create mode 100644 flang/test/Lower/goto-do-body.f90

diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 5d5ac0f274773ed..66ee2f6ecaea4a0 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -111,7 +111,6 @@ struct IncrementLoopInfo {
   llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
   llvm::SmallVector<const Fortran::semantics::Symbol *> sharedSymList;
   mlir::Value loopVariable = nullptr;
-  mlir::Value stepValue = nullptr; // possible uses in multiple blocks
 
   // Data members for structured loops.
   fir::DoLoopOp doLoop = nullptr;
@@ -119,6 +118,7 @@ struct IncrementLoopInfo {
   // Data members for unstructured loops.
   bool hasRealControl = false;
   mlir::Value tripVariable = nullptr;
+  mlir::Value stepVariable = nullptr;
   mlir::Block *headerBlock = nullptr; // loop entry and test block
   mlir::Block *maskBlock = nullptr;   // concurrent loop mask block
   mlir::Block *bodyBlock = nullptr;   // first loop body block
@@ -1708,29 +1708,45 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     genFIR(endDoEval, unstructuredContext);
   }
 
+  /// Generate FIR to evaluate loop control values (lower, upper and step).
+  mlir::Value genControlValue(const Fortran::lower::SomeExpr *expr,
+                              const IncrementLoopInfo &info,
+                              bool *isConst = nullptr) {
+    mlir::Location loc = toLocation();
+    mlir::Type controlType = info.isStructured() ? builder->getIndexType()
+                                                 : info.getLoopVariableType();
+    Fortran::lower::StatementContext stmtCtx;
+    if (expr) {
+      if (isConst)
+        *isConst = Fortran::evaluate::IsConstantExpr(*expr);
+      return builder->createConvert(loc, controlType,
+                                    createFIRExpr(loc, expr, stmtCtx));
+    }
+
+    if (isConst)
+      *isConst = true;
+    if (info.hasRealControl)
+      return builder->createRealConstant(loc, controlType, 1u);
+    return builder->createIntegerConstant(loc, controlType, 1); // step
+  }
+
   /// Generate FIR to begin a structured or unstructured increment loop nest.
   void genFIRIncrementLoopBegin(IncrementLoopNestInfo &incrementLoopNestInfo) {
     assert(!incrementLoopNestInfo.empty() && "empty loop nest");
     mlir::Location loc = toLocation();
-    auto genControlValue = [&](const Fortran::lower::SomeExpr *expr,
-                               const IncrementLoopInfo &info) {
-      mlir::Type controlType = info.isStructured() ? builder->getIndexType()
-                                                   : info.getLoopVariableType();
-      Fortran::lower::StatementContext stmtCtx;
-      if (expr)
-        return builder->createConvert(loc, controlType,
-                                      createFIRExpr(loc, expr, stmtCtx));
-
-      if (info.hasRealControl)
-        return builder->createRealConstant(loc, controlType, 1u);
-      return builder->createIntegerConstant(loc, controlType, 1); // step
-    };
     for (IncrementLoopInfo &info : incrementLoopNestInfo) {
       info.loopVariable =
           genLoopVariableAddress(loc, info.loopVariableSym, info.isUnordered);
       mlir::Value lowerValue = genControlValue(info.lowerExpr, info);
       mlir::Value upperValue = genControlValue(info.upperExpr, info);
-      info.stepValue = genControlValue(info.stepExpr, info);
+      bool isConst = true;
+      mlir::Value stepValue = genControlValue(
+          info.stepExpr, info, info.isStructured() ? nullptr : &isConst);
+      // Use a temp variable for unstructured loops with non-const step.
+      if (!isConst) {
+        info.stepVariable = builder->createTemporary(loc, stepValue.getType());
+        builder->create<fir::StoreOp>(loc, stepValue, info.stepVariable);
+      }
 
       // Structured loop - generate fir.do_loop.
       if (info.isStructured()) {
@@ -1739,14 +1755,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         if (info.isUnordered) {
           // The loop variable value is explicitly updated.
           info.doLoop = builder->create<fir::DoLoopOp>(
-              loc, lowerValue, upperValue, info.stepValue, /*unordered=*/true);
+              loc, lowerValue, upperValue, stepValue, /*unordered=*/true);
           builder->setInsertionPointToStart(info.doLoop.getBody());
           loopValue = builder->createConvert(loc, loopVarType,
                                              info.doLoop.getInductionVar());
         } else {
           // The loop variable is a doLoop op argument.
           info.doLoop = builder->create<fir::DoLoopOp>(
-              loc, lowerValue, upperValue, info.stepValue, /*unordered=*/false,
+              loc, lowerValue, upperValue, stepValue, /*unordered=*/false,
               /*finalCountValue=*/true,
               builder->createConvert(loc, loopVarType, lowerValue));
           builder->setInsertionPointToStart(info.doLoop.getBody());
@@ -1775,18 +1791,17 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         auto diff1 =
             builder->create<mlir::arith::SubFOp>(loc, upperValue, lowerValue);
         auto diff2 =
-            builder->create<mlir::arith::AddFOp>(loc, diff1, info.stepValue);
-        tripCount =
-            builder->create<mlir::arith::DivFOp>(loc, diff2, info.stepValue);
+            builder->create<mlir::arith::AddFOp>(loc, diff1, stepValue);
+        tripCount = builder->create<mlir::arith::DivFOp>(loc, diff2, stepValue);
         tripCount =
             builder->createConvert(loc, builder->getIndexType(), tripCount);
       } else {
         auto diff1 =
             builder->create<mlir::arith::SubIOp>(loc, upperValue, lowerValue);
         auto diff2 =
-            builder->create<mlir::arith::AddIOp>(loc, diff1, info.stepValue);
+            builder->create<mlir::arith::AddIOp>(loc, diff1, stepValue);
         tripCount =
-            builder->create<mlir::arith::DivSIOp>(loc, diff2, info.stepValue);
+            builder->create<mlir::arith::DivSIOp>(loc, diff2, stepValue);
       }
       if (forceLoopToExecuteOnce) { // minimum tripCount is 1
         mlir::Value one =
@@ -1874,12 +1889,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       tripCount = builder->create<mlir::arith::SubIOp>(loc, tripCount, one);
       builder->create<fir::StoreOp>(loc, tripCount, info.tripVariable);
       mlir::Value value = builder->create<fir::LoadOp>(loc, info.loopVariable);
+      mlir::Value step;
+      if (info.stepVariable)
+        step = builder->create<fir::LoadOp>(loc, info.stepVariable);
+      else
+        step = genControlValue(info.stepExpr, info);
       if (info.hasRealControl)
-        value =
-            builder->create<mlir::arith::AddFOp>(loc, value, info.stepValue);
+        value = builder->create<mlir::arith::AddFOp>(loc, value, step);
       else
-        value =
-            builder->create<mlir::arith::AddIOp>(loc, value, info.stepValue);
+        value = builder->create<mlir::arith::AddIOp>(loc, value, step);
       builder->create<fir::StoreOp>(loc, value, info.loopVariable);
 
       genBranch(info.headerBlock);
diff --git a/flang/test/Lower/HLFIR/goto-do-body.f90 b/flang/test/Lower/HLFIR/goto-do-body.f90
new file mode 100644
index 000000000000000..383b839e591e33d
--- /dev/null
+++ b/flang/test/Lower/HLFIR/goto-do-body.f90
@@ -0,0 +1,114 @@
+! RUN: bbc --hlfir -o - %s | FileCheck %s
+
+! Test jumping to the body of a do loop.
+subroutine sub1()
+! CHECK-LABEL:  func @_QPsub1() {
+  implicit none
+  integer :: i
+  external foo
+! CHECK:    %[[C2:.*]] = arith.constant 2 : i32
+! CHECK:    %[[C0:.*]] = arith.constant 0 : i32
+! CHECK:    %[[C1:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TRIP:.*]] = fir.alloca i32
+! CHECK:    %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", {{.*}}}
+! CHECK:    %[[I:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFsub1Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+
+  do i = 1, 3
+    if (i .eq. 2) goto 70
+! CHECK:    %[[TMP1:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
+! CHECK:    %[[COND:.*]] = arith.cmpi eq, %[[TMP1]], %[[C2]] : i32
+! CHECK:    cf.cond_br %[[COND]], ^[[BODY:.*]], ^{{.*}}
+
+  end do
+
+  call foo
+! CHECK:  fir.call @_QPfoo()
+
+  do i = 1, 2
+! CHECK:    fir.store %[[C2]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    fir.store %[[C1]] to %[[I]]#1 : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER:.*]]
+! CHECK:  ^[[HEADER]]:
+! CHECK:    %[[TMP2:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP3:.*]] = arith.cmpi sgt, %[[TMP2]], %[[C0]] : i32
+! CHECK:    cf.cond_br %[[TMP3]], ^[[BODY]], ^[[EXIT:.*]]
+
+    70 call foo
+! CHECK:  ^[[BODY]]:
+! CHECK:    fir.call @_QPfoo()
+! CHECK:    %[[TMP4:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP5:.*]] = arith.subi %[[TMP4]], %[[C1]] : i32
+! CHECK:    fir.store %[[TMP5]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP6:.*]] = fir.load %[[I]]#1 : !fir.ref<i32>
+! CHECK:    %[[TMP7:.*]] = arith.addi %[[TMP6]], %[[C1]] : i32
+! CHECK:    fir.store %[[TMP7]] to %[[I]]#1 : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER]]
+  end do
+end subroutine
+! CHECK: ^[[EXIT]]:
+! CHECK:    return
+! CHECK:  }
+
+! Test jumping to the body of a do loop with a step expression.
+subroutine sub2()
+! CHECK-LABEL:  func @_QPsub2() {
+  implicit none
+  integer :: i, j
+  external foo
+! CHECK:    %[[C_7:.*]] = arith.constant -7 : i32
+! CHECK:    %[[C8:.*]] = arith.constant 8 : i32
+! CHECK:    %[[C2:.*]] = arith.constant 2 : i32
+! CHECK:    %[[C0:.*]] = arith.constant 0 : i32
+! CHECK:    %[[C3:.*]] = arith.constant 3 : i32
+! CHECK:    %[[C1:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TRIP:.*]] = fir.alloca i32
+! CHECK:    %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", {{.*}}}
+! CHECK:    %[[I:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFsub2Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:    %[[J_REF:.*]] = fir.alloca i32 {bindc_name = "j", {{.*}}}
+! CHECK:    %[[J:.*]]:2 = hlfir.declare %[[J_REF]] {uniq_name = "_QFsub2Ej"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+
+  do i = 1, 3
+    if (i .eq. 2) goto 70
+! CHECK:    %[[TMP1:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
+! CHECK:    %[[COND:.*]] = arith.cmpi eq, %[[TMP1]], %[[C2]] : i32
+! CHECK:    cf.cond_br %[[COND]], ^[[BODY:.*]], ^{{.*}}
+
+  end do
+
+  call foo
+! CHECK:    fir.call @_QPfoo()
+
+  j = 3
+! CHECK:    hlfir.assign %[[C3]] to %[[J]]#0 : i32, !fir.ref<i32>
+
+  do i = 1, 2, 3 * j - 8
+! CHECK:    %[[TMP2:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
+! CHECK:    %[[TMP3:.*]] = arith.muli %[[TMP2]], %[[C3]] : i32
+! CHECK:    %[[STEP:.*]] = arith.subi %[[TMP3]], %[[C8]] : i32
+! CHECK:    fir.store %[[STEP]] to %[[STEP_VAR:.*]] : !fir.ref<i32>
+! CHECK:    %[[TMP4:.*]] = arith.addi %[[TMP3]], %[[C_7]] : i32
+! CHECK:    %[[TMP5:.*]] = arith.divsi %[[TMP4]], %[[STEP]] : i32
+! CHECK:    fir.store %[[TMP5]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    fir.store %[[C1]] to %[[I]]#1 : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER:.*]]
+! CHECK:  ^[[HEADER]]:
+! CHECK:    %[[TMP6:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP7:.*]] = arith.cmpi sgt, %[[TMP6]], %[[C0]] : i32
+! CHECK:    cf.cond_br %[[TMP7]], ^[[BODY]], ^[[EXIT:.*]]
+
+    70 call foo
+! CHECK:  ^[[BODY]]:
+! CHECK:    fir.call @_QPfoo()
+! CHECK:    %[[TMP8:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP9:.*]] = arith.subi %[[TMP8]], %[[C1]] : i32
+! CHECK:    fir.store %[[TMP9]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP10:.*]] = fir.load %[[I]]#1 : !fir.ref<i32>
+! CHECK:    %[[STEP_VAL:.*]] = fir.load %[[STEP_VAR]] : !fir.ref<i32>
+! CHECK:    %[[TMP11:.*]] = arith.addi %[[TMP10]], %[[STEP_VAL]] : i32
+! CHECK:    fir.store %[[TMP11]] to %[[I]]#1 : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER]]
+  end do
+end subroutine
+! CHECK: ^[[EXIT]]:
+! CHECK:    return
+! CHECK:  }
diff --git a/flang/test/Lower/do_loop.f90 b/flang/test/Lower/do_loop.f90
index 512168763ceb9bd..d6ca1fe70977dd9 100644
--- a/flang/test/Lower/do_loop.f90
+++ b/flang/test/Lower/do_loop.f90
@@ -245,6 +245,7 @@ subroutine loop_with_real_control(s,e,st)
   ! CHECK-DAG: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<f32>
   ! CHECK-DAG: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<f32>
   ! CHECK-DAG: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<f32>
+  ! CHECK: fir.store %[[ST]] to %[[ST_VAR:.*]] : !fir.ref<f32>
   real :: x, s, e, st
 
   ! CHECK: %[[DIFF:.*]] = arith.subf %[[E]], %[[S]] {{.*}}: f32
@@ -267,7 +268,8 @@ subroutine loop_with_real_control(s,e,st)
     ! CHECK: %[[INC:.*]] = arith.subi %[[INDEX2]], %[[C1]] : index
     ! CHECK: fir.store %[[INC]] to %[[INDEX_REF]] : !fir.ref<index>
     ! CHECK: %[[X2:.*]] = fir.load %[[X_REF]] : !fir.ref<f32>
-    ! CHECK: %[[XINC:.*]] = arith.addf %[[X2]], %[[ST]] {{.*}}: f32
+    ! CHECK: %[[ST_VAL:.*]] = fir.load %[[ST_VAR]] : !fir.ref<f32>
+    ! CHECK: %[[XINC:.*]] = arith.addf %[[X2]], %[[ST_VAL]] {{.*}}: f32
     ! CHECK: fir.store %[[XINC]] to %[[X_REF]] : !fir.ref<f32>
     ! CHECK: br ^[[HDR]]
   end do
diff --git a/flang/test/Lower/do_loop_unstructured.f90 b/flang/test/Lower/do_loop_unstructured.f90
index a8c849a48827934..2b5f1c6c0061a1d 100644
--- a/flang/test/Lower/do_loop_unstructured.f90
+++ b/flang/test/Lower/do_loop_unstructured.f90
@@ -37,7 +37,8 @@ subroutine simple_unstructured()
 ! CHECK:   %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_ONE]] : i32
+! CHECK:   %[[STEP_ONE_2:.*]] = arith.constant 1 : i32
+! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_ONE_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER]]
 ! CHECK: ^[[EXIT]]:
@@ -75,7 +76,8 @@ subroutine simple_unstructured_with_step()
 ! CHECK:   %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP]] : i32
+! CHECK:   %[[STEP_2:.*]] = arith.constant 2 : i32
+! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER]]
 ! CHECK: ^[[EXIT]]:
@@ -151,7 +153,8 @@ subroutine nested_unstructured()
 ! CHECK:   %[[TRIP_VAR_K_NEXT:.*]] = arith.subi %[[TRIP_VAR_K]], %[[ONE_1]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_K_NEXT]] to %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR_K:.*]] = fir.load %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_K_NEXT:.*]] = arith.addi %[[LOOP_VAR_K]], %[[K_STEP]] : i32
+! CHECK:   %[[K_STEP_2:.*]] = arith.constant 1 : i32
+! CHECK:   %[[LOOP_VAR_K_NEXT:.*]] = arith.addi %[[LOOP_VAR_K]], %[[K_STEP_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_K_NEXT]] to %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER_K]]
 ! CHECK: ^[[EXIT_K]]:
@@ -160,7 +163,8 @@ subroutine nested_unstructured()
 ! CHECK:   %[[TRIP_VAR_J_NEXT:.*]] = arith.subi %[[TRIP_VAR_J]], %[[ONE_1]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_J_NEXT]] to %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %[[J_STEP]] : i32
+! CHECK:   %[[J_STEP_2:.*]] = arith.constant 1 : i32
+! CHECK:   %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %[[J_STEP_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_J_NEXT]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER_J]]
 ! CHECK: ^[[EXIT_J]]:
@@ -169,7 +173,8 @@ subroutine nested_unstructured()
 ! CHECK:   %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[ONE_1]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP]] : i32
+! CHECK:   %[[I_STEP_2:.*]] = arith.constant 1 : i32
+! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER_I]]
 ! CHECK: ^[[EXIT_I]]:
@@ -215,7 +220,8 @@ subroutine nested_structured_in_unstructured()
 ! CHECK:   %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[C1_3]] : i32
 ! CHECK:   fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
 ! CHECK:   %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
-! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %c1_i32_0 : i32
+! CHECK:   %[[I_STEP_2:.*]] = arith.constant 1 : i32
+! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] : i32
 ! CHECK:   fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
 ! CHECK:   cf.br ^[[HEADER]]
 ! CHECK: ^[[EXIT]]:
diff --git a/flang/test/Lower/goto-do-body.f90 b/flang/test/Lower/goto-do-body.f90
new file mode 100644
index 000000000000000..3854947b55f6294
--- /dev/null
+++ b/flang/test/Lower/goto-do-body.f90
@@ -0,0 +1,125 @@
+! RUN: bbc %s -emit-fir -o - | FileCheck %s
+
+! Test jumping to the body of a do loop.
+subroutine sub1()
+! CHECK-LABEL:  func @_QPsub1() {
+  implicit none
+  integer :: i
+  external foo
+! CHECK:    %[[TRIP:.*]] = fir.alloca i32
+! CHECK:    %[[I:.*]] = fir.alloca i32 {bindc_name = "i", {{.*}}}
+
+  do i = 1, 3
+    if (i .eq. 2) goto 70
+! CHECK:    %[[TMP1:.*]] = fir.load %[[I]] : !fir.ref<i32>
+! CHECK:    %[[C2_1:.*]] = arith.constant 2 : i32
+! CHECK:    %[[COND:.*]] = arith.cmpi eq, %[[TMP1]], %[[C2_1]] : i32
+! CHECK:    cf.cond_br %[[COND]], ^[[COND_TRUE:.*]], ^{{.*}}
+! CHECK:  ^[[COND_TRUE]]:
+! CHECK:    cf.br ^[[BODY:.*]]
+
+  end do
+
+  call foo
+! CHECK:  fir.call @_QPfoo()
+
+  do i = 1, 2
+! CHECK:    %[[C1_1:.*]] = arith.constant 1 : i32
+! CHECK:    %[[C2_2:.*]] = arith.constant 2 : i32
+! CHECK:    %[[C1_2:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TMP2:.*]] = arith.subi %[[C2_2]], %[[C1_1]] : i32
+! CHECK:    %[[TMP3:.*]] = arith.addi %[[TMP2]], %[[C1_2]] : i32
+! CHECK:    %[[TMP4:.*]] = arith.divsi %[[TMP3]], %[[C1_2]] : i32
+! CHECK:    fir.store %[[TMP4]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    fir.store %[[C1_1]] to %[[I]] : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER:.*]]
+! CHECK:  ^[[HEADER]]:
+! CHECK:    %[[TMP5:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[C0_1:.*]] = arith.constant 0 : i32
+! CHECK:    %[[TMP6:.*]] = arith.cmpi sgt, %[[TMP5]], %[[C0_1]] : i32
+! CHECK:    cf.cond_br %[[TMP6]], ^[[BODY]], ^[[EXIT:.*]]
+
+    70 call foo
+! CHECK:  ^[[BODY]]:
+! CHECK:    fir.call @_QPfoo()
+! CHECK:    %[[TMP7:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[C1_3:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TMP8:.*]] = arith.subi %[[TMP7]], %[[C1_3]] : i32
+! CHECK:    fir.store %[[TMP8]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP9:.*]] = fir.load %[[I]] : !fir.ref<i32>
+! CHECK:    %[[C1_4:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TMP10:.*]] = arith.addi %[[TMP9]], %[[C1_4]] : i32
+! CHECK:    fir.store %[[TMP10]] to %[[I]] : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER]]
+  end do
+end subroutine
+! CHECK: ^[[EXIT]]:
+! CHECK:    return
+! CHECK:  }
+
+! Test jumping to the body of a do loop with a step expression.
+subroutine sub2()
+! CHECK-LABEL:  func @_QPsub2() {
+  implicit none
+  integer :: i, j
+  external foo
+! CHECK:    %[[TRIP:.*]] = fir.alloca i32
+! CHECK:    %[[I:.*]] = fir.alloca i32 {bindc_name = "i", {{.*}}}
+! CHECK:    %[[J:.*]] = fir.alloca i32 {bindc_name = "j", {{.*}}}
+
+  do i = 1, 3
+    if (i .eq. 2) goto 70
+! CHECK:    %[[TMP1:.*]] = fir.load %[[I]] : !fir.ref<i32>
+! CHECK:    %[[C2_1:.*]] = arith.constant 2 : i32
+! CHECK:    %[[COND:.*]] = arith.cmpi eq, %[[TMP1]], %[[C2_1]] : i32
+! CHECK:    cf.cond_br %[[COND]], ^[[COND_TRUE:.*]], ^{{.*}}
+! CHECK:  ^[[COND_TRUE]]:
+! CHECK:    cf.br ^[[BODY:.*]]
+
+  end do
+
+  call foo
+! CHECK:    fir.call @_QPfoo()
+
+  j = 3
+! CHECK:    %[[C3_1:.*]] = arith.constant 3 : i32
+! CHECK:    fir.store %[[C3_1]] to %[[J]] : !fir.ref<i32>
+
+  do i = 1, 2, 3 * j - 8
+! CHECK:    %[[C1_1:.*]] = arith.constant 1 : i32
+! CHECK:    %[[C2_2:.*]] = arith.constant 2 : i32
+! CHECK:    %[[C3_2:.*]] = arith.constant 3 : i32
+! CHECK:    %[[TMP2:.*]] = fir.load %[[J]] : !fir.ref<i32>
+! CHECK:    %[[TMP3:.*]] = arith.muli %[[C3_2]], %[[TMP2]] : i32
+! CHECK:    %[[C8_1:.*]] = arith.constant 8 : i32
+! CHECK:    %[[STEP:.*]] = arith.subi %[[TMP3]], %[[C8_1]] : i32
+! CHECK:    fir.store %[[STEP]] to %[[STEP_VAR:.*]] : !fir.ref<i32>
+! CHECK:    %[[TMP4:.*]] = arith.subi %[[C2_2]], %[[C1_1]] : i32
+! CHECK:    %[[TMP5:.*]] = arith.addi %[[TMP4]], %[[STEP]] : i32
+! CHECK:    %[[TMP6:.*]] = arith.divsi %[[TMP5]], %[[STEP]] : i32
+! CHECK:    fir.store %[[TMP6]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    fir.store %[[C1_1]] to %[[I]] : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER:.*]]
+! CHECK:  ^[[HEADER]]:
+! CHECK:    %[[TMP7:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[C0_1:.*]] = arith.constant 0 : i32
+! CHECK:    %[[TMP8:.*]] = arith.cmpi sgt, %[[TMP7]], %[[C0_1]] : i32
+! CHECK:    cf.cond_br %[[TMP8]], ^[[BODY]], ^[[EXIT:.*]]
+
+    70 call foo
+! CHECK:  ^[[BODY]]:
+! CHECK:    fir.call @_QPfoo()
+! CHECK:    %[[TMP9:.*]] = fir.load %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[C1_2:.*]] = arith.constant 1 : i32
+! CHECK:    %[[TMP10:.*]] = arith.subi %[[TMP9]], %[[C1_2]] : i32
+! CHECK:    fir.store %[[TMP10]] to %[[TRIP]] : !fir.ref<i32>
+! CHECK:    %[[TMP11:.*]] = fir.load %[[I]] : !fir.ref<i32>
+! CHECK:    %[[STEP_VAL:.*]] = fir.load %[[STEP_VAR]] : !fir.ref<i32>
+! CHECK:    %[[TMP12:.*]] = arith.addi %[[TMP11]], %[[STEP_VAL]] : i32
+! CHECK:    fir.store %[[TMP12]] to %[[I]] : !fir.ref<i32>
+! CHECK:    cf.br ^[[HEADER]]
+  end do
+end subroutine
+! CHECK: ^[[EXIT]]:
+! CHECK:    return
+! CHECK:  }
diff --git a/flang/test/Lower/loops2.f90 b/flang/test/Lower/loops2.f90
index 78795fa642ea42e..4baf4f2b6ec3894 100644
--- a/flang/test/Lower/loops2.f90
+++ b/flang/test/Lower/loops2.f90
@@ -52,8 +52,9 @@ subroutine test_real_pointer()
 ! CHECK:         cond_br %{{.*}}, ^bb2, ^bb3
 ! CHECK:       ^bb2:
 ! CHECK:         %[[VAL_19:.*]] = fir.load %[[VAL_3]] : !fir.ptr<f32>
-! CHECK:         %[[VAL_20:.*]] = arith.addf %[[VAL_19]], %[[VAL_8]] {{.*}}: f32
-! CHECK:         fir.store %[[VAL_20]] to %[[VAL_3]] : !fir.ptr<f32>
+! CHECK:         %[[VAL_20:.*]] = arith.constant 1.000000e+00 : f32
+! CHECK:         %[[VAL_21:.*]] = arith.addf %[[VAL_19]], %[[VAL_20]] {{.*}}: f32
+! CHECK:         fir.store %[[VAL_21]] to %[[VAL_3]] : !fir.ptr<f32>
 ! CHECK:         br ^bb1
 ! CHECK:       ^bb3:
 ! CHECK:         return
@@ -77,8 +78,9 @@ subroutine test_real_allocatable()
 ! CHECK:         cond_br %{{.*}}, ^bb2, ^bb3
 ! CHECK:       ^bb2:
 ! CHECK:         %[[VAL_19:.*]] = fir.load %[[VAL_3]] : !fir.heap<f32>
-! CHECK:         %[[VAL_20:.*]] = arith.addf %[[VAL_19]], %[[VAL_8]] {{.*}}: f32
-! CHECK:         fir.store %[[VAL_20]] to %[[VAL_3]] : !fir.heap<f32>
+! CHECK:         %[[VAL_20:.*]] = arith.constant 1.000000e+00 : f32
+! CHECK:         %[[VAL_21:.*]] = arith.addf %[[VAL_19]], %[[VAL_20]] {{.*}}: f32
+! CHECK:         fir.store %[[VAL_21]] to %[[VAL_3]] : !fir.heap<f32>
 ! CHECK:         br ^bb1
 ! CHECK:       ^bb3:
 ! CHECK:         return
@@ -103,8 +105,9 @@ subroutine test_pointer_unstructured_loop()
 ! CHECK:       ^bb3:
 ! CHECK:         br ^bb5
 ! CHECK:       ^bb4:
-! CHECK:         %[[VAL_21:.*]] = fir.load %[[VAL_3]] : !fir.ptr<i32>
-! CHECK:         %[[VAL_22:.*]] = arith.addi %[[VAL_21]], %[[VAL_6]] : i32
+! CHECK:         %[[VAL_20:.*]] = fir.load %[[VAL_3]] : !fir.ptr<i32>
+! CHECK:         %[[VAL_21:.*]] = arith.constant 1 : i32
+! CHECK:         %[[VAL_22:.*]] = arith.addi %[[VAL_20]], %[[VAL_21]] : i32
 ! CHECK:         fir.store %[[VAL_22]] to %[[VAL_3]] : !fir.ptr<i32>
 ! CHECK:         br ^bb1
 ! CHECK:       ^bb5:
diff --git a/flang/test/Lower/mixed_loops.f90 b/flang/test/Lower/mixed_loops.f90
index 651919dd5b3b1ca..dcbc7893983459f 100644
--- a/flang/test/Lower/mixed_loops.f90
+++ b/flang/test/Lower/mixed_loops.f90
@@ -52,7 +52,8 @@ subroutine while_inside_do_loop
   ! CHECK: %[[TDEC:.*]] = arith.subi %[[T2]], %[[C1_AGAIN]] : i32
   ! CHECK: fir.store %[[TDEC]] to %[[T_REF]]
   ! CHECK: %[[I3:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
-  ! CHECK: %[[IINC:.*]] = arith.addi %[[I3]], %[[C1]] : i32
+  ! CHECK: %[[C1_2:.*]] = arith.constant 1 : i32
+  ! CHECK: %[[IINC:.*]] = arith.addi %[[I3]], %[[C1_2]] : i32
   ! CHECK: fir.store %[[IINC]] to %[[I_REF]] : !fir.ref<i32>
   ! CHECK: br ^[[HDR1]]
   end do



More information about the flang-commits mailing list