@@ -383,7 +383,8 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
383383 // construct
384384 mlir::OpBuilder::InsertPoint unstructuredSectionsIP =
385385 firOpBuilder.saveInsertionPoint ();
386- firOpBuilder.setInsertionPointToStart (&op->getRegion (0 ).back ());
386+ mlir::Operation *lastOper = op->getRegion (0 ).back ().getTerminator ();
387+ firOpBuilder.setInsertionPoint (lastOper);
387388 lastPrivIP = firOpBuilder.saveInsertionPoint ();
388389 firOpBuilder.restoreInsertionPoint (unstructuredSectionsIP);
389390 }
@@ -2133,15 +2134,6 @@ static mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
21332134 return converter.getFirOpBuilder ().getIntegerType (loopVarTypeSize);
21342135}
21352136
2136- static void resetBeforeTerminator (fir::FirOpBuilder &firOpBuilder,
2137- mlir::Operation *storeOp,
2138- mlir::Block &block) {
2139- if (storeOp)
2140- firOpBuilder.setInsertionPointAfter (storeOp);
2141- else
2142- firOpBuilder.setInsertionPointToStart (&block);
2143- }
2144-
21452137static mlir::Operation *
21462138createAndSetPrivatizedLoopVar (Fortran::lower::AbstractConverter &converter,
21472139 mlir::Location loc, mlir::Value indexVal,
@@ -2183,11 +2175,43 @@ static void createBodyOfOp(
21832175 const llvm::SmallVector<const Fortran::semantics::Symbol *> &args = {},
21842176 bool outerCombined = false , DataSharingProcessor *dsp = nullptr ) {
21852177 fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder ();
2178+
2179+ auto insertMarker = [](fir::FirOpBuilder &builder) {
2180+ mlir::Value undef = builder.create <fir::UndefOp>(builder.getUnknownLoc (),
2181+ builder.getIndexType ());
2182+ return undef.getDefiningOp ();
2183+ };
2184+
2185+ // Find the block where the OMP terminator should go. In simple cases
2186+ // it is the single block in the operation's region. When the region
2187+ // is more complicated, especially with unstructured control flow, there
2188+ // may be multiple blocks, and some of them may have non-OMP terminators
2189+ // resulting from lowering of the code contained within the operation.
2190+ // By OpenMP rules, there should be a single exit point from the region:
2191+ // here exit means transfering control to the code following the operation.
2192+ // STOP statement is allowed and does not count as exit for the purpose of
2193+ // inserting terminators.
2194+ auto findExitBlock = [&](mlir::Region ®ion) -> mlir::Block * {
2195+ auto isTerminated = [](mlir::Block &block) -> bool {
2196+ if (block.empty ())
2197+ return false ;
2198+ return block.back ().hasTrait <mlir::OpTrait::IsTerminator>();
2199+ };
2200+
2201+ mlir::Block *exit = nullptr ;
2202+ for (auto &block : region) {
2203+ if (!isTerminated (block)) {
2204+ assert (exit == nullptr && " Multiple exit block in OpenMP region" );
2205+ exit = █
2206+ }
2207+ }
2208+ return exit;
2209+ };
2210+
21862211 // If an argument for the region is provided then create the block with that
21872212 // argument. Also update the symbol's address with the mlir argument value.
21882213 // e.g. For loops the argument is the induction variable. And all further
21892214 // uses of the induction variable should use this mlir value.
2190- mlir::Operation *storeOp = nullptr ;
21912215 if (args.size ()) {
21922216 std::size_t loopVarTypeSize = 0 ;
21932217 for (const Fortran::semantics::Symbol *arg : args)
@@ -2198,20 +2222,20 @@ static void createBodyOfOp(
21982222 firOpBuilder.createBlock (&op.getRegion (), {}, tiv, locs);
21992223 // The argument is not currently in memory, so make a temporary for the
22002224 // argument, and store it there, then bind that location to the argument.
2225+ mlir::Operation *storeOp = nullptr ;
22012226 for (auto [argIndex, argSymbol] : llvm::enumerate (args)) {
22022227 mlir::Value indexVal =
22032228 fir::getBase (op.getRegion ().front ().getArgument (argIndex));
22042229 storeOp =
22052230 createAndSetPrivatizedLoopVar (converter, loc, indexVal, argSymbol);
22062231 }
2232+ firOpBuilder.setInsertionPointAfter (storeOp);
22072233 } else {
22082234 firOpBuilder.createBlock (&op.getRegion ());
22092235 }
2210- // Set the insert for the terminator operation to go at the end of the
2211- // block - this is either empty or the block with the stores above,
2212- // the end of the block works for both.
2213- mlir::Block &block = op.getRegion ().back ();
2214- firOpBuilder.setInsertionPointToEnd (&block);
2236+
2237+ // Mark the earliest insertion point.
2238+ mlir::Operation *marker = insertMarker (firOpBuilder);
22152239
22162240 // If it is an unstructured region and is not the outer region of a combined
22172241 // construct, create empty blocks for all evaluations.
@@ -2220,37 +2244,64 @@ static void createBodyOfOp(
22202244 mlir::omp::YieldOp>(
22212245 firOpBuilder, eval.getNestedEvaluations ());
22222246
2223- // Insert the terminator.
2224- Fortran::lower::genOpenMPTerminator (firOpBuilder, op.getOperation (), loc);
2225- // Reset the insert point to before the terminator.
2226- resetBeforeTerminator (firOpBuilder, storeOp, block);
2247+ // Start with privatization, so that the lowering of the nested
2248+ // code will use the right symbols.
2249+ constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> ||
2250+ std::is_same_v<Op, mlir::omp::SimdLoopOp>;
2251+ bool privatize = clauses && !outerCombined;
22272252
2228- // Handle privatization. Do not privatize if this is the outer operation.
2229- if (clauses && !outerCombined) {
2230- constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> ||
2231- std::is_same_v<Op, mlir::omp::SimdLoopOp>;
2253+ firOpBuilder.setInsertionPoint (marker);
2254+ std::optional<DataSharingProcessor> tempDsp;
2255+ if (privatize) {
22322256 if (!dsp) {
2233- DataSharingProcessor proc (converter, *clauses, eval);
2234- proc.processStep1 ();
2235- proc.processStep2 (op, isLoop);
2236- } else {
2237- if (isLoop && args.size () > 0 )
2238- dsp->setLoopIV (converter.getSymbolAddress (*args[0 ]));
2239- dsp->processStep2 (op, isLoop);
2257+ tempDsp.emplace (converter, *clauses, eval);
2258+ tempDsp->processStep1 ();
22402259 }
2241-
2242- if (storeOp)
2243- firOpBuilder.setInsertionPointAfter (storeOp);
22442260 }
22452261
22462262 if constexpr (std::is_same_v<Op, mlir::omp::ParallelOp>) {
22472263 threadPrivatizeVars (converter, eval);
2248- if (clauses)
2264+ if (clauses) {
2265+ firOpBuilder.setInsertionPoint (marker);
22492266 ClauseProcessor (converter, *clauses).processCopyin ();
2267+ }
22502268 }
22512269
2252- if (genNested)
2270+ if (genNested) {
2271+ // genFIR(Evaluation&) tries to patch up unterminated blocks, causing
2272+ // a lot of trouble if the terminator generation is delayed past this
2273+ // point. Insert a temporary terminator here, then delete it.
2274+ firOpBuilder.setInsertionPointToEnd (&op.getRegion ().back ());
2275+ auto *temp = Fortran::lower::genOpenMPTerminator (firOpBuilder,
2276+ op.getOperation (), loc);
2277+ firOpBuilder.setInsertionPointAfter (marker);
22532278 genNestedEvaluations (converter, eval);
2279+ temp->erase ();
2280+ }
2281+
2282+ if (auto *exitBlock = findExitBlock (op.getRegion ())) {
2283+ firOpBuilder.setInsertionPointToEnd (exitBlock);
2284+ auto *term = Fortran::lower::genOpenMPTerminator (firOpBuilder,
2285+ op.getOperation (), loc);
2286+ // Only insert lastprivate code when there actually is an exit block.
2287+ // Such a block may not exist if the nested code produced an infinite
2288+ // loop (this may not make sense in production code, but a user could
2289+ // write that and we should handle it).
2290+ firOpBuilder.setInsertionPoint (term);
2291+ if (privatize) {
2292+ if (!dsp) {
2293+ assert (tempDsp.has_value ());
2294+ tempDsp->processStep2 (op, isLoop);
2295+ } else {
2296+ if (isLoop && args.size () > 0 )
2297+ dsp->setLoopIV (converter.getSymbolAddress (*args[0 ]));
2298+ dsp->processStep2 (op, isLoop);
2299+ }
2300+ }
2301+ }
2302+
2303+ firOpBuilder.setInsertionPointAfter (marker);
2304+ marker->erase ();
22542305}
22552306
22562307static void genBodyOfTargetDataOp (
@@ -3664,14 +3715,14 @@ genOMP(Fortran::lower::AbstractConverter &converter,
36643715// Public functions
36653716// ===----------------------------------------------------------------------===//
36663717
3667- void Fortran::lower::genOpenMPTerminator (fir::FirOpBuilder &builder,
3668- mlir::Operation *op,
3669- mlir::Location loc) {
3718+ mlir::Operation * Fortran::lower::genOpenMPTerminator (fir::FirOpBuilder &builder,
3719+ mlir::Operation *op,
3720+ mlir::Location loc) {
36703721 if (mlir::isa<mlir::omp::WsLoopOp, mlir::omp::ReductionDeclareOp,
36713722 mlir::omp::AtomicUpdateOp, mlir::omp::SimdLoopOp>(op))
3672- builder.create <mlir::omp::YieldOp>(loc);
3723+ return builder.create <mlir::omp::YieldOp>(loc);
36733724 else
3674- builder.create <mlir::omp::TerminatorOp>(loc);
3725+ return builder.create <mlir::omp::TerminatorOp>(loc);
36753726}
36763727
36773728void Fortran::lower::genOpenMPConstruct (
0 commit comments