diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h index 7f1b93c564b4c..de9abea301435 100644 --- a/flang/include/flang/Lower/PFTBuilder.h +++ b/flang/include/flang/Lower/PFTBuilder.h @@ -362,6 +362,7 @@ struct Evaluation : EvaluationVariant { bool activeConstruct{false}; // temporarily set for some constructs mlir::Block *block{nullptr}; // isNewBlock block (ActionStmt, ConstructStmt) int printIndex{0}; // (ActionStmt, ConstructStmt) evaluation index for dumps + mlir::Operation *op{nullptr}; // associated mlir operation }; using ProgramVariant = diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 0894a5903635e..02871009020dd 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2012,6 +2012,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { IncrementLoopNestInfo incrementLoopNestInfo; const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr; bool infiniteLoop = !loopControl.has_value(); + bool isConcurrent = false; if (infiniteLoop) { assert(unstructuredContext && "infinite loop must be unstructured"); startBlock(headerBlock); @@ -2042,6 +2043,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { std::get_if( &loopControl->u); assert(concurrent && "invalid DO loop variant"); + isConcurrent = true; incrementLoopNestInfo = getConcurrentControl( std::get(concurrent->t), std::get>(concurrent->t)); @@ -2070,7 +2072,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { // Increment loop begin code. (Infinite/while code was already generated.) if (!infiniteLoop && !whileCondition) - genFIRIncrementLoopBegin(incrementLoopNestInfo, doStmtEval.dirs); + genFIRIncrementLoopBegin(incrementLoopNestInfo, doStmtEval.dirs, + isConcurrent); // Loop body code. auto iter = eval.getNestedEvaluations().begin(); @@ -2128,12 +2131,26 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Generate FIR to begin a structured or unstructured increment loop nest. void genFIRIncrementLoopBegin( IncrementLoopNestInfo &incrementLoopNestInfo, - llvm::SmallVectorImpl &dirs) { + llvm::SmallVectorImpl &dirs, + bool isConcurrent) { assert(!incrementLoopNestInfo.empty() && "empty loop nest"); mlir::Location loc = toLocation(); + Fortran::lower::pft::Evaluation &eval = getEval(); + Fortran::lower::pft::Evaluation *outermostEval = nullptr; + if (isConcurrent) { + outermostEval = &eval; + while (outermostEval->parentConstruct) { + outermostEval = outermostEval->parentConstruct; + } + } + mlir::OpBuilder::InsertPoint insertPt; for (IncrementLoopInfo &info : incrementLoopNestInfo) { info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym, info.isUnordered); + if (outermostEval && outermostEval->op) { + insertPt = builder->saveInsertionPoint(); + builder->setInsertionPoint(outermostEval->op); + } mlir::Value lowerValue = genControlValue(info.lowerExpr, info); mlir::Value upperValue = genControlValue(info.upperExpr, info); bool isConst = true; @@ -2144,7 +2161,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { info.stepVariable = builder->createTemporary(loc, stepValue.getType()); builder->create(loc, stepValue, info.stepVariable); } - + if (outermostEval && outermostEval->op) + builder->restoreInsertionPoint(insertPt); // Structured loop - generate fir.do_loop. if (info.isStructured()) { mlir::Type loopVarType = info.getLoopVariableType(); @@ -2179,6 +2197,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { builder->setInsertionPointToStart(info.doLoop.getBody()); loopValue = info.doLoop.getRegionIterArgs()[0]; } + eval.op = info.doLoop; // Update the loop variable value in case it has non-index references. builder->create(loc, loopValue, info.loopVariable); if (info.maskExpr) { diff --git a/flang/test/Lower/do_concurrent.f90 b/flang/test/Lower/do_concurrent.f90 new file mode 100644 index 0000000000000..3a09ed97ebd84 --- /dev/null +++ b/flang/test/Lower/do_concurrent.f90 @@ -0,0 +1,50 @@ +! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s + +! Simple tests for structured concurrent loops with loop-control. + +pure function bar(n, m) + implicit none + integer, intent(in) :: n, m + integer :: bar + bar = n + m +end function + +subroutine sub1(n) + implicit none + integer :: n, m, i, j + integer, dimension(n) :: a +!CHECK: %[[LB1:.*]] = arith.constant 1 : i32 +!CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index +!CHECK: %[[UB1:.*]] = fir.load %5#0 : !fir.ref +!CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index +!CHECK: %[[LB2:.*]] = arith.constant 1 : i32 +!CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index +!CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs fastmath : (!fir.ref, !fir.ref) -> i32 +!CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index +!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered +!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered + do concurrent(i=1:n, j=1:bar(n*m, n/m)) + a(i) = n + end do +end subroutine + +subroutine sub2(n) + implicit none + integer :: n, m, i, j + integer, dimension(n) :: a +!CHECK: %[[LB1:.*]] = arith.constant 1 : i32 +!CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index +!CHECK: %[[UB1:.*]] = fir.load %5#0 : !fir.ref +!CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index +!CHECK: %[[LB2:.*]] = arith.constant 1 : i32 +!CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index +!CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs fastmath : (!fir.ref, !fir.ref) -> i32 +!CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index +!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered +!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered + do concurrent(i=1:n) + do concurrent(j=1:bar(n*m, n/m)) + a(i) = n + end do + end do +end subroutine