From b5b3e50f65ee99257041723e7645d44c1aeb1117 Mon Sep 17 00:00:00 2001 From: Kiran Chandramohan Date: Thu, 28 Apr 2022 12:20:11 +0000 Subject: [PATCH] [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 Co-authored-by: Jean Perier Co-authored-by: Val Donaldson Co-authored-by: Peter Klausler Co-authored-by: Valentin Clement --- flang/lib/Lower/Bridge.cpp | 158 ++++++++++++++++++++++++++++++-- flang/test/Lower/do_loop.f90 | 209 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+), 9 deletions(-) create mode 100644 flang/test/Lower/do_loop.f90 diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 340da68..dc4ee10 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -62,6 +62,43 @@ static llvm::cl::opt 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 + explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower, + const T &upper, const std::optional &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 @@ private: llvm::SmallSetVector seen; }; +using IncrementLoopNestInfo = llvm::SmallVector; } // namespace //===----------------------------------------------------------------------===// @@ -573,6 +611,15 @@ private: [&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 @@ private: /// - 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(); + const auto &loopControl = + std::get>(doStmt->t); + IncrementLoopNestInfo incrementLoopNestInfo; + if (const auto *bounds = std::get_if( + &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( + 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(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( + loc, info.doLoop.getInductionVar(), info.doLoop.getStep()); + builder->create(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(loc, lcv, info.loopVariable); + continue; + } + + // TODO: Unstructured loop + } } /// Generate structured or unstructured FIR for an IF construct. @@ -2074,10 +2220,6 @@ private: 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 @@ private: 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 @@ private: 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 0000000..6ef6de2 --- /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 + ! 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 + ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref + ! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[I]]) : (!fir.ref, 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 + ! 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 + ! CHECK: %[[ASUM:.*]] = fir.load %[[ASUM_REF]] : !fir.ref + ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref + ! 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 + ! 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>, i64, i64) -> !fir.ref + ! CHECK: %[[ARR_VAL:.*]] = fir.load %[[ARR_IJ_REF]] : !fir.ref + ! CHECK: %[[ASUM_NEW:.*]] = arith.addi %[[ASUM]], %[[ARR_VAL]] : i32 + ! CHECK: fir.store %[[ASUM_NEW]] to %[[ASUM_REF]] : !fir.ref + 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 + ! 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 +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 + ! 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 +end subroutine + +! Test a general loop with a variable step +! CHECK-LABEL: loop_with_variable_step +! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st"}) { +subroutine loop_with_variable_step(s,e,st) + integer :: s, e, st + ! CHECK: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref + ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index + ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref + ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index + ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref + ! 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 + ! 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 +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 {fir.bindc_name = "s", fir.target}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e", fir.target}, %[[ST_REF:.*]]: !fir.ref {fir.bindc_name = "st", fir.target}) { +subroutine loop_with_pointer_variables(s,e,st) +! CHECK: %[[E_PTR_REF:.*]] = fir.alloca !fir.ptr {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 {uniq_name = "_QFloop_with_pointer_variablesEiptr.addr"} +! CHECK: %[[S_PTR_REF:.*]] = fir.alloca !fir.ptr {uniq_name = "_QFloop_with_pointer_variablesEsptr.addr"} +! CHECK: %[[ST_PTR_REF:.*]] = fir.alloca !fir.ptr {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) -> !fir.ptr +! CHECK: fir.store %[[I_PTR]] to %[[I_PTR_REF]] : !fir.ref> +! CHECK: %[[S_PTR:.*]] = fir.convert %[[S_REF]] : (!fir.ref) -> !fir.ptr +! CHECK: fir.store %[[S_PTR]] to %[[S_PTR_REF]] : !fir.ref> +! CHECK: %[[E_PTR:.*]] = fir.convert %[[E_REF]] : (!fir.ref) -> !fir.ptr +! CHECK: fir.store %[[E_PTR]] to %[[E_PTR_REF]] : !fir.ref> +! CHECK: %[[ST_PTR:.*]] = fir.convert %[[ST_REF]] : (!fir.ref) -> !fir.ptr +! CHECK: fir.store %[[ST_PTR]] to %[[ST_PTR_REF]] : !fir.ref> + iptr => i + sptr => s + eptr => e + stptr => st + +! CHECK: %[[I_PTR:.*]] = fir.load %[[I_PTR_REF]] : !fir.ref> +! CHECK: %[[S_PTR:.*]] = fir.load %[[S_PTR_REF]] : !fir.ref> +! CHECK: %[[S:.*]] = fir.load %[[S_PTR]] : !fir.ptr +! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index +! CHECK: %[[E_PTR:.*]] = fir.load %[[E_PTR_REF]] : !fir.ref> +! CHECK: %[[E:.*]] = fir.load %[[E_PTR]] : !fir.ptr +! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index +! CHECK: %[[ST_PTR:.*]] = fir.load %[[ST_PTR_REF]] : !fir.ref> +! CHECK: %[[ST:.*]] = fir.load %[[ST_PTR]] : !fir.ptr +! 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 +! 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 +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 {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref {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 + ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i64) -> index + ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref + ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i64) -> index + ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref + ! 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 + ! 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 +end subroutine -- 2.7.4