2727#include " flang/Parser/parse-tree.h"
2828#include " flang/Semantics/openmp-directive-sets.h"
2929#include " flang/Semantics/tools.h"
30+ #include " mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
3031#include " mlir/Dialect/OpenMP/OpenMPDialect.h"
3132#include " mlir/Dialect/SCF/IR/SCF.h"
3233#include " mlir/Transforms/RegionUtils.h"
@@ -385,7 +386,8 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
385386 // construct
386387 mlir::OpBuilder::InsertPoint unstructuredSectionsIP =
387388 firOpBuilder.saveInsertionPoint ();
388- firOpBuilder.setInsertionPointToStart (&op->getRegion (0 ).back ());
389+ mlir::Operation *lastOper = op->getRegion (0 ).back ().getTerminator ();
390+ firOpBuilder.setInsertionPoint (lastOper);
389391 lastPrivIP = firOpBuilder.saveInsertionPoint ();
390392 firOpBuilder.restoreInsertionPoint (unstructuredSectionsIP);
391393 }
@@ -2206,15 +2208,6 @@ static mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
22062208 return converter.getFirOpBuilder ().getIntegerType (loopVarTypeSize);
22072209}
22082210
2209- static void resetBeforeTerminator (fir::FirOpBuilder &firOpBuilder,
2210- mlir::Operation *storeOp,
2211- mlir::Block &block) {
2212- if (storeOp)
2213- firOpBuilder.setInsertionPointAfter (storeOp);
2214- else
2215- firOpBuilder.setInsertionPointToStart (&block);
2216- }
2217-
22182211static mlir::Operation *
22192212createAndSetPrivatizedLoopVar (Fortran::lower::AbstractConverter &converter,
22202213 mlir::Location loc, mlir::Value indexVal,
@@ -2257,11 +2250,17 @@ static void createBodyOfOp(
22572250 const llvm::SmallVector<const Fortran::semantics::Symbol *> &args = {},
22582251 bool outerCombined = false , DataSharingProcessor *dsp = nullptr ) {
22592252 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
2253+
2254+ auto insertMarker = [](fir::FirOpBuilder &builder) {
2255+ mlir::Value undef = builder.create <fir::UndefOp>(builder.getUnknownLoc (),
2256+ builder.getIndexType ());
2257+ return undef.getDefiningOp ();
2258+ };
2259+
22602260 // If an argument for the region is provided then create the block with that
22612261 // argument. Also update the symbol's address with the mlir argument value.
22622262 // e.g. For loops the argument is the induction variable. And all further
22632263 // uses of the induction variable should use this mlir value.
2264- mlir::Operation *storeOp = nullptr ;
22652264 if (args.size ()) {
22662265 std::size_t loopVarTypeSize = 0 ;
22672266 for (const Fortran::semantics::Symbol *arg : args)
@@ -2272,20 +2271,20 @@ static void createBodyOfOp(
22722271 firOpBuilder.createBlock (&op.getRegion (), {}, tiv, locs);
22732272 // The argument is not currently in memory, so make a temporary for the
22742273 // argument, and store it there, then bind that location to the argument.
2274+ mlir::Operation *storeOp = nullptr ;
22752275 for (auto [argIndex, argSymbol] : llvm::enumerate (args)) {
22762276 mlir::Value indexVal =
22772277 fir::getBase (op.getRegion ().front ().getArgument (argIndex));
22782278 storeOp =
22792279 createAndSetPrivatizedLoopVar (converter, loc, indexVal, argSymbol);
22802280 }
2281+ firOpBuilder.setInsertionPointAfter (storeOp);
22812282 } else {
22822283 firOpBuilder.createBlock (&op.getRegion ());
22832284 }
2284- // Set the insert for the terminator operation to go at the end of the
2285- // block - this is either empty or the block with the stores above,
2286- // the end of the block works for both.
2287- mlir::Block &block = op.getRegion ().back ();
2288- firOpBuilder.setInsertionPointToEnd (&block);
2285+
2286+ // Mark the earliest insertion point.
2287+ mlir::Operation *marker = insertMarker (firOpBuilder);
22892288
22902289 // If it is an unstructured region and is not the outer region of a combined
22912290 // construct, create empty blocks for all evaluations.
@@ -2294,37 +2293,100 @@ static void createBodyOfOp(
22942293 mlir::omp::YieldOp>(
22952294 firOpBuilder, eval.getNestedEvaluations ());
22962295
2297- // Insert the terminator.
2298- Fortran::lower::genOpenMPTerminator (firOpBuilder, op.getOperation (), loc);
2299- // Reset the insert point to before the terminator.
2300- resetBeforeTerminator (firOpBuilder, storeOp, block);
2296+ // Start with privatization, so that the lowering of the nested
2297+ // code will use the right symbols.
2298+ constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> ||
2299+ std::is_same_v<Op, mlir::omp::SimdLoopOp>;
2300+ bool privatize = clauses && !outerCombined;
23012301
2302- // Handle privatization. Do not privatize if this is the outer operation.
2303- if (clauses && !outerCombined) {
2304- constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> ||
2305- std::is_same_v<Op, mlir::omp::SimdLoopOp>;
2302+ firOpBuilder.setInsertionPoint (marker);
2303+ std::optional<DataSharingProcessor> tempDsp;
2304+ if (privatize) {
23062305 if (!dsp) {
2307- DataSharingProcessor proc (converter, *clauses, eval);
2308- proc.processStep1 ();
2309- proc.processStep2 (op, isLoop);
2310- } else {
2311- if (isLoop && args.size () > 0 )
2312- dsp->setLoopIV (converter.getSymbolAddress (*args[0 ]));
2313- dsp->processStep2 (op, isLoop);
2306+ tempDsp.emplace (converter, *clauses, eval);
2307+ tempDsp->processStep1 ();
23142308 }
2315-
2316- if (storeOp)
2317- firOpBuilder.setInsertionPointAfter (storeOp);
23182309 }
23192310
23202311 if constexpr (std::is_same_v<Op, mlir::omp::ParallelOp>) {
23212312 threadPrivatizeVars (converter, eval);
2322- if (clauses)
2313+ if (clauses) {
2314+ firOpBuilder.setInsertionPoint (marker);
23232315 ClauseProcessor (converter, *clauses).processCopyin ();
2316+ }
23242317 }
23252318
2326- if (genNested)
2319+ if (genNested) {
2320+ // genFIR(Evaluation&) tries to patch up unterminated blocks, causing
2321+ // a lot of trouble if the terminator generation is delayed past this
2322+ // point. Insert a temporary terminator here, then delete it.
2323+ firOpBuilder.setInsertionPointToEnd (&op.getRegion ().back ());
2324+ auto *temp = Fortran::lower::genOpenMPTerminator (firOpBuilder,
2325+ op.getOperation (), loc);
2326+ firOpBuilder.setInsertionPointAfter (marker);
23272327 genNestedEvaluations (converter, eval);
2328+ temp->erase ();
2329+ }
2330+
2331+ // Get or create a unique exiting block from the given region, or
2332+ // return nullptr if there is no exiting block.
2333+ auto getUniqueExit = [&](mlir::Region ®ion) -> mlir::Block * {
2334+ // Find the blocks where the OMP terminator should go. In simple cases
2335+ // it is the single block in the operation's region. When the region
2336+ // is more complicated, especially with unstructured control flow, there
2337+ // may be multiple blocks, and some of them may have non-OMP terminators
2338+ // resulting from lowering of the code contained within the operation.
2339+ // All the remaining blocks are potential exit points from the op's region.
2340+ //
2341+ // Explicit control flow cannot exit any OpenMP region (other than via
2342+ // STOP), and that is enforced by semantic checks prior to lowering. STOP
2343+ // statements are lowered to a function call.
2344+
2345+ // Collect unterminated blocks.
2346+ llvm::SmallVector<mlir::Block *> exits;
2347+ for (mlir::Block &b : region) {
2348+ if (b.empty () || !b.back ().hasTrait <mlir::OpTrait::IsTerminator>())
2349+ exits.push_back (&b);
2350+ }
2351+
2352+ if (exits.empty ())
2353+ return nullptr ;
2354+ // If there already is a unique exiting block, do not create another one.
2355+ // Additionally, some ops (e.g. omp.sections) require only 1 block in
2356+ // its region.
2357+ if (exits.size () == 1 )
2358+ return exits[0 ];
2359+ mlir::Block *exit = firOpBuilder.createBlock (®ion);
2360+ for (mlir::Block *b : exits) {
2361+ firOpBuilder.setInsertionPointToEnd (b);
2362+ firOpBuilder.create <mlir::cf::BranchOp>(loc, exit);
2363+ }
2364+ return exit;
2365+ };
2366+
2367+ if (auto *exitBlock = getUniqueExit (op.getRegion ())) {
2368+ firOpBuilder.setInsertionPointToEnd (exitBlock);
2369+ auto *term = Fortran::lower::genOpenMPTerminator (firOpBuilder,
2370+ op.getOperation (), loc);
2371+ // Only insert lastprivate code when there actually is an exit block.
2372+ // Such a block may not exist if the nested code produced an infinite
2373+ // loop (this may not make sense in production code, but a user could
2374+ // write that and we should handle it).
2375+ firOpBuilder.setInsertionPoint (term);
2376+ if (privatize) {
2377+ if (!dsp) {
2378+ assert (tempDsp.has_value ());
2379+ tempDsp->processStep2 (op, isLoop);
2380+ } else {
2381+ if (isLoop && args.size () > 0 )
2382+ dsp->setLoopIV (converter.getSymbolAddress (*args[0 ]));
2383+ dsp->processStep2 (op, isLoop);
2384+ }
2385+ }
2386+ }
2387+
2388+ firOpBuilder.setInsertionPointAfter (marker);
2389+ marker->erase ();
23282390}
23292391
23302392static void genBodyOfTargetDataOp (
@@ -3756,14 +3818,14 @@ genOMP(Fortran::lower::AbstractConverter &converter,
37563818// Public functions
37573819// ===----------------------------------------------------------------------===//
37583820
3759- void Fortran::lower::genOpenMPTerminator (fir::FirOpBuilder &builder,
3760- mlir::Operation *op,
3761- mlir::Location loc) {
3821+ mlir::Operation * Fortran::lower::genOpenMPTerminator (fir::FirOpBuilder &builder,
3822+ mlir::Operation *op,
3823+ mlir::Location loc) {
37623824 if (mlir::isa<mlir::omp::WsLoopOp, mlir::omp::ReductionDeclareOp,
37633825 mlir::omp::AtomicUpdateOp, mlir::omp::SimdLoopOp>(op))
3764- builder.create <mlir::omp::YieldOp>(loc);
3826+ return builder.create <mlir::omp::YieldOp>(loc);
37653827 else
3766- builder.create <mlir::omp::TerminatorOp>(loc);
3828+ return builder.create <mlir::omp::TerminatorOp>(loc);
37673829}
37683830
37693831void Fortran::lower::genOpenMPConstruct (
0 commit comments