@@ -94,10 +94,11 @@ struct IncrementLoopInfo {
9494 template <typename T>
9595 explicit IncrementLoopInfo (Fortran::semantics::Symbol &sym, const T &lower,
9696 const T &upper, const std::optional<T> &step,
97- bool isUnordered = false )
97+ bool isConcurrent = false )
9898 : loopVariableSym{&sym}, lowerExpr{Fortran::semantics::GetExpr (lower)},
9999 upperExpr{Fortran::semantics::GetExpr (upper)},
100- stepExpr{Fortran::semantics::GetExpr (step)}, isUnordered{isUnordered} {}
100+ stepExpr{Fortran::semantics::GetExpr (step)},
101+ isConcurrent{isConcurrent} {}
101102
102103 IncrementLoopInfo (IncrementLoopInfo &&) = default ;
103104 IncrementLoopInfo &operator =(IncrementLoopInfo &&x) = default ;
@@ -120,7 +121,7 @@ struct IncrementLoopInfo {
120121 const Fortran::lower::SomeExpr *upperExpr;
121122 const Fortran::lower::SomeExpr *stepExpr;
122123 const Fortran::lower::SomeExpr *maskExpr = nullptr ;
123- bool isUnordered; // do concurrent, forall
124+ bool isConcurrent;
124125 llvm::SmallVector<const Fortran::semantics::Symbol *> localSymList;
125126 llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
126127 llvm::SmallVector<
@@ -130,7 +131,7 @@ struct IncrementLoopInfo {
130131 mlir::Value loopVariable = nullptr ;
131132
132133 // Data members for structured loops.
133- fir::DoLoopOp doLoop = nullptr ;
134+ mlir::Operation *loopOp = nullptr ;
134135
135136 // Data members for unstructured loops.
136137 bool hasRealControl = false ;
@@ -1981,7 +1982,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
19811982 llvm_unreachable (" illegal reduction operator" );
19821983 }
19831984
1984- // / Collect DO CONCURRENT or FORALL loop control information.
1985+ // / Collect DO CONCURRENT loop control information.
19851986 IncrementLoopNestInfo getConcurrentControl (
19861987 const Fortran::parser::ConcurrentHeader &header,
19871988 const std::list<Fortran::parser::LocalitySpec> &localityList = {}) {
@@ -2292,8 +2293,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
22922293 mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get (
22932294 builder->getContext (), {}, /* vectorize=*/ va, {}, /* unroll*/ ua,
22942295 /* unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
2295- if (has_attrs)
2296- info.doLoop .setLoopAnnotationAttr (la);
2296+ if (has_attrs) {
2297+ if (auto loopOp = mlir::dyn_cast<fir::DoLoopOp>(info.loopOp ))
2298+ loopOp.setLoopAnnotationAttr (la);
2299+
2300+ if (auto doConcurrentOp =
2301+ mlir::dyn_cast<fir::DoConcurrentLoopOp>(info.loopOp ))
2302+ doConcurrentOp.setLoopAnnotationAttr (la);
2303+ }
22972304 }
22982305
22992306 // / Generate FIR to begin a structured or unstructured increment loop nest.
@@ -2302,96 +2309,77 @@ class FirConverter : public Fortran::lower::AbstractConverter {
23022309 llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
23032310 assert (!incrementLoopNestInfo.empty () && " empty loop nest" );
23042311 mlir::Location loc = toLocation ();
2305- mlir::Operation *boundsAndStepIP = nullptr ;
23062312 mlir::arith::IntegerOverflowFlags iofBackup{};
23072313
2314+ llvm::SmallVector<mlir::Value> nestLBs;
2315+ llvm::SmallVector<mlir::Value> nestUBs;
2316+ llvm::SmallVector<mlir::Value> nestSts;
2317+ llvm::SmallVector<mlir::Value> nestReduceOperands;
2318+ llvm::SmallVector<mlir::Attribute> nestReduceAttrs;
2319+ bool genDoConcurrent = false ;
2320+
23082321 for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2309- mlir::Value lowerValue;
2310- mlir::Value upperValue;
2311- mlir::Value stepValue;
2322+ genDoConcurrent = info.isStructured () && info.isConcurrent ;
23122323
2313- {
2314- mlir::OpBuilder::InsertionGuard guard (*builder);
2324+ if (!genDoConcurrent)
2325+ info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2326+ info.isConcurrent );
23152327
2316- // Set the IP before the first loop in the nest so that all nest bounds
2317- // and step values are created outside the nest.
2318- if (boundsAndStepIP)
2319- builder->setInsertionPointAfter (boundsAndStepIP);
2328+ if (!getLoweringOptions ().getIntegerWrapAround ()) {
2329+ iofBackup = builder->getIntegerOverflowFlags ();
2330+ builder->setIntegerOverflowFlags (
2331+ mlir::arith::IntegerOverflowFlags::nsw);
2332+ }
23202333
2321- info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2322- info.isUnordered );
2323- if (!getLoweringOptions ().getIntegerWrapAround ()) {
2324- iofBackup = builder->getIntegerOverflowFlags ();
2325- builder->setIntegerOverflowFlags (
2326- mlir::arith::IntegerOverflowFlags::nsw);
2327- }
2328- lowerValue = genControlValue (info.lowerExpr , info);
2329- upperValue = genControlValue (info.upperExpr , info);
2330- bool isConst = true ;
2331- stepValue = genControlValue (info.stepExpr , info,
2332- info.isStructured () ? nullptr : &isConst);
2333- if (!getLoweringOptions ().getIntegerWrapAround ())
2334- builder->setIntegerOverflowFlags (iofBackup);
2335- boundsAndStepIP = stepValue.getDefiningOp ();
2336-
2337- // Use a temp variable for unstructured loops with non-const step.
2338- if (!isConst) {
2339- info.stepVariable =
2340- builder->createTemporary (loc, stepValue.getType ());
2341- boundsAndStepIP =
2342- builder->create <fir::StoreOp>(loc, stepValue, info.stepVariable );
2334+ nestLBs.push_back (genControlValue (info.lowerExpr , info));
2335+ nestUBs.push_back (genControlValue (info.upperExpr , info));
2336+ bool isConst = true ;
2337+ nestSts.push_back (genControlValue (
2338+ info.stepExpr , info, info.isStructured () ? nullptr : &isConst));
2339+
2340+ if (!getLoweringOptions ().getIntegerWrapAround ())
2341+ builder->setIntegerOverflowFlags (iofBackup);
2342+
2343+ // Use a temp variable for unstructured loops with non-const step.
2344+ if (!isConst) {
2345+ mlir::Value stepValue = nestSts.back ();
2346+ info.stepVariable = builder->createTemporary (loc, stepValue.getType ());
2347+ builder->create <fir::StoreOp>(loc, stepValue, info.stepVariable );
2348+ }
2349+
2350+ if (genDoConcurrent && nestReduceOperands.empty ()) {
2351+ // Create DO CONCURRENT reduce operands and attributes
2352+ for (const auto &reduceSym : info.reduceSymList ) {
2353+ const fir::ReduceOperationEnum reduceOperation = reduceSym.first ;
2354+ const Fortran::semantics::Symbol *sym = reduceSym.second ;
2355+ fir::ExtendedValue exv = getSymbolExtendedValue (*sym, nullptr );
2356+ nestReduceOperands.push_back (fir::getBase (exv));
2357+ auto reduceAttr =
2358+ fir::ReduceAttr::get (builder->getContext (), reduceOperation);
2359+ nestReduceAttrs.push_back (reduceAttr);
23432360 }
23442361 }
2362+ }
23452363
2364+ for (auto [info, lowerValue, upperValue, stepValue] :
2365+ llvm::zip_equal (incrementLoopNestInfo, nestLBs, nestUBs, nestSts)) {
23462366 // Structured loop - generate fir.do_loop.
23472367 if (info.isStructured ()) {
2368+ if (genDoConcurrent)
2369+ continue ;
2370+
2371+ // The loop variable is a doLoop op argument.
23482372 mlir::Type loopVarType = info.getLoopVariableType ();
2349- mlir::Value loopValue;
2350- if (info.isUnordered ) {
2351- llvm::SmallVector<mlir::Value> reduceOperands;
2352- llvm::SmallVector<mlir::Attribute> reduceAttrs;
2353- // Create DO CONCURRENT reduce operands and attributes
2354- for (const auto &reduceSym : info.reduceSymList ) {
2355- const fir::ReduceOperationEnum reduce_operation = reduceSym.first ;
2356- const Fortran::semantics::Symbol *sym = reduceSym.second ;
2357- fir::ExtendedValue exv = getSymbolExtendedValue (*sym, nullptr );
2358- reduceOperands.push_back (fir::getBase (exv));
2359- auto reduce_attr =
2360- fir::ReduceAttr::get (builder->getContext (), reduce_operation);
2361- reduceAttrs.push_back (reduce_attr);
2362- }
2363- // The loop variable value is explicitly updated.
2364- info.doLoop = builder->create <fir::DoLoopOp>(
2365- loc, lowerValue, upperValue, stepValue, /* unordered=*/ true ,
2366- /* finalCountValue=*/ false , /* iterArgs=*/ std::nullopt ,
2367- llvm::ArrayRef<mlir::Value>(reduceOperands), reduceAttrs);
2368- builder->setInsertionPointToStart (info.doLoop .getBody ());
2369- loopValue = builder->createConvert (loc, loopVarType,
2370- info.doLoop .getInductionVar ());
2371- } else {
2372- // The loop variable is a doLoop op argument.
2373- info.doLoop = builder->create <fir::DoLoopOp>(
2374- loc, lowerValue, upperValue, stepValue, /* unordered=*/ false ,
2375- /* finalCountValue=*/ true ,
2376- builder->createConvert (loc, loopVarType, lowerValue));
2377- builder->setInsertionPointToStart (info.doLoop .getBody ());
2378- loopValue = info.doLoop .getRegionIterArgs ()[0 ];
2379- }
2373+ auto loopOp = builder->create <fir::DoLoopOp>(
2374+ loc, lowerValue, upperValue, stepValue, /* unordered=*/ false ,
2375+ /* finalCountValue=*/ true ,
2376+ builder->createConvert (loc, loopVarType, lowerValue));
2377+ info.loopOp = loopOp;
2378+ builder->setInsertionPointToStart (loopOp.getBody ());
2379+ mlir::Value loopValue = loopOp.getRegionIterArgs ()[0 ];
2380+
23802381 // Update the loop variable value in case it has non-index references.
23812382 builder->create <fir::StoreOp>(loc, loopValue, info.loopVariable );
2382- if (info.maskExpr ) {
2383- Fortran::lower::StatementContext stmtCtx;
2384- mlir::Value maskCond = createFIRExpr (loc, info.maskExpr , stmtCtx);
2385- stmtCtx.finalizeAndReset ();
2386- mlir::Value maskCondCast =
2387- builder->createConvert (loc, builder->getI1Type (), maskCond);
2388- auto ifOp = builder->create <fir::IfOp>(loc, maskCondCast,
2389- /* withElseRegion=*/ false );
2390- builder->setInsertionPointToStart (&ifOp.getThenRegion ().front ());
2391- }
2392- if (info.hasLocalitySpecs ())
2393- handleLocalitySpecs (info);
2394-
23952383 addLoopAnnotationAttr (info, dirs);
23962384 continue ;
23972385 }
@@ -2455,6 +2443,60 @@ class FirConverter : public Fortran::lower::AbstractConverter {
24552443 builder->restoreInsertionPoint (insertPt);
24562444 }
24572445 }
2446+
2447+ if (genDoConcurrent) {
2448+ auto loopWrapperOp = builder->create <fir::DoConcurrentOp>(loc);
2449+ builder->setInsertionPointToStart (
2450+ builder->createBlock (&loopWrapperOp.getRegion ()));
2451+
2452+ for (IncrementLoopInfo &info : llvm::reverse (incrementLoopNestInfo)) {
2453+ info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2454+ info.isConcurrent );
2455+ }
2456+
2457+ builder->setInsertionPointToEnd (loopWrapperOp.getBody ());
2458+ auto loopOp = builder->create <fir::DoConcurrentLoopOp>(
2459+ loc, nestLBs, nestUBs, nestSts, nestReduceOperands,
2460+ nestReduceAttrs.empty ()
2461+ ? nullptr
2462+ : mlir::ArrayAttr::get (builder->getContext (), nestReduceAttrs),
2463+ nullptr );
2464+
2465+ llvm::SmallVector<mlir::Type> loopBlockArgTypes (
2466+ incrementLoopNestInfo.size (), builder->getIndexType ());
2467+ llvm::SmallVector<mlir::Location> loopBlockArgLocs (
2468+ incrementLoopNestInfo.size (), loc);
2469+ mlir::Region &loopRegion = loopOp.getRegion ();
2470+ mlir::Block *loopBlock = builder->createBlock (
2471+ &loopRegion, loopRegion.begin (), loopBlockArgTypes, loopBlockArgLocs);
2472+ builder->setInsertionPointToStart (loopBlock);
2473+
2474+ for (auto [info, blockArg] :
2475+ llvm::zip_equal (incrementLoopNestInfo, loopBlock->getArguments ())) {
2476+ info.loopOp = loopOp;
2477+ mlir::Value loopValue =
2478+ builder->createConvert (loc, info.getLoopVariableType (), blockArg);
2479+ builder->create <fir::StoreOp>(loc, loopValue, info.loopVariable );
2480+
2481+ if (info.maskExpr ) {
2482+ Fortran::lower::StatementContext stmtCtx;
2483+ mlir::Value maskCond = createFIRExpr (loc, info.maskExpr , stmtCtx);
2484+ stmtCtx.finalizeAndReset ();
2485+ mlir::Value maskCondCast =
2486+ builder->createConvert (loc, builder->getI1Type (), maskCond);
2487+ auto ifOp = builder->create <fir::IfOp>(loc, maskCondCast,
2488+ /* withElseRegion=*/ false );
2489+ builder->setInsertionPointToStart (&ifOp.getThenRegion ().front ());
2490+ }
2491+ }
2492+
2493+ IncrementLoopInfo &innermostInfo = incrementLoopNestInfo.back ();
2494+
2495+ if (innermostInfo.hasLocalitySpecs ())
2496+ handleLocalitySpecs (innermostInfo);
2497+
2498+ addLoopAnnotationAttr (innermostInfo, dirs);
2499+ }
24582500 }
24592501
24602502 // / Generate FIR to end a structured or unstructured increment loop nest.
@@ -2471,29 +2513,31 @@ class FirConverter : public Fortran::lower::AbstractConverter {
24712513 it != rend; ++it) {
24722514 IncrementLoopInfo &info = *it;
24732515 if (info.isStructured ()) {
2474- // End fir.do_loop .
2475- if (info.isUnordered ) {
2476- builder->setInsertionPointAfter (info.doLoop );
2516+ // End fir.do_concurent.loop .
2517+ if (info.isConcurrent ) {
2518+ builder->setInsertionPointAfter (info.loopOp -> getParentOp () );
24772519 continue ;
24782520 }
2521+
2522+ // End fir.do_loop.
24792523 // Decrement tripVariable.
2480- builder->setInsertionPointToEnd (info.doLoop .getBody ());
2524+ auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp );
2525+ builder->setInsertionPointToEnd (doLoopOp.getBody ());
24812526 llvm::SmallVector<mlir::Value, 2 > results;
24822527 results.push_back (builder->create <mlir::arith::AddIOp>(
2483- loc, info.doLoop .getInductionVar (), info.doLoop .getStep (),
2484- iofAttr));
2528+ loc, doLoopOp.getInductionVar (), doLoopOp.getStep (), iofAttr));
24852529 // Step loopVariable to help optimizations such as vectorization.
24862530 // Induction variable elimination will clean up as necessary.
24872531 mlir::Value step = builder->createConvert (
2488- loc, info.getLoopVariableType (), info. doLoop .getStep ());
2532+ loc, info.getLoopVariableType (), doLoopOp .getStep ());
24892533 mlir::Value loopVar =
24902534 builder->create <fir::LoadOp>(loc, info.loopVariable );
24912535 results.push_back (
24922536 builder->create <mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
24932537 builder->create <fir::ResultOp>(loc, results);
2494- builder->setInsertionPointAfter (info. doLoop );
2538+ builder->setInsertionPointAfter (doLoopOp );
24952539 // The loop control variable may be used after the loop.
2496- builder->create <fir::StoreOp>(loc, info. doLoop .getResult (1 ),
2540+ builder->create <fir::StoreOp>(loc, doLoopOp .getResult (1 ),
24972541 info.loopVariable );
24982542 continue ;
24992543 }
0 commit comments