[llvm-branch-commits] [flang] [Flang][OpenMP] Add combined construct information (PR #198783)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed May 20 06:39:16 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Sergio Afonso (skatrak)
<details>
<summary>Changes</summary>
This patch adds the `omp.combined` attribute to OpenMP dialect operations following changes to the `ComposableOpInterface`.
This attribute is added to operations representing non-innermost leaf constructs of a combined construct and to standalone block-associated constructs that can be combined with their parent construct.
Changes are made to the OpenMP lowering logic, as well as the do-concurrent, workshare and workdistribute transformation passes.
---
Patch is 53.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/198783.diff
33 Files Affected:
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+56-20)
- (modified) flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp (+6-2)
- (modified) flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp (+5-1)
- (modified) flang/lib/Optimizer/OpenMP/LowerWorkshare.cpp (+7)
- (modified) flang/test/Integration/OpenMP/workshare-array-array-assign.f90 (+2-1)
- (modified) flang/test/Integration/OpenMP/workshare-axpy.f90 (+2-1)
- (modified) flang/test/Integration/OpenMP/workshare-forall-sliced-array.f90 (+2-1)
- (modified) flang/test/Integration/OpenMP/workshare-scalar-array-assign.f90 (+2-1)
- (modified) flang/test/Integration/OpenMP/workshare-scalar-array-mul.f90 (+4)
- (added) flang/test/Lower/OpenMP/compound.f90 (+1094)
- (modified) flang/test/Lower/OpenMP/multiple-entry-points.f90 (+1)
- (modified) flang/test/Lower/OpenMP/workshare.f90 (+3-3)
- (modified) flang/test/Transforms/DoConcurrent/basic_device.f90 (+3-3)
- (modified) flang/test/Transforms/DoConcurrent/basic_host.f90 (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/basic_host.mlir (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/local_device.mlir (+5-5)
- (modified) flang/test/Transforms/DoConcurrent/locality_specifiers_simple.mlir (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/non_const_bounds.f90 (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/reduce_add.mlir (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/reduce_all_regions.mlir (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/reduce_device.mlir (+4-4)
- (modified) flang/test/Transforms/DoConcurrent/reduce_device_min.f90 (+2-2)
- (modified) flang/test/Transforms/DoConcurrent/reduce_local.mlir (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/reduction_symbol_resultion.f90 (+2-2)
- (modified) flang/test/Transforms/DoConcurrent/runtime_sized_array.f90 (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 (+1-1)
- (modified) flang/test/Transforms/DoConcurrent/use_loop_bounds_in_body.f90 (+6-6)
- (modified) flang/test/Transforms/OpenMP/lower-workdistribute-doloop.mlir (+1-1)
- (modified) flang/test/Transforms/OpenMP/lower-workdistribute-fission-host.mlir (+2-2)
- (modified) flang/test/Transforms/OpenMP/lower-workdistribute-fission-target.mlir (+2-2)
- (modified) flang/test/Transforms/OpenMP/lower-workdistribute-fission.mlir (+1-1)
- (modified) flang/test/Transforms/OpenMP/lower-workdistribute-runtime-assign-scalar.mlir (+2-2)
- (modified) flang/test/Transforms/omp-function-filtering-todo.mlir (+2-2)
``````````diff
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 3db1ec256ea73..f7e26bb11bc99 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -68,6 +68,25 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
const ConstructQueue &queue,
ConstructQueue::const_iterator item);
+/// Return the directive that is immediately nested inside of the given
+/// \c parent evaluation, if it is its only non-end-statement nested evaluation
+/// and it represents an OpenMP construct.
+lower::pft::Evaluation *
+extractOnlyOmpNestedEval(lower::pft::Evaluation &parent) {
+ if (!parent.hasNestedEvaluations())
+ return nullptr;
+
+ auto &nested{parent.getFirstNestedEvaluation()};
+ if (!nested.isA<parser::OpenMPConstruct>())
+ return nullptr;
+
+ for (auto &sibling : parent.getNestedEvaluations())
+ if (&sibling != &nested && !sibling.isEndStmt())
+ return nullptr;
+
+ return &nested;
+}
+
namespace {
/// Structure holding information that is needed to pass host-evaluated
/// information to later lowering stages.
@@ -298,25 +317,6 @@ class OpenMPPatternProcessor {
}
}
- /// Return the directive that is immediately nested inside of the given
- /// \c parent evaluation, if it is its only non-end-statement nested
- /// evaluation and it represents an OpenMP construct.
- lower::pft::Evaluation *
- extractOnlyOmpNestedEval(lower::pft::Evaluation &parent) {
- if (!parent.hasNestedEvaluations())
- return nullptr;
-
- auto &nested{parent.getFirstNestedEvaluation()};
- if (!nested.isA<parser::OpenMPConstruct>())
- return nullptr;
-
- for (auto &sibling : parent.getNestedEvaluations())
- if (&sibling != &nested && !sibling.isEndStmt())
- return nullptr;
-
- return &nested;
- }
-
protected:
semantics::SemanticsContext &semaCtx;
@@ -4033,7 +4033,7 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
// Lowered in the enclosing genSectionsOp.
break;
case llvm::omp::Directive::OMPD_sections:
- genSectionsOp(converter, symTable, semaCtx, eval, loc, queue, item);
+ newOp = genSectionsOp(converter, symTable, semaCtx, eval, loc, queue, item);
break;
case llvm::omp::Directive::OMPD_simd:
newOp =
@@ -4120,6 +4120,42 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
finalizeStmtCtx();
if (loopLeaf)
symTable.popScope();
+
+ // Add the omp.combined attribute to eligible ops. In this case, all
+ // composable ops that are not loop-associated, except for the ones that can
+ // only appear as the innermost leaf construct.
+ if (!loopLeaf &&
+ llvm::isa_and_present<mlir::omp::ComposableOpInterface>(newOp) &&
+ !llvm::isa<mlir::omp::SectionsOp, mlir::omp::WorkshareOp,
+ mlir::omp::WorkdistributeOp>(newOp)) {
+ bool isCombined = false;
+ if (std::next(item) != queue.end()) {
+ // Non-innermost leafs of a combined construct must always hold the
+ // attribute.
+ isCombined = true;
+ } else if (lower::pft::Evaluation *nestedEval =
+ extractOnlyOmpNestedEval(eval)) {
+ // Combinable constructs that are immediately nested with no other
+ // statements or directives preventing them from being combined need the
+ // attribute as well.
+ OmpDirectiveSet combinableDirs =
+ (llvm::omp::blockConstructSet &
+ ~OmpDirectiveSet{llvm::omp::Directive::OMPD_ordered,
+ llvm::omp::Directive::OMPD_scope,
+ llvm::omp::Directive::OMPD_taskgroup}) |
+ (llvm::omp::loopConstructSet & ~llvm::omp::loopTransformationSet);
+ const auto &ompEval = nestedEval->get<parser::OpenMPConstruct>();
+ llvm::omp::Directive nestedDir =
+ parser::omp::GetOmpDirectiveName(ompEval).v;
+ llvm::omp::Directive firstLeafDir =
+ llvm::omp::getLeafConstructsOrSelf(nestedDir).front();
+
+ if (combinableDirs.test(firstLeafDir))
+ isCombined = true;
+ }
+ if (isCombined)
+ llvm::cast<mlir::omp::ComposableOpInterface>(newOp).setCombined(true);
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index 244c462ed93f7..b30c87cb9160b 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -326,14 +326,18 @@ class DoConcurrentConversion
targetOp =
genTargetOp(doLoop.getLoc(), rewriter, mapper, loopNestLiveIns,
targetClauseOps, loopNestClauseOps, liveInShapeInfoMap);
- genTeamsOp(rewriter, loop, mapper);
+ auto teamsOp = genTeamsOp(rewriter, loop, mapper);
+ targetOp.setCombined(true);
+ teamsOp.setCombined(true);
}
mlir::omp::ParallelOp parallelOp =
genParallelOp(rewriter, loop, ivInfos, mapper);
- // Only set as composite when part of `distribute parallel do`.
+ // Only set as composite when part of `distribute parallel do`, and only set
+ // as combined when part of `parallel do`.
parallelOp.setComposite(mapToDevice);
+ parallelOp.setCombined(!mapToDevice);
if (!mapToDevice)
genLoopNestClauseOps(doLoop.getLoc(), rewriter, loop, loopNestClauseOps);
diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
index 6f2e398b549f0..84ac1bec4d98c 100644
--- a/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
+++ b/flang/lib/Optimizer/OpenMP/LowerWorkdistribute.cpp
@@ -274,8 +274,10 @@ fissionWorkdistribute(omp::WorkdistributeOp workdistribute) {
}
if (parallelize && hoisted.empty() &&
- parallelize->getNextNode() == terminator)
+ parallelize->getNextNode() == terminator) {
+ teams.setCombined(true);
break;
+ }
if (parallelize) {
auto newTeams = rewriter.cloneWithoutRegions(teams);
auto *newTeamsBlock = rewriter.createBlock(
@@ -290,6 +292,7 @@ fissionWorkdistribute(omp::WorkdistributeOp workdistribute) {
parallelize->replaceAllUsesWith(cloned);
parallelize->erase();
omp::TerminatorOp::create(rewriter, loc);
+ newTeams.setCombined(true);
changed = true;
}
}
@@ -1582,6 +1585,7 @@ genIsolatedTargetOp(omp::TargetOp targetOp, SmallVector<Value> &postMapOperands,
targetOp.getPrivateMapsAttr(),
omp::TargetExecModeAttr::get(targetOp->getContext(),
omp::TargetExecMode::spmd));
+ isolatedTargetOp.setCombined(true);
auto *isolatedTargetBlock =
rewriter.createBlock(&isolatedTargetOp.getRegion(),
isolatedTargetOp.getRegion().begin(), {}, {});
diff --git a/flang/lib/Optimizer/OpenMP/LowerWorkshare.cpp b/flang/lib/Optimizer/OpenMP/LowerWorkshare.cpp
index a41d8d8826501..b8231bc35c999 100644
--- a/flang/lib/Optimizer/OpenMP/LowerWorkshare.cpp
+++ b/flang/lib/Optimizer/OpenMP/LowerWorkshare.cpp
@@ -612,6 +612,13 @@ LogicalResult lowerWorkshare(mlir::omp::WorkshareOp wsOp, DominanceInfo &di) {
term->erase();
newOp->erase();
wsOp->erase();
+
+ // If this was part of a combined construct (e.g. 'parallel workshare'), the
+ // changes we just made to the region can be incompatible with a combined
+ // construct, such as containing multiple block-associated constructs in it.
+ if (auto parentOp =
+ dyn_cast<omp::ComposableOpInterface>(parentBlock->getParentOp()))
+ parentOp.setCombined(false);
} else {
// Otherwise just change the operation to an omp.single.
diff --git a/flang/test/Integration/OpenMP/workshare-array-array-assign.f90 b/flang/test/Integration/OpenMP/workshare-array-array-assign.f90
index e9ec5d9175beb..3ccb46ebeebea 100644
--- a/flang/test/Integration/OpenMP/workshare-array-array-assign.f90
+++ b/flang/test/Integration/OpenMP/workshare-array-array-assign.f90
@@ -23,7 +23,7 @@ subroutine sb1(x, y)
! HLFIR: omp.terminator
! HLFIR: }
! HLFIR: omp.terminator
-! HLFIR: }
+! HLFIR: } {omp.combined}
! FIR: omp.parallel {
! FIR: omp.wsloop nowait {
@@ -32,3 +32,4 @@ subroutine sb1(x, y)
! FIR: omp.barrier
! FIR: omp.terminator
! FIR: }
+! FIR-NOT: omp.combined
diff --git a/flang/test/Integration/OpenMP/workshare-axpy.f90 b/flang/test/Integration/OpenMP/workshare-axpy.f90
index 12246e54d3432..bcf8c2d2c8ed4 100644
--- a/flang/test/Integration/OpenMP/workshare-axpy.f90
+++ b/flang/test/Integration/OpenMP/workshare-axpy.f90
@@ -32,7 +32,7 @@ subroutine sb1(a, x, y, z)
! HLFIR: }
! HLFIR-NOT: omp.barrier
! HLFIR: omp.terminator
-! HLFIR: }
+! HLFIR: } {omp.combined}
! HLFIR: return
! HLFIR: }
! HLFIR:}
@@ -55,3 +55,4 @@ subroutine sb1(a, x, y, z)
! FIR: omp.barrier
! FIR: omp.terminator
! FIR: }
+! FIR-NOT:omp.combined
diff --git a/flang/test/Integration/OpenMP/workshare-forall-sliced-array.f90 b/flang/test/Integration/OpenMP/workshare-forall-sliced-array.f90
index 88d1062b091bf..e841213c2f1bf 100644
--- a/flang/test/Integration/OpenMP/workshare-forall-sliced-array.f90
+++ b/flang/test/Integration/OpenMP/workshare-forall-sliced-array.f90
@@ -36,7 +36,7 @@ subroutine workshare_forall_sliced(a1)
! HLFIR: omp.terminator
! HLFIR: }
! HLFIR: omp.terminator
-! HLFIR: }
+! HLFIR: } {omp.combined}
! After workshare lowering, the forall should be in omp.single (since it
! contains operations that are not safe to parallelize across threads).
@@ -51,6 +51,7 @@ subroutine workshare_forall_sliced(a1)
! FIR: omp.barrier
! FIR: omp.terminator
! FIR: }
+! FIR-NOT: omp.combined
! Verify LLVM IR is generated successfully (the original issue caused crashes)
! LLVM-LABEL: define {{.*}}workshare_forall_sliced
diff --git a/flang/test/Integration/OpenMP/workshare-scalar-array-assign.f90 b/flang/test/Integration/OpenMP/workshare-scalar-array-assign.f90
index 6c180cd639997..43e6cc4bef7b7 100644
--- a/flang/test/Integration/OpenMP/workshare-scalar-array-assign.f90
+++ b/flang/test/Integration/OpenMP/workshare-scalar-array-assign.f90
@@ -24,7 +24,7 @@ subroutine sb1(a, x)
! HLFIR: omp.terminator
! HLFIR: }
! HLFIR: omp.terminator
-! HLFIR: }
+! HLFIR: } {omp.combined}
! FIR: omp.parallel {
! FIR: %[[SCALAR_ALLOCA:.*]] = fir.alloca i32
@@ -43,3 +43,4 @@ subroutine sb1(a, x)
! FIR: }
! FIR: omp.barrier
! FIR: omp.terminator
+! FIR-NOT: omp.combined
diff --git a/flang/test/Integration/OpenMP/workshare-scalar-array-mul.f90 b/flang/test/Integration/OpenMP/workshare-scalar-array-mul.f90
index 9b8ef66b48f47..1a9c9a031d9c4 100644
--- a/flang/test/Integration/OpenMP/workshare-scalar-array-mul.f90
+++ b/flang/test/Integration/OpenMP/workshare-scalar-array-mul.f90
@@ -26,12 +26,14 @@ program test
! HLFIR-O3: hlfir.destroy
! HLFIR-O3: omp.terminator
! HLFIR-O3: omp.terminator
+! HLFIR-O3: omp.combined
! FIR-O3: omp.parallel {
! FIR-O3: omp.wsloop nowait {
! FIR-O3: omp.loop_nest
! FIR-O3: omp.barrier
! FIR-O3: omp.terminator
+! FIR-O3-NOT:omp.combined
! HLFIR-O0: omp.parallel {
! HLFIR-O0: omp.workshare {
@@ -40,6 +42,7 @@ program test
! HLFIR-O0: hlfir.destroy
! HLFIR-O0: omp.terminator
! HLFIR-O0: omp.terminator
+! HLFIR-O0: omp.combined
! Check the copyprivate copy function
! FIR-O0: func.func private @_workshare_copy_heap_{{.*}}(%[[DST:.*]]: {{.*}}, %[[SRC:.*]]: {{.*}})
@@ -63,3 +66,4 @@ program test
! FIR-O0: omp.terminator
! FIR-O0: omp.barrier
! FIR-O0: omp.terminator
+! FIR-O0-NOT:omp.combined
diff --git a/flang/test/Lower/OpenMP/compound.f90 b/flang/test/Lower/OpenMP/compound.f90
new file mode 100644
index 0000000000000..d61745345a640
--- /dev/null
+++ b/flang/test/Lower/OpenMP/compound.f90
@@ -0,0 +1,1094 @@
+! This test checks lowering of compound (combined and composite) constructs.
+! Specifically, it makes sure that the proper ComposableOpInterface attributes
+! are set.
+
+! RUN: bbc -fopenmp -fopenmp-version=60 -emit-hlfir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
+
+! ------------------------------------------------------------------------------
+! COMPOSITE CONSTRUCTS
+! ------------------------------------------------------------------------------
+
+subroutine distribute_parallel_do()
+ implicit none
+ integer :: i
+
+ !$omp teams
+ !$omp distribute parallel do
+ do i=1, 10
+ end do
+ !$omp end teams
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdistribute_parallel_do
+! CHECK: omp.parallel
+! CHECK: omp.distribute
+! CHECK-NEXT: omp.wsloop
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+
+subroutine distribute_parallel_do_simd()
+ implicit none
+ integer :: i
+
+ !$omp teams
+ !$omp distribute parallel do simd
+ do i=1, 10
+ end do
+ !$omp end teams
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdistribute_parallel_do_simd
+! CHECK: omp.parallel
+! CHECK: omp.distribute
+! CHECK-NEXT: omp.wsloop
+! CHECK-NEXT: omp.simd
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+
+subroutine distribute_simd()
+ implicit none
+ integer :: i
+
+ !$omp teams
+ !$omp distribute simd
+ do i=1, 10
+ end do
+ !$omp end teams
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdistribute_simd
+! CHECK: omp.distribute
+! CHECK-NEXT: omp.simd
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+
+subroutine do_simd()
+ implicit none
+ integer :: i
+
+ !$omp do simd
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdo_simd
+! CHECK: omp.wsloop
+! CHECK-NEXT: omp.simd
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+! CHECK-NEXT: } {{{.*}}omp.composite{{.*}}}
+
+! TODO: Add taskloop simd once supported by lowering.
+
+! ------------------------------------------------------------------------------
+! COMBINED CONSTRUCTS
+! ------------------------------------------------------------------------------
+
+subroutine masked_taskloop()
+ implicit none
+ integer :: i
+
+ !$omp masked taskloop
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmasked_taskloop
+! CHECK: omp.masked
+! CHECK: omp.taskloop.context
+! CHECK: omp.taskloop.wrapper
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine master_taskloop()
+ implicit none
+ integer :: i
+
+ !$omp master taskloop
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmaster_taskloop
+! CHECK: omp.master
+! CHECK: omp.taskloop.context
+! CHECK: omp.taskloop.wrapper
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_do()
+ implicit none
+ integer :: i
+
+ !$omp parallel do
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_do
+! CHECK: omp.parallel
+! CHECK: omp.wsloop
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_loop()
+ implicit none
+ integer :: i
+
+ !$omp parallel loop
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_loop
+! CHECK: omp.parallel
+! CHECK: omp.wsloop
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_masked()
+ implicit none
+
+ !$omp parallel masked
+ call foo()
+ !$omp end parallel masked
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_masked
+! CHECK: omp.parallel
+! CHECK: omp.masked
+! CHECK: omp.terminator
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_master()
+ implicit none
+
+ !$omp parallel master
+ call foo()
+ !$omp end parallel master
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_master
+! CHECK: omp.parallel
+! CHECK: omp.master
+! CHECK: omp.terminator
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_sections()
+ implicit none
+
+ !$omp parallel sections
+ call foo()
+ !$omp end parallel sections
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_sections
+! CHECK: omp.parallel
+! CHECK: omp.sections
+! CHECK: omp.section
+! CHECK: omp.terminator
+! CHECK-NEXT: }
+! CHECK: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine parallel_workshare()
+ implicit none
+ integer :: x(10)
+
+ !$omp parallel workshare
+ x = 1
+ !$omp end parallel workshare
+end subroutine
+
+! CHECK-LABEL: func.func @_QPparallel_workshare
+! CHECK: omp.parallel
+! CHECK: omp.workshare
+! CHECK: omp.terminator
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine target_loop()
+ implicit none
+ integer :: i
+
+ !$omp target loop
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_loop
+! CHECK: omp.target
+! CHECK: omp.simd
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine target_parallel()
+ implicit none
+
+ !$omp target parallel
+ call foo()
+ !$omp end target parallel
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_parallel
+! CHECK: omp.target
+! CHECK: omp.parallel
+! CHECK: omp.terminator
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine target_simd()
+ implicit none
+ integer :: i
+
+ !$omp target simd
+ do i=1, 10
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_simd
+! CHECK: omp.target
+! CHECK: omp.simd
+! CHECK-NEXT: omp.loop_nest
+! CHECK: omp.yield
+! CHECK-NEXT: }
+! CHECK-NEXT: }
+! CHECK-NOT: omp.combined
+! CHECK: omp.terminator
+! CHECK-NEXT: } {{{.*}}omp.combined{{.*}}}
+
+subroutine tar...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/198783
More information about the llvm-branch-commits
mailing list