diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -138,11 +138,35 @@ return converter.getFirOpBuilder().getIntegerType(loopVarTypeSize); } +/// Create empty blocks for the current region. +/// These blocks replace blocks parented to an enclosing region. +void createEmptyRegionBlocks( + fir::FirOpBuilder &firOpBuilder, + std::list &evaluationList) { + auto *region = &firOpBuilder.getRegion(); + for (auto &eval : evaluationList) { + if (eval.block) { + if (eval.block->empty()) { + eval.block->erase(); + eval.block = firOpBuilder.createBlock(region); + } else { + [[maybe_unused]] auto &terminatorOp = eval.block->back(); + assert((mlir::isa(terminatorOp) || + mlir::isa(terminatorOp)) && + "expected terminator op"); + } + } + if (eval.hasNestedEvaluations()) + createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations()); + } +} + /// Create the body (block) for an OpenMP Operation. /// /// \param [in] op - the operation the body belongs to. /// \param [inout] converter - converter to use for the clauses. /// \param [in] loc - location in source code. +/// \param [in] eval - current PFT node/evaluation. /// \oaran [in] clauses - list of clauses to process. /// \param [in] args - block arguments (induction variable[s]) for the //// region. @@ -151,14 +175,14 @@ template static void createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter, - mlir::Location &loc, + mlir::Location &loc, Fortran::lower::pft::Evaluation &eval, const Fortran::parser::OmpClauseList *clauses = nullptr, const SmallVector &args = {}, bool outerCombined = false) { - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - // If arguments for the region are provided then create the block with those - // arguments. Also update the symbol's address with the mlir argument values. - // e.g. For loops the arguments are the induction variable. And all further + auto &firOpBuilder = converter.getFirOpBuilder(); + // If an argument for the region is provided then create the block with that + // argument. Also update the symbol's address with the mlir argument value. + // e.g. For loops the argument is the induction variable. And all further // uses of the induction variable should use this mlir value. if (args.size()) { std::size_t loopVarTypeSize = 0; @@ -184,7 +208,10 @@ auto &block = op.getRegion().back(); firOpBuilder.setInsertionPointToStart(&block); - // Insert the terminator. + if (eval.lowerAsUnstructured()) + createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations()); + + // Ensure the block is well-formed by inserting terminators. if constexpr (std::is_same_v) { mlir::ValueRange results; firOpBuilder.create(loc, results); @@ -369,7 +396,7 @@ allocateOperands, allocatorOperands, /*reduction_vars=*/ValueRange(), /*reductions=*/nullptr, procBindKindAttr); - createBodyOfOp(parallelOp, converter, currentLocation, + createBodyOfOp(parallelOp, converter, currentLocation, eval, &opClauseList, /*iv=*/{}, /*isCombined=*/true); } @@ -461,26 +488,27 @@ allocateOperands, allocatorOperands, /*reduction_vars=*/ValueRange(), /*reductions=*/nullptr, procBindKindAttr); createBodyOfOp(parallelOp, converter, currentLocation, - &opClauseList); + eval, &opClauseList); } else if (blockDirective.v == llvm::omp::OMPD_master) { auto masterOp = firOpBuilder.create(currentLocation, argTy); - createBodyOfOp(masterOp, converter, currentLocation); + createBodyOfOp(masterOp, converter, currentLocation, eval); } else if (blockDirective.v == llvm::omp::OMPD_single) { auto singleOp = firOpBuilder.create( currentLocation, allocateOperands, allocatorOperands, nowaitAttr); - createBodyOfOp(singleOp, converter, currentLocation); + createBodyOfOp(singleOp, converter, currentLocation, eval); } else if (blockDirective.v == llvm::omp::OMPD_ordered) { auto orderedOp = firOpBuilder.create( currentLocation, /*simd=*/nullptr); - createBodyOfOp(orderedOp, converter, currentLocation); + createBodyOfOp(orderedOp, converter, currentLocation, + eval); } else if (blockDirective.v == llvm::omp::OMPD_task) { auto taskOp = firOpBuilder.create( currentLocation, ifClauseOperand, finalClauseOperand, untiedAttr, mergeableAttr, /*in_reduction_vars=*/ValueRange(), /*in_reductions=*/nullptr, priorityClauseOperand, allocateOperands, allocatorOperands); - createBodyOfOp(taskOp, converter, currentLocation, &opClauseList); + createBodyOfOp(taskOp, converter, currentLocation, eval, &opClauseList); } else { TODO(converter.getCurrentLocation(), "Unhandled block directive"); } @@ -644,7 +672,7 @@ wsLoopOp.nowaitAttr(firOpBuilder.getUnitAttr()); } - createBodyOfOp(wsLoopOp, converter, currentLocation, + createBodyOfOp(wsLoopOp, converter, currentLocation, eval, &wsLoopOpClauseList, iv); } @@ -688,7 +716,7 @@ firOpBuilder.getContext(), global.sym_name())); } }(); - createBodyOfOp(criticalOp, converter, currentLocation); + createBodyOfOp(criticalOp, converter, currentLocation, eval); } static void @@ -700,7 +728,7 @@ auto currentLocation = converter.getCurrentLocation(); mlir::omp::SectionOp sectionOp = firOpBuilder.create(currentLocation); - createBodyOfOp(sectionOp, converter, currentLocation); + createBodyOfOp(sectionOp, converter, currentLocation, eval); } // TODO: Add support for reduction @@ -757,14 +785,15 @@ currentLocation, /*reduction_vars*/ ValueRange(), /*reductions=*/nullptr, allocateOperands, allocatorOperands, /*nowait=*/nullptr); - createBodyOfOp(sectionsOp, converter, currentLocation); + createBodyOfOp(sectionsOp, converter, currentLocation, eval); // Sections Construct } else if (dir == llvm::omp::Directive::OMPD_sections) { auto sectionsOp = firOpBuilder.create( currentLocation, reductionVars, /*reductions = */ nullptr, allocateOperands, allocatorOperands, noWaitClauseOperand); - createBodyOfOp(sectionsOp, converter, currentLocation); + createBodyOfOp(sectionsOp, converter, currentLocation, + eval); } } diff --git a/flang/test/Lower/OpenMP/omp-unstructured.f90 b/flang/test/Lower/OpenMP/omp-unstructured.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-unstructured.f90 @@ -0,0 +1,113 @@ +! Test unstructured code adjacent to and inside OpenMP constructs. + +! RUN: bbc %s -fopenmp -o "-" | FileCheck %s + +! CHECK-LABEL: func @_QPss1{{.*}} { +! CHECK: br ^bb1 +! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 +! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 +! CHECK: ^bb2: // pred: ^bb1 +! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 +! CHECK: ^bb3: // pred: ^bb2 +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: br ^bb1 +! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 +! CHECK: omp.master { +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: omp.terminator +! CHECK: } +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: } +subroutine ss1(n) ! unstructured code followed by a structured OpenMP construct + do i = 1, 3 + if (i .eq. n) exit + print*, 'ss1-A', i + enddo + !$omp master + print*, 'ss1-B', i + !$omp end master + print* +end + +! CHECK-LABEL: func @_QPss2{{.*}} { +! CHECK: omp.master { +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: br ^bb1 +! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 +! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 +! CHECK: ^bb2: // pred: ^bb1 +! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 +! CHECK: ^bb3: // pred: ^bb2 +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: br ^bb1 +! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 +! CHECK: omp.terminator +! CHECK: } +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: } +subroutine ss2(n) ! unstructured OpenMP construct; loop exit inside construct + !$omp master + print*, 'ss2-A', n + do i = 1, 3 + if (i .eq. n) exit + print*, 'ss2-B', i + enddo + !$omp end master + print*, 'ss2-C', i + print* +end + +! CHECK-LABEL: func @_QPss3{{.*}} { +! CHECK: omp.parallel { +! CHECK: br ^bb1 +! CHECK: ^bb1: // 2 preds: ^bb0, ^bb2 +! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb3 +! CHECK: ^bb2: // pred: ^bb1 +! CHECK: omp.wsloop {{.*}} { +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.wsloop {{.*}} { +! CHECK: br ^bb1 +! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3 +! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 +! CHECK: ^bb2: // pred: ^bb1 +! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb3 +! CHECK: ^bb3: // pred: ^bb2 +! CHECK: @_FortranAioBeginExternalListOutput +! CHECK: br ^bb1 +! CHECK: ^bb4: // 2 preds: ^bb1, ^bb2 +! CHECK: omp.yield +! CHECK: } +! CHECK: br ^bb1 +! CHECK: ^bb3: // pred: ^bb1 +! CHECK: omp.terminator +! CHECK: } +! CHECK: } +subroutine ss3(n) ! nested unstructured OpenMP constructs + !$omp parallel + do i = 1, 3 + !$omp do + do k = 1, 3 + print*, 'ss3-A', k + enddo + !$omp end do + !$omp do + do j = 1, 3 + do k = 1, 3 + if (k .eq. n) exit + print*, 'ss3-B', k + enddo + enddo + !$omp end do + enddo + !$omp end parallel +end + +! CHECK-LABEL: func @_QQmain +program p + call ss1(2) + call ss2(2) + call ss3(2) +end