================ @@ -2223,37 +2222,100 @@ static void createBodyOfOp( mlir::omp::YieldOp>( firOpBuilder, eval.getNestedEvaluations()); - // Insert the terminator. - Fortran::lower::genOpenMPTerminator(firOpBuilder, op.getOperation(), loc); - // Reset the insert point to before the terminator. - resetBeforeTerminator(firOpBuilder, storeOp, block); + // Start with privatization, so that the lowering of the nested + // code will use the right symbols. + constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> || + std::is_same_v<Op, mlir::omp::SimdLoopOp>; + bool privatize = clauses && !outerCombined; - // Handle privatization. Do not privatize if this is the outer operation. - if (clauses && !outerCombined) { - constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsLoopOp> || - std::is_same_v<Op, mlir::omp::SimdLoopOp>; + firOpBuilder.setInsertionPoint(marker); + std::optional<DataSharingProcessor> tempDsp; + if (privatize) { if (!dsp) { - DataSharingProcessor proc(converter, *clauses, eval); - proc.processStep1(); - proc.processStep2(op, isLoop); - } else { - if (isLoop && args.size() > 0) - dsp->setLoopIV(converter.getSymbolAddress(*args[0])); - dsp->processStep2(op, isLoop); + tempDsp.emplace(converter, *clauses, eval); + tempDsp->processStep1(); } - - if (storeOp) - firOpBuilder.setInsertionPointAfter(storeOp); } if constexpr (std::is_same_v<Op, mlir::omp::ParallelOp>) { threadPrivatizeVars(converter, eval); - if (clauses) + if (clauses) { + firOpBuilder.setInsertionPoint(marker); ClauseProcessor(converter, *clauses).processCopyin(); + } } - if (genNested) + if (genNested) { + // genFIR(Evaluation&) tries to patch up unterminated blocks, causing + // a lot of trouble if the terminator generation is delayed past this + // point. Insert a temporary terminator here, then delete it. + firOpBuilder.setInsertionPointToEnd(&op.getRegion().back()); + auto *temp = Fortran::lower::genOpenMPTerminator(firOpBuilder, + op.getOperation(), loc); + firOpBuilder.setInsertionPointAfter(marker); genNestedEvaluations(converter, eval); + temp->erase(); + } + + // Get or create a unique exiting block from the given region, or + // return nullptr if there is no exiting block. + auto getUniqueExit = [&](mlir::Region ®ion) -> mlir::Block * { + // Find the blocks where the OMP terminator should go. In simple cases + // it is the single block in the operation's region. When the region + // is more complicated, especially with unstructured control flow, there + // may be multiple blocks, and some of them may have non-OMP terminators + // resulting from lowering of the code contained within the operation. + // All the remaining blocks are potential exit points from the op's region. + // + // Explicit control flow cannot exit any OpenMP region (other than via + // STOP), and that is enforced by semantic checks prior to lowering. STOP + // statements are lowered to a function call. + + // Collect unterminated blocks. + llvm::SmallVector<mlir::Block *> exits; + for (mlir::Block &b : region) { + if (b.empty() || !b.back().hasTrait<mlir::OpTrait::IsTerminator>()) + exits.push_back(&b); + } + + if (exits.empty()) + return nullptr; + // If there already is a unique exiting block, do not create another one. + // Additionally, some ops (e.g. omp.sections) require onlt 1 block in ---------------- kiranchandramohan wrote:
```suggestion // Additionally, some ops (e.g. omp.sections) require only 1 block in ``` https://github.com/llvm/llvm-project/pull/77761 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits