[flang-commits] [flang] b5b3e50 - [Flang] Initial lowering of the Fortran Do loop

Kiran Chandramohan via flang-commits flang-commits at lists.llvm.org
Thu Apr 28 06:07:22 PDT 2022


Author: Kiran Chandramohan
Date: 2022-04-28T13:03:16Z
New Revision: b5b3e50f65ee99257041723e7645d44c1aeb1117

URL: https://github.com/llvm/llvm-project/commit/b5b3e50f65ee99257041723e7645d44c1aeb1117
DIFF: https://github.com/llvm/llvm-project/commit/b5b3e50f65ee99257041723e7645d44c1aeb1117.diff

LOG: [Flang] Initial lowering of the Fortran Do loop

This patch adds code to lower simple Fortran Do loops with loop control.
Lowering is performed by the the `genFIR` function when called with a
`Fortran::parser::DoConstruct`. `genFIR` function calls `genFIRIncrementLoopBegin`
then calls functions to lower the body of the loop and finally calls
the function `genFIRIncrementLoopEnd`. `genFIRIncrementLoopBegin` is
responsible for creating the FIR `do_loop` as well as storing the value of
the loop index to the loop variable. `genFIRIncrementLoopEnd` returns
the incremented value of the loop index and also stores the index value
outside the loop. This is important since the loop variable can be used
outside the loop. Information about a loop is collected in a structure
`IncrementLoopInfo`.

Note 1: Future patches will bring in lowering for unstructured,
infinite, while loops
Note 2: This patch is part of upstreaming code from the fir-dev branch of
https://github.com/flang-compiler/f18-llvm-project.

Reviewed By: awarzynski

Differential Revision: https://reviews.llvm.org/D124277

Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Val Donaldson <vdonaldson at nvidia.com>
Co-authored-by: Peter Klausler <pklausler at nvidia.com>
Co-authored-by: Valentin Clement <clementval at gmail.com>

Added: 
    flang/test/Lower/do_loop.f90

Modified: 
    flang/lib/Lower/Bridge.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 340da68653695..dc4ee10767fef 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -62,6 +62,43 @@ static llvm::cl::opt<bool> forceLoopToExecuteOnce(
     llvm::cl::desc("force the body of a loop to execute at least once"));
 
 namespace {
+/// Information for generating a structured or unstructured increment loop.
+struct IncrementLoopInfo {
+  template <typename T>
+  explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower,
+                             const T &upper, const std::optional<T> &step,
+                             bool isUnordered = false)
+      : loopVariableSym{sym}, lowerExpr{Fortran::semantics::GetExpr(lower)},
+        upperExpr{Fortran::semantics::GetExpr(upper)},
+        stepExpr{Fortran::semantics::GetExpr(step)}, isUnordered{isUnordered} {}
+
+  IncrementLoopInfo(IncrementLoopInfo &&) = default;
+  IncrementLoopInfo &operator=(IncrementLoopInfo &&x) { return x; }
+
+  // TODO: change when unstructured loops are also supported
+  bool isStructured() const { return true; }
+
+  mlir::Type getLoopVariableType() const {
+    assert(loopVariable && "must be set");
+    return fir::unwrapRefType(loopVariable.getType());
+  }
+
+  // Data members common to both structured and unstructured loops.
+  const Fortran::semantics::Symbol &loopVariableSym;
+  const Fortran::lower::SomeExpr *lowerExpr;
+  const Fortran::lower::SomeExpr *upperExpr;
+  const Fortran::lower::SomeExpr *stepExpr;
+  bool isUnordered; // do concurrent, forall
+  mlir::Value loopVariable = nullptr;
+  mlir::Value stepValue = nullptr; // possible uses in multiple blocks
+
+  // Data members for structured loops.
+  fir::DoLoopOp doLoop = nullptr;
+
+  // Data members for unstructured loops.
+  // TODO:
+};
+
 /// Helper class to generate the runtime type info global data. This data
 /// is required to describe the derived type to the runtime so that it can
 /// operate over it. It must be ensured this data will be generated for every
@@ -122,6 +159,7 @@ class RuntimeTypeInfoConverter {
   llvm::SmallSetVector<Fortran::semantics::SymbolRef, 64> seen;
 };
 
+using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo>;
 } // namespace
 
 //===----------------------------------------------------------------------===//
@@ -573,6 +611,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         [&sb](auto &) { return sb.toExtendedValue(); });
   }
 
