@@ -94,11 +94,10 @@ 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 isConcurrent = false )
97+ bool isUnordered = false )
9898 : loopVariableSym{&sym}, lowerExpr{Fortran::semantics::GetExpr (lower)},
9999 upperExpr{Fortran::semantics::GetExpr (upper)},
100- stepExpr{Fortran::semantics::GetExpr (step)},
101- isConcurrent{isConcurrent} {}
100+ stepExpr{Fortran::semantics::GetExpr (step)}, isUnordered{isUnordered} {}
102101
103102 IncrementLoopInfo (IncrementLoopInfo &&) = default ;
104103 IncrementLoopInfo &operator =(IncrementLoopInfo &&x) = default ;
@@ -121,7 +120,7 @@ struct IncrementLoopInfo {
121120 const Fortran::lower::SomeExpr *upperExpr;
122121 const Fortran::lower::SomeExpr *stepExpr;
123122 const Fortran::lower::SomeExpr *maskExpr = nullptr ;
124- bool isConcurrent;
123+ bool isUnordered; // do concurrent, forall
125124 llvm::SmallVector<const Fortran::semantics::Symbol *> localSymList;
126125 llvm::SmallVector<const Fortran::semantics::Symbol *> localInitSymList;
127126 llvm::SmallVector<
@@ -131,7 +130,7 @@ struct IncrementLoopInfo {
131130 mlir::Value loopVariable = nullptr ;
132131
133132 // Data members for structured loops.
134- mlir::Operation *loopOp = nullptr ;
133+ fir::DoLoopOp doLoop = nullptr ;
135134
136135 // Data members for unstructured loops.
137136 bool hasRealControl = false ;
@@ -1981,7 +1980,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
19811980 llvm_unreachable (" illegal reduction operator" );
19821981 }
19831982
1984- // / Collect DO CONCURRENT loop control information.
1983+ // / Collect DO CONCURRENT or FORALL loop control information.
19851984 IncrementLoopNestInfo getConcurrentControl (
19861985 const Fortran::parser::ConcurrentHeader &header,
19871986 const std::list<Fortran::parser::LocalitySpec> &localityList = {}) {
@@ -2292,14 +2291,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
22922291 mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get (
22932292 builder->getContext (), {}, /* vectorize=*/ va, {}, /* unroll*/ ua,
22942293 /* unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
2295- if (has_attrs) {
2296- if (auto loopOp = mlir::dyn_cast<fir::DoLoopOp>(info.loopOp ))
2297- loopOp.setLoopAnnotationAttr (la);
2298-
2299- if (auto doConcurrentOp =
2300- mlir::dyn_cast<fir::DoConcurrentLoopOp>(info.loopOp ))
2301- doConcurrentOp.setLoopAnnotationAttr (la);
2302- }
2294+ if (has_attrs)
2295+ info.doLoop .setLoopAnnotationAttr (la);
23032296 }
23042297
23052298 // / Generate FIR to begin a structured or unstructured increment loop nest.
@@ -2308,77 +2301,96 @@ class FirConverter : public Fortran::lower::AbstractConverter {
23082301 llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
23092302 assert (!incrementLoopNestInfo.empty () && " empty loop nest" );
23102303 mlir::Location loc = toLocation ();
2304+ mlir::Operation *boundsAndStepIP = nullptr ;
23112305 mlir::arith::IntegerOverflowFlags iofBackup{};
23122306
2313- llvm::SmallVector<mlir::Value> nestLBs;
2314- llvm::SmallVector<mlir::Value> nestUBs;
2315- llvm::SmallVector<mlir::Value> nestSts;
2316- llvm::SmallVector<mlir::Value> nestReduceOperands;
2317- llvm::SmallVector<mlir::Attribute> nestReduceAttrs;
2318- bool genDoConcurrent = false ;
2319-
23202307 for (IncrementLoopInfo &info : incrementLoopNestInfo) {
2321- genDoConcurrent = info.isStructured () && info.isConcurrent ;
2322-
2323- if (!genDoConcurrent)
2324- info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2325- info.isConcurrent );
2326-
2327- if (!getLoweringOptions ().getIntegerWrapAround ()) {
2328- iofBackup = builder->getIntegerOverflowFlags ();
2329- builder->setIntegerOverflowFlags (
2330- mlir::arith::IntegerOverflowFlags::nsw);
2331- }
2308+ mlir::Value lowerValue;
2309+ mlir::Value upperValue;
2310+ mlir::Value stepValue;
23322311
2333- nestLBs.push_back (genControlValue (info.lowerExpr , info));
2334- nestUBs.push_back (genControlValue (info.upperExpr , info));
2335- bool isConst = true ;
2336- nestSts.push_back (genControlValue (
2337- info.stepExpr , info, info.isStructured () ? nullptr : &isConst));
2312+ {
2313+ mlir::OpBuilder::InsertionGuard guard (*builder);
23382314
2339- if (!getLoweringOptions ().getIntegerWrapAround ())
2340- builder->setIntegerOverflowFlags (iofBackup);
2315+ // Set the IP before the first loop in the nest so that all nest bounds
2316+ // and step values are created outside the nest.
2317+ if (boundsAndStepIP)
2318+ builder->setInsertionPointAfter (boundsAndStepIP);
23412319
2342- // Use a temp variable for unstructured loops with non-const step.
2343- if (!isConst) {
2344- mlir::Value stepValue = nestSts.back ();
2345- info.stepVariable = builder->createTemporary (loc, stepValue.getType ());
2346- builder->create <fir::StoreOp>(loc, stepValue, info.stepVariable );
2347- }
2348-
2349- if (genDoConcurrent && nestReduceOperands.empty ()) {
2350- // Create DO CONCURRENT reduce operands and attributes
2351- for (const auto &reduceSym : info.reduceSymList ) {
2352- const fir::ReduceOperationEnum reduceOperation = reduceSym.first ;
2353- const Fortran::semantics::Symbol *sym = reduceSym.second ;
2354- fir::ExtendedValue exv = getSymbolExtendedValue (*sym, nullptr );
2355- nestReduceOperands.push_back (fir::getBase (exv));
2356- auto reduceAttr =
2357- fir::ReduceAttr::get (builder->getContext (), reduceOperation);
2358- nestReduceAttrs.push_back (reduceAttr);
2320+ info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2321+ info.isUnordered );
2322+ if (!getLoweringOptions ().getIntegerWrapAround ()) {
2323+ iofBackup = builder->getIntegerOverflowFlags ();
2324+ builder->setIntegerOverflowFlags (
2325+ mlir::arith::IntegerOverflowFlags::nsw);
2326+ }
2327+ lowerValue = genControlValue (info.lowerExpr , info);
2328+ upperValue = genControlValue (info.upperExpr , info);
2329+ bool isConst = true ;
2330+ stepValue = genControlValue (info.stepExpr , info,
2331+ info.isStructured () ? nullptr : &isConst);
2332+ if (!getLoweringOptions ().getIntegerWrapAround ())
2333+ builder->setIntegerOverflowFlags (iofBackup);
2334+ boundsAndStepIP = stepValue.getDefiningOp ();
2335+
2336+ // Use a temp variable for unstructured loops with non-const step.
2337+ if (!isConst) {
2338+ info.stepVariable =
2339+ builder->createTemporary (loc, stepValue.getType ());
2340+ boundsAndStepIP =
2341+ builder->create <fir::StoreOp>(loc, stepValue, info.stepVariable );
23592342 }
23602343 }
2361- }
23622344
2363- for (auto [info, lowerValue, upperValue, stepValue] :
2364- llvm::zip_equal (incrementLoopNestInfo, nestLBs, nestUBs, nestSts)) {
23652345 // Structured loop - generate fir.do_loop.
23662346 if (info.isStructured ()) {
2367- if (genDoConcurrent)
2368- continue ;
2369-
2370- // The loop variable is a doLoop op argument.
23712347 mlir::Type loopVarType = info.getLoopVariableType ();
2372- auto loopOp = builder->create <fir::DoLoopOp>(
2373- loc, lowerValue, upperValue, stepValue, /* unordered=*/ false ,
2374- /* finalCountValue=*/ true ,
2375- builder->createConvert (loc, loopVarType, lowerValue));
2376- info.loopOp = loopOp;
2377- builder->setInsertionPointToStart (loopOp.getBody ());
2378- mlir::Value loopValue = loopOp.getRegionIterArgs ()[0 ];
2379-
2348+ mlir::Value loopValue;
2349+ if (info.isUnordered ) {
2350+ llvm::SmallVector<mlir::Value> reduceOperands;
2351+ llvm::SmallVector<mlir::Attribute> reduceAttrs;
2352+ // Create DO CONCURRENT reduce operands and attributes
2353+ for (const auto &reduceSym : info.reduceSymList ) {
2354+ const fir::ReduceOperationEnum reduce_operation = reduceSym.first ;
2355+ const Fortran::semantics::Symbol *sym = reduceSym.second ;
2356+ fir::ExtendedValue exv = getSymbolExtendedValue (*sym, nullptr );
2357+ reduceOperands.push_back (fir::getBase (exv));
2358+ auto reduce_attr =
2359+ fir::ReduceAttr::get (builder->getContext (), reduce_operation);
2360+ reduceAttrs.push_back (reduce_attr);
2361+ }
2362+ // The loop variable value is explicitly updated.
2363+ info.doLoop = builder->create <fir::DoLoopOp>(
2364+ loc, lowerValue, upperValue, stepValue, /* unordered=*/ true ,
2365+ /* finalCountValue=*/ false , /* iterArgs=*/ std::nullopt ,
2366+ llvm::ArrayRef<mlir::Value>(reduceOperands), reduceAttrs);
2367+ builder->setInsertionPointToStart (info.doLoop .getBody ());
2368+ loopValue = builder->createConvert (loc, loopVarType,
2369+ info.doLoop .getInductionVar ());
2370+ } else {
2371+ // The loop variable is a doLoop op argument.
2372+ info.doLoop = builder->create <fir::DoLoopOp>(
2373+ loc, lowerValue, upperValue, stepValue, /* unordered=*/ false ,
2374+ /* finalCountValue=*/ true ,
2375+ builder->createConvert (loc, loopVarType, lowerValue));
2376+ builder->setInsertionPointToStart (info.doLoop .getBody ());
2377+ loopValue = info.doLoop .getRegionIterArgs ()[0 ];
2378+ }
23802379 // Update the loop variable value in case it has non-index references.
23812380 builder->create <fir::StoreOp>(loc, loopValue, info.loopVariable );
2381+ if (info.maskExpr ) {
2382+ Fortran::lower::StatementContext stmtCtx;
2383+ mlir::Value maskCond = createFIRExpr (loc, info.maskExpr , stmtCtx);
2384+ stmtCtx.finalizeAndReset ();
2385+ mlir::Value maskCondCast =
2386+ builder->createConvert (loc, builder->getI1Type (), maskCond);
2387+ auto ifOp = builder->create <fir::IfOp>(loc, maskCondCast,
2388+ /* withElseRegion=*/ false );
2389+ builder->setInsertionPointToStart (&ifOp.getThenRegion ().front ());
2390+ }
2391+ if (info.hasLocalitySpecs ())
2392+ handleLocalitySpecs (info);
2393+
23822394 addLoopAnnotationAttr (info, dirs);
23832395 continue ;
23842396 }
@@ -2442,60 +2454,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
24422454 builder->restoreInsertionPoint (insertPt);
24432455 }
24442456 }
2445-
2446- if (genDoConcurrent) {
2447- auto loopWrapperOp = builder->create <fir::DoConcurrentOp>(loc);
2448- builder->setInsertionPointToStart (
2449- builder->createBlock (&loopWrapperOp.getRegion ()));
2450-
2451- for (IncrementLoopInfo &info : llvm::reverse (incrementLoopNestInfo)) {
2452- info.loopVariable = genLoopVariableAddress (loc, *info.loopVariableSym ,
2453- info.isConcurrent );
2454- }
2455-
2456- builder->setInsertionPointToEnd (loopWrapperOp.getBody ());
2457- auto loopOp = builder->create <fir::DoConcurrentLoopOp>(
2458- loc, nestLBs, nestUBs, nestSts, nestReduceOperands,
2459- nestReduceAttrs.empty ()
2460- ? nullptr
2461- : mlir::ArrayAttr::get (builder->getContext (), nestReduceAttrs),
2462- nullptr );
2463-
2464- llvm::SmallVector<mlir::Type> loopBlockArgTypes (
2465- incrementLoopNestInfo.size (), builder->getIndexType ());
2466- llvm::SmallVector<mlir::Location> loopBlockArgLocs (
2467- incrementLoopNestInfo.size (), loc);
2468- mlir::Region &loopRegion = loopOp.getRegion ();
2469- mlir::Block *loopBlock = builder->createBlock (
2470- &loopRegion, loopRegion.begin (), loopBlockArgTypes, loopBlockArgLocs);
2471- builder->setInsertionPointToStart (loopBlock);
2472-
2473- for (auto [info, blockArg] :
2474- llvm::zip_equal (incrementLoopNestInfo, loopBlock->getArguments ())) {
2475- info.loopOp = loopOp;
2476- mlir::Value loopValue =
2477- builder->createConvert (loc, info.getLoopVariableType (), blockArg);
2478- builder->create <fir::StoreOp>(loc, loopValue, info.loopVariable );
2479-
2480- if (info.maskExpr ) {
2481- Fortran::lower::StatementContext stmtCtx;
2482- mlir::Value maskCond = createFIRExpr (loc, info.maskExpr , stmtCtx);
2483- stmtCtx.finalizeAndReset ();
2484- mlir::Value maskCondCast =
2485- builder->createConvert (loc, builder->getI1Type (), maskCond);
2486- auto ifOp = builder->create <fir::IfOp>(loc, maskCondCast,
2487- /* withElseRegion=*/ false );
2488- builder->setInsertionPointToStart (&ifOp.getThenRegion ().front ());
2489- }
2490- }
2491-
2492- IncrementLoopInfo &innermostInfo = incrementLoopNestInfo.back ();
2493-
2494- if (innermostInfo.hasLocalitySpecs ())
2495- handleLocalitySpecs (innermostInfo);
2496-
2497- addLoopAnnotationAttr (innermostInfo, dirs);
2498- }
24992457 }
25002458
25012459 // / Generate FIR to end a structured or unstructured increment loop nest.
@@ -2512,31 +2470,29 @@ class FirConverter : public Fortran::lower::AbstractConverter {
25122470 it != rend; ++it) {
25132471 IncrementLoopInfo &info = *it;
25142472 if (info.isStructured ()) {
2515- // End fir.do_concurent.loop .
2516- if (info.isConcurrent ) {
2517- builder->setInsertionPointAfter (info.loopOp -> getParentOp () );
2473+ // End fir.do_loop .
2474+ if (info.isUnordered ) {
2475+ builder->setInsertionPointAfter (info.doLoop );
25182476 continue ;
25192477 }
2520-
2521- // End fir.do_loop.
25222478 // Decrement tripVariable.
2523- auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp );
2524- builder->setInsertionPointToEnd (doLoopOp.getBody ());
2479+ builder->setInsertionPointToEnd (info.doLoop .getBody ());
25252480 llvm::SmallVector<mlir::Value, 2 > results;
25262481 results.push_back (builder->create <mlir::arith::AddIOp>(
2527- loc, doLoopOp.getInductionVar (), doLoopOp.getStep (), iofAttr));
2482+ loc, info.doLoop .getInductionVar (), info.doLoop .getStep (),
2483+ iofAttr));
25282484 // Step loopVariable to help optimizations such as vectorization.
25292485 // Induction variable elimination will clean up as necessary.
25302486 mlir::Value step = builder->createConvert (
2531- loc, info.getLoopVariableType (), doLoopOp .getStep ());
2487+ loc, info.getLoopVariableType (), info. doLoop .getStep ());
25322488 mlir::Value loopVar =
25332489 builder->create <fir::LoadOp>(loc, info.loopVariable );
25342490 results.push_back (
25352491 builder->create <mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
25362492 builder->create <fir::ResultOp>(loc, results);
2537- builder->setInsertionPointAfter (doLoopOp );
2493+ builder->setInsertionPointAfter (info. doLoop );
25382494 // The loop control variable may be used after the loop.
2539- builder->create <fir::StoreOp>(loc, doLoopOp .getResult (1 ),
2495+ builder->create <fir::StoreOp>(loc, info. doLoop .getResult (1 ),
25402496 info.loopVariable );
25412497 continue ;
25422498 }
0 commit comments