+  /// Generate the address of loop variable \p sym.
+  mlir::Value genLoopVariableAddress(mlir::Location loc,
+                                     const Fortran::semantics::Symbol &sym) {
+    assert(lookupSymbol(sym) && "loop control variable must already be in map");
+    Fortran::lower::StatementContext stmtCtx;
+    return fir::getBase(
+        genExprAddr(Fortran::evaluate::AsGenericExpr(sym).value(), stmtCtx));
+  }
+
   static bool isNumericScalarCategory(Fortran::common::TypeCategory cat) {
     return cat == Fortran::common::TypeCategory::Integer ||
            cat == Fortran::common::TypeCategory::Real ||
@@ -907,7 +954,106 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   ///  - structured and unstructured increment loops
   ///  - structured and unstructured concurrent loops
   void genFIR(const Fortran::parser::DoConstruct &doConstruct) {
-    TODO(toLocation(), "DoConstruct lowering");
+    setCurrentPositionAt(doConstruct);
+    // Collect loop nest information.
+    // Generate begin loop code directly for infinite and while loops.
+    Fortran::lower::pft::Evaluation &eval = getEval();
+    Fortran::lower::pft::Evaluation &doStmtEval =
+        eval.getFirstNestedEvaluation();
+    auto *doStmt = doStmtEval.getIf<Fortran::parser::NonLabelDoStmt>();
+    const auto &loopControl =
+        std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
+    IncrementLoopNestInfo incrementLoopNestInfo;
+    if (const auto *bounds = std::get_if<Fortran::parser::LoopControl::Bounds>(
+            &loopControl->u)) {
+      // Non-concurrent increment loop.
+      incrementLoopNestInfo.emplace_back(*bounds->name.thing.symbol,
+                                         bounds->lower, bounds->upper,
+                                         bounds->step);
+      // TODO: unstructured loop
+    } else {
+      TODO(toLocation(), "infinite/unstructured loop/concurrent loop");
+    }
+
+    // Increment loop begin code.  (TODO: Infinite/while code was already
+    // generated.)
+    genFIRIncrementLoopBegin(incrementLoopNestInfo);
+
+    // Loop body code - NonLabelDoStmt and EndDoStmt code is generated here.
+    // Their genFIR calls are nops except for block management in some cases.
+    for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations())
+      genFIR(e, /*unstructuredContext=*/false);
+
+    // Loop end code. (TODO: infinite/while loop)
+    genFIRIncrementLoopEnd(incrementLoopNestInfo);
+  }
+
+  /// 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));
+      return builder->createIntegerConstant(loc, controlType, 1); // step
+    };
+    for (IncrementLoopInfo &info : incrementLoopNestInfo) {
+      info.loopVariable = genLoopVariableAddress(loc, info.loopVariableSym);
+      mlir::Value lowerValue = genControlValue(info.lowerExpr, info);
+      mlir::Value upperValue = genControlValue(info.upperExpr, info);
+      info.stepValue = genControlValue(info.stepExpr, info);
+
+      // Structured loop - generate fir.do_loop.
+      if (info.isStructured()) {
+        info.doLoop = builder->create<fir::DoLoopOp>(
+            loc, lowerValue, upperValue, info.stepValue, info.isUnordered,
+            /*finalCountValue=*/!info.isUnordered);
+        builder->setInsertionPointToStart(info.doLoop.getBody());
+        // Update the loop variable value, as it may have non-index references.
+        mlir::Value value = builder->createConvert(
+            loc, info.getLoopVariableType(), info.doLoop.getInductionVar());
+        builder->create<fir::StoreOp>(loc, value, info.loopVariable);
+        // TODO: Mask expr
+        // TODO: handle Locality Spec
+        continue;
+      }
+      // TODO: Unstructured loop handling
+    }
+  }
+
+  /// Generate FIR to end a structured or unstructured increment loop nest.
+  void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
+    assert(!incrementLoopNestInfo.empty() && "empty loop nest");
+    mlir::Location loc = toLocation();
+    for (auto it = incrementLoopNestInfo.rbegin(),
+              rend = incrementLoopNestInfo.rend();
+         it != rend; ++it) {
+      IncrementLoopInfo &info = *it;
+      if (info.isStructured()) {
+        // End fir.do_loop.
+        if (!info.isUnordered) {
+          builder->setInsertionPointToEnd(info.doLoop.getBody());
+          mlir::Value result = builder->create<mlir::arith::AddIOp>(
+              loc, info.doLoop.getInductionVar(), info.doLoop.getStep());
+          builder->create<fir::ResultOp>(loc, result);
+        }
+        builder->setInsertionPointAfter(info.doLoop);
+        if (info.isUnordered)
+          continue;
+        // The loop control variable may be used after loop execution.
+        mlir::Value lcv = builder->createConvert(
+            loc, info.getLoopVariableType(), info.doLoop.getResult(0));
+        builder->create<fir::StoreOp>(loc, lcv, info.loopVariable);
+        continue;
+      }
+
+      // TODO: Unstructured loop
+    }
   }
 
   /// Generate structured or unstructured FIR for an IF construct.
@@ -2074,10 +2220,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     genFIRBranch(getEval().controlSuccessor->block);
   }
 
-  void genFIR(const Fortran::parser::EndDoStmt &) {
-    TODO(toLocation(), "EndDoStmt lowering");
-  }
-
   // Nop statements - No code, or code is generated at the construct level.
   void genFIR(const Fortran::parser::AssociateStmt &) {}       // nop
   void genFIR(const Fortran::parser::CaseStmt &) {}            // nop
@@ -2085,6 +2227,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   void genFIR(const Fortran::parser::ElseIfStmt &) {}          // nop
   void genFIR(const Fortran::parser::ElseStmt &) {}            // nop
   void genFIR(const Fortran::parser::EndAssociateStmt &) {}    // nop
+  void genFIR(const Fortran::parser::EndDoStmt &) {}           // nop
   void genFIR(const Fortran::parser::EndFunctionStmt &) {}     // nop
   void genFIR(const Fortran::parser::EndIfStmt &) {}           // nop
   void genFIR(const Fortran::parser::EndMpSubprogramStmt &) {} // nop
@@ -2093,10 +2236,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   void genFIR(const Fortran::parser::EntryStmt &) {}           // nop
   void genFIR(const Fortran::parser::IfStmt &) {}              // nop
   void genFIR(const Fortran::parser::IfThenStmt &) {}          // nop
-
-  void genFIR(const Fortran::parser::NonLabelDoStmt &) {
-    TODO(toLocation(), "NonLabelDoStmt lowering");
-  }
+  void genFIR(const Fortran::parser::NonLabelDoStmt &) {}      // nop
 
   void genFIR(const Fortran::parser::OmpEndLoopDirective &) {
     TODO(toLocation(), "OmpEndLoopDirective lowering");

diff  --git a/flang/test/Lower/do_loop.f90 b/flang/test/Lower/do_loop.f90
new file mode 100644
index 0000000000000..6ef6de2c17eb1
--- /dev/null
+++ b/flang/test/Lower/do_loop.f90
@@ -0,0 +1,209 @@
+! RUN: bbc -emit-fir -o - %s | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -o - %s | FileCheck %s
+
+! 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.
+
+! Test a simple loop with the final value of the index variable read outside the loop
+! CHECK-LABEL: simple_loop
+subroutine simple_loop
+  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_loopEi"}
+  integer :: i
+
+  ! CHECK: %[[C1:.*]] = arith.constant 1 : i32
+  ! CHECK: %[[C1_CVT:.*]] = fir.convert %c1_i32 : (i32) -> index
+  ! CHECK: %[[C5:.*]] = arith.constant 5 : i32
+  ! CHECK: %[[C5_CVT:.*]] = fir.convert %c5_i32 : (i32) -> index
+  ! CHECK: %[[C1:.*]] = arith.constant 1 : index
+  ! CHECK: %[[LI_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[C1_CVT]] to %[[C5_CVT]] step %[[C1]] -> index {
+  do i=1,5
+  ! CHECK:   %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
+  ! CHECK:   fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
+  ! CHECK:   %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[C1]] : index
+  ! CHECK:  fir.result %[[LI_NEXT]] : index
+  ! CHECK: }
+  end do
+  ! CHECK: %[[LI_RES_CVT:.*]] = fir.convert %[[LI_RES]] : (index) -> i32
+  ! CHECK: fir.store %[[LI_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
+  ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
+  ! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[I]]) : (!fir.ref<i8>, i32) -> i1
+  print *, i
+end subroutine
+
+! Test a 2-nested loop with a body composed of a reduction. Values are read from a 2d array.
+! CHECK-LABEL: nested_loop
+subroutine nested_loop
+  ! CHECK: %[[ARR_REF:.*]] = fir.alloca !fir.array<5x5xi32> {bindc_name = "arr", uniq_name = "_QFnested_loopEarr"}
+  ! CHECK: %[[ASUM_REF:.*]] = fir.alloca i32 {bindc_name = "asum", uniq_name = "_QFnested_loopEasum"}
+  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_loopEi"}
+  ! CHECK: %[[J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_loopEj"}
+  integer :: asum, arr(5,5)
+  integer :: i, j
+  asum = 0
+  ! CHECK: %[[S_I:.*]] = arith.constant 1 : i32
+  ! CHECK: %[[S_I_CVT:.*]] = fir.convert %[[S_I]] : (i32) -> index
+  ! 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_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_I_CVT]] to %[[E_I_CVT]] step %[[ST_I]] -> index {
+  do i=1,5
+    ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
+    ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !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_RES:.*]] = fir.do_loop %[[LJ:.*]] = %[[S_J_CVT]] to %[[E_J_CVT]] step %[[ST_J]] -> index {
+    do j=1,5
+      ! CHECK: %[[LJ_CVT:.*]] = fir.convert %[[LJ]] : (index) -> i32
+      ! CHECK: fir.store %[[LJ_CVT]] to %[[J_REF]] : !fir.ref<i32>
+      ! CHECK: %[[ASUM:.*]] = fir.load %[[ASUM_REF]] : !fir.ref<i32>
+      ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
+      ! CHECK: %[[I_CVT:.*]] = fir.convert %[[I]] : (i32) -> i64
+      ! CHECK: %[[C1_I:.*]] = arith.constant 1 : i64
+      ! CHECK: %[[I_INDX:.*]] = arith.subi %[[I_CVT]], %[[C1_I]] : i64
+      ! CHECK: %[[J:.*]] = fir.load %[[J_REF]] : !fir.ref<i32>
+      ! CHECK: %[[J_CVT:.*]] = fir.convert %[[J]] : (i32) -> i64
+      ! CHECK: %[[C1_J:.*]] = arith.constant 1 : i64
+      ! CHECK: %[[J_INDX:.*]] = arith.subi %[[J_CVT]], %[[C1_J]] : i64
+      ! CHECK: %[[ARR_IJ_REF:.*]] = fir.coordinate_of %[[ARR_REF]], %[[I_INDX]], %[[J_INDX]] : (!fir.ref<!fir.array<5x5xi32>>, i64, i64) -> !fir.ref<i32>
+      ! CHECK: %[[ARR_VAL:.*]] = fir.load %[[ARR_IJ_REF]] : !fir.ref<i32>
+      ! CHECK: %[[ASUM_NEW:.*]] = arith.addi %[[ASUM]], %[[ARR_VAL]] : i32
+      ! CHECK: fir.store %[[ASUM_NEW]] to %[[ASUM_REF]] : !fir.ref<i32>
+      asum = asum + arr(i,j)
+      ! CHECK: %[[LJ_NEXT:.*]] = arith.addi %[[LJ]], %[[ST_J]] : index
+      ! CHECK: fir.result %[[LJ_NEXT]] : index
+    ! CHECK: }
+    end do
+    ! CHECK: %[[J_RES_CVT:.*]] = fir.convert %[[J_RES]] : (index) -> i32
+    ! CHECK: fir.store %[[J_RES_CVT]] to %[[J_REF]] : !fir.ref<i32>
+    ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_I]] : index
+    ! CHECK: fir.result %[[LI_NEXT]] : index
+  ! CHECK: }
+  end do
+  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
+  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
+end subroutine
+
+! Test a downcounting loop
+! CHECK-LABEL: down_counting_loop
+subroutine down_counting_loop()
+  integer :: i
+  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFdown_counting_loopEi"}
+
+  ! CHECK: %[[C5:.*]] = arith.constant 5 : i32
+  ! CHECK: %[[C5_CVT:.*]] = fir.convert %[[C5]] : (i32) -> index
+  ! CHECK: %[[C1:.*]] = arith.constant 1 : i32
+  ! 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_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[C5_CVT]] to %[[C1_CVT]] step %[[CMINUS1_STEP_CVT]] -> index {
+  do i=5,1,-1
+  ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
+  ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
+  ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[CMINUS1_STEP_CVT]] : index
+  ! CHECK: fir.result %[[LI_NEXT]] : index
+  ! CHECK: }
+  end do
+  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
+  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
+end subroutine
+
+! Test a general loop with a variable step
+! CHECK-LABEL: loop_with_variable_step
+! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "st"}) {
+subroutine loop_with_variable_step(s,e,st)
+  integer :: s, e, st
+  ! CHECK: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<i32>
+  ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index
+  ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<i32>
+  ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index
+  ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<i32>
+  ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
+  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
+  do i=s,e,st
+  ! CHECK:  %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
+  ! CHECK:  fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
+  ! CHECK:  %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
+  ! CHECK:  fir.result %[[LI_NEXT]] : index
+  ! CHECK: }
+  end do
+  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
+  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
+end subroutine
+
+! Test usage of pointer variables as index, start, end and step variables
+! CHECK-LABEL: loop_with_pointer_variables
+! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "s", fir.target}, %[[E_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "e", fir.target}, %[[ST_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "st", fir.target}) {
+subroutine loop_with_pointer_variables(s,e,st)
+! CHECK:  %[[E_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEeptr.addr"}
+! CHECK:  %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", fir.target, uniq_name = "_QFloop_with_pointer_variablesEi"}
+! CHECK:  %[[I_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEiptr.addr"}
+! CHECK:  %[[S_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEsptr.addr"}
+! CHECK:  %[[ST_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEstptr.addr"}
+  integer, target :: i
+  integer, target :: s, e, st
+  integer, pointer :: iptr, sptr, eptr, stptr
+
+! CHECK:  %[[I_PTR:.*]] = fir.convert %[[I_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
+! CHECK:  fir.store %[[I_PTR]] to %[[I_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[S_PTR:.*]] = fir.convert %[[S_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
+! CHECK:  fir.store %[[S_PTR]] to %[[S_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[E_PTR:.*]] = fir.convert %[[E_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
+! CHECK:  fir.store %[[E_PTR]] to %[[E_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[ST_PTR:.*]] = fir.convert %[[ST_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
+! CHECK:  fir.store %[[ST_PTR]] to %[[ST_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+  iptr => i
+  sptr => s
+  eptr => e
+  stptr => st
+
+! CHECK:  %[[I_PTR:.*]] = fir.load %[[I_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[S_PTR:.*]] = fir.load %[[S_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[S:.*]] = fir.load %[[S_PTR]] : !fir.ptr<i32>
+! CHECK:  %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index
+! CHECK:  %[[E_PTR:.*]] = fir.load %[[E_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[E:.*]] = fir.load %[[E_PTR]] : !fir.ptr<i32>
+! CHECK:  %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index
+! CHECK:  %[[ST_PTR:.*]] = fir.load %[[ST_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
+! CHECK:  %[[ST:.*]] = fir.load %[[ST_PTR]] : !fir.ptr<i32>
+! CHECK:  %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
+! CHECK:  %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
+  do iptr=sptr,eptr,stptr
+! CHECK:    %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
+! CHECK:    fir.store %[[LI_CVT]] to %[[I_PTR]] : !fir.ptr<i32>
+! CHECK:    %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
+! CHECK:    fir.result %[[LI_NEXT]] : index
+  end do
+! CHECK:  }
+! CHECK:  %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
+! CHECK:  fir.store %[[I_RES_CVT:.*]] to %[[I_PTR]] : !fir.ptr<i32>
+end subroutine
+
+! Test usage of non-default integer kind for loop control and loop index variable
+! CHECK-LABEL: loop_with_non_default_integer
+! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "st"}) {
+subroutine loop_with_non_default_integer(s,e,st)
+  ! CHECK: %[[I_REF:.*]] = fir.alloca i64 {bindc_name = "i", uniq_name = "_QFloop_with_non_default_integerEi"}
+  integer(kind=8):: i
+  ! CHECK: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<i64>
+  ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i64) -> index
+  ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<i64>
+  ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i64) -> index
+  ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<i64>
+  ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i64) -> index
+  integer(kind=8) :: s, e, st
+
+  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
+  do i=s,e,st
+    ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i64
+    ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i64>
+    ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
+    ! CHECK: fir.result %[[LI_NEXT]] : index
+  end do
+  ! CHECK: }
+  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i64
+  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i64>
+end subroutine


        


More information about the flang-commits mailing list