[flang-commits] [flang] [mlir] Support for "!$omp dispatch". (PR #203320)
via flang-commits
flang-commits at lists.llvm.org
Thu Jun 11 09:08:50 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: SunilKuravinakop
<details>
<summary>Changes</summary>
Basic support for "!$omp dispatch". This PR supports only dispatch.
This also Fixes [#<!-- -->203317](https://github.com/llvm/llvm-project/issues/203317)
---
Full diff: https://github.com/llvm/llvm-project/pull/203320.diff
8 Files Affected:
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+30-3)
- (added) flang/test/Integration/OpenMP/dispatch.f90 (+76)
- (removed) flang/test/Lower/OpenMP/Todo/dispatch.f90 (-12)
- (added) flang/test/Lower/OpenMP/dispatch.f90 (+89)
- (modified) mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td (+15)
- (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+17)
- (added) mlir/test/Dialect/OpenMP/dispatch.mlir (+77)
- (added) mlir/test/Target/LLVMIR/openmp-dispatch.mlir (+81)
``````````diff
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index be876c563433a..758d8eb8148e5 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2592,6 +2592,18 @@ genMasterOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
queue, item);
}
+static mlir::omp::DispatchOp
+genDispatchOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
+ semantics::SemanticsContext &semaCtx,
+ lower::pft::Evaluation &eval, mlir::Location loc,
+ const ConstructQueue &queue,
+ ConstructQueue::const_iterator item) {
+ return genOpWithBody<mlir::omp::DispatchOp>(
+ OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
+ llvm::omp::Directive::OMPD_dispatch),
+ queue, item);
+}
+
static mlir::omp::OrderedOp
genOrderedOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
@@ -3940,6 +3952,9 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
case llvm::omp::Directive::OMPD_barrier:
newOp = genBarrierOp(converter, symTable, semaCtx, eval, loc, queue, item);
break;
+ case llvm::omp::Directive::OMPD_dispatch:
+ newOp = genDispatchOp(converter, symTable, semaCtx, eval, loc, queue, item);
+ break;
case llvm::omp::Directive::OMPD_distribute:
newOp = genStandaloneDistribute(converter, symTable, stmtCtx, semaCtx, eval,
loc, queue, item);
@@ -5312,9 +5327,21 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
- const parser::OpenMPDispatchConstruct &) {
- if (!semaCtx.langOptions().OpenMPSimd)
- TODO(converter.getCurrentLocation(), "OpenMPDispatchConstruct");
+ const parser::OpenMPDispatchConstruct &dispatchConstruct) {
+ const parser::OmpDirectiveSpecification &beginSpec =
+ dispatchConstruct.BeginDir();
+ List<Clause> clauses = makeClauses(beginSpec.Clauses(), semaCtx);
+ if (auto &endSpec = dispatchConstruct.EndDir())
+ clauses.append(makeClauses(endSpec->Clauses(), semaCtx));
+
+ llvm::omp::Directive directive = beginSpec.DirId();
+ mlir::Location currentLocation = converter.genLocation(beginSpec.source);
+
+ ConstructQueue queue{
+ buildConstructQueue(converter.getFirOpBuilder().getModule(), semaCtx,
+ eval, beginSpec.source, directive, clauses)};
+ genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue,
+ queue.begin());
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
diff --git a/flang/test/Integration/OpenMP/dispatch.f90 b/flang/test/Integration/OpenMP/dispatch.f90
new file mode 100644
index 0000000000000..c4d16690c8e29
--- /dev/null
+++ b/flang/test/Integration/OpenMP/dispatch.f90
@@ -0,0 +1,76 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+!RUN: %flang_fc1 -emit-llvm -fopenmp %s -o - | FileCheck %s
+
+!CHECK-LABEL: define void @_QMfuncsPfoo_variant1()
+!CHECK: call ptr @_FortranAioBeginExternalListOutput
+
+!CHECK-LABEL: define void @_QMfuncsPfoo_variant2()
+!CHECK: call ptr @_FortranAioBeginExternalListOutput
+
+!CHECK-LABEL: define void @_QMfuncsPfoo_dispatch()
+!CHECK: %[[COND:.*]] = load i32, ptr @_QMfuncsEfoo_sub
+!CHECK: %[[CMP:.*]] = icmp ne i32 %[[COND]], 0
+!CHECK: br i1 %[[CMP]], label %[[IF_TRUE:.*]], label %[[IF_FALSE:.*]]
+!CHECK: [[IF_TRUE]]:
+!CHECK: call void @_QMfuncsPfoo_variant2()
+!CHECK: [[IF_FALSE]]:
+!CHECK: call void @_QMfuncsPfoo_variant1()
+
+!CHECK-LABEL: define void @_QQmain()
+!CHECK: store i32 0, ptr @_QMfuncsEfoo_sub
+!CHECK: br label %omp.dispatch.region
+!CHECK: omp.dispatch.region:
+!CHECK: call void @_QMfuncsPfoo_dispatch()
+!CHECK: br label %omp.region.cont
+!CHECK: omp.region.cont:
+!CHECK: store i32 1, ptr @_QMfuncsEfoo_sub
+!CHECK: br label %omp.dispatch.region2
+!CHECK: omp.dispatch.region2:
+!CHECK: call void @_QMfuncsPfoo_dispatch()
+!CHECK: br label %omp.region.cont1
+!CHECK: omp.region.cont1:
+
+module funcs
+ implicit none
+ logical :: foo_sub
+
+contains
+
+ subroutine foo_variant1()
+ print *, "in foo_variant1"
+ end subroutine
+
+ subroutine foo_variant2()
+ print *, "in foo_variant2"
+ end subroutine
+
+ subroutine foo_dispatch()
+ if (foo_sub) then
+ call foo_variant2()
+ else
+ call foo_variant1()
+ end if
+ end subroutine
+
+end module funcs
+
+program dispatch_test
+ use funcs
+ implicit none
+
+ foo_sub = .false.
+ !$omp dispatch
+ call foo_dispatch()
+
+ foo_sub = .true.
+ !$omp dispatch
+ call foo_dispatch()
+
+end program
diff --git a/flang/test/Lower/OpenMP/Todo/dispatch.f90 b/flang/test/Lower/OpenMP/Todo/dispatch.f90
deleted file mode 100644
index 380dfa14eaae1..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/dispatch.f90
+++ /dev/null
@@ -1,12 +0,0 @@
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: OpenMPDispatchConstruct
-program p
- integer r
- r = 1
-!$omp dispatch nowait
- call foo()
-contains
- subroutine foo
- end subroutine
-end program p
diff --git a/flang/test/Lower/OpenMP/dispatch.f90 b/flang/test/Lower/OpenMP/dispatch.f90
new file mode 100644
index 0000000000000..df86503817163
--- /dev/null
+++ b/flang/test/Lower/OpenMP/dispatch.f90
@@ -0,0 +1,89 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefix=HLFIR
+!RUN: %flang_fc1 -emit-mlir -fopenmp %s -o - | FileCheck %s --check-prefix=FIR
+
+!HLFIR-LABEL: func @_QMfuncsPfoo_dispatch
+!HLFIR: %[[XD_H:.*]]:2 = hlfir.declare %{{.*}} {{{.*}}uniq_name = {{.*}}foo_dispatch{{.*}}x{{.*}}
+!HLFIR: %[[LOAD_H:.*]] = fir.load %[[XD_H]]#0 : !fir.ref<i32>
+!HLFIR: %[[C1_H:.*]] = arith.constant 1 : i32
+!HLFIR: %[[CMP_H:.*]] = arith.cmpi eq, %[[LOAD_H]], %[[C1_H]] : i32
+!HLFIR: fir.if %[[CMP_H]] {
+!HLFIR: fir.call @_QMfuncsPvariant1() {{.*}}: () -> ()
+!HLFIR: } else {
+!HLFIR: fir.call @_QMfuncsPvariant2() {{.*}}: () -> ()
+!HLFIR: }
+
+!FIR-LABEL: func @_QMfuncsPfoo_dispatch
+!FIR: %[[XD_F:.*]] = fir.declare %{{.*}} {{{.*}}uniq_name = {{.*}}foo_dispatch{{.*}}x{{.*}}
+!FIR: %[[LOAD_F:.*]] = fir.load %[[XD_F]] : !fir.ref<i32>
+!FIR: %[[CMP_F:.*]] = arith.cmpi eq, %[[LOAD_F]], %{{.*}} : i32
+!FIR: fir.if %[[CMP_F]] {
+!FIR: fir.call @_QMfuncsPvariant1() {{.*}}: () -> ()
+!FIR: } else {
+!FIR: fir.call @_QMfuncsPvariant2() {{.*}}: () -> ()
+!FIR: }
+
+module funcs
+ implicit none
+
+contains
+
+ subroutine variant1()
+ print *, "in variant1"
+ end subroutine
+
+ subroutine variant2()
+ print *, "in variant2"
+ end subroutine
+
+ subroutine foo_dispatch(x)
+ integer, intent(in) :: x
+ if (x == 1) then
+ call variant1()
+ else
+ call variant2()
+ end if
+ end subroutine
+
+end module funcs
+
+!HLFIR-LABEL: func @_QQmain
+!FIR-LABEL: func @_QQmain
+!FIR-DAG: %[[C1:.*]] = arith.constant 1 : i32
+!FIR-DAG: %[[C2:.*]] = arith.constant 2 : i32
+!FIR: %[[X:.*]] = fir.declare %{{.*}} {uniq_name = {{.*}}x{{.*}}
+program dispatch_test
+ use funcs
+ implicit none
+ integer :: x
+
+ !HLFIR: %[[X:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = {{.*}}x{{.*}}
+ !HLFIR: %[[C1:.*]] = arith.constant 1 : i32
+ !HLFIR: hlfir.assign %[[C1]] to %[[X]]#0 : i32, !fir.ref<i32>
+ !FIR: fir.store %[[C1]] to %[[X]] : !fir.ref<i32>
+ x = 1
+ !HLFIR: omp.dispatch {
+ !FIR: omp.dispatch {
+ !$omp dispatch
+ !HLFIR: fir.call @_QMfuncsPfoo_dispatch(%[[X]]#0) {{.*}}: (!fir.ref<i32>) -> ()
+ !FIR: fir.call @_QMfuncsPfoo_dispatch(%[[X]]) {{.*}}: (!fir.ref<i32>) -> ()
+ call foo_dispatch(x)
+ !HLFIR: omp.terminator
+ !FIR: omp.terminator
+ !HLFIR: }
+ !FIR: }
+
+ !HLFIR: %[[C2:.*]] = arith.constant 2 : i32
+ !HLFIR: hlfir.assign %[[C2]] to %[[X]]#0 : i32, !fir.ref<i32>
+ !FIR: fir.store %[[C2]] to %[[X]] : !fir.ref<i32>
+ x = 2
+ !HLFIR: omp.dispatch {
+ !FIR: omp.dispatch {
+ !$omp dispatch
+ !HLFIR: fir.call @_QMfuncsPfoo_dispatch(%[[X]]#0) {{.*}}: (!fir.ref<i32>) -> ()
+ !FIR: fir.call @_QMfuncsPfoo_dispatch(%[[X]]) {{.*}}: (!fir.ref<i32>) -> ()
+ call foo_dispatch(x)
+ !HLFIR: omp.terminator
+ !FIR: omp.terminator
+ !HLFIR: }
+ !FIR: }
+end program
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 51e7080db5b29..6170e40a835c6 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -2286,6 +2286,21 @@ def MaskedOp : OpenMP_Op<"masked", clauses = [
];
}
+//===----------------------------------------------------------------------===//
+// [Spec 5.1] 12.3 dispatch Construct
+//===----------------------------------------------------------------------===//
+def DispatchOp : OpenMP_Op<"dispatch", singleRegion = true> {
+ let summary = "dispatch construct";
+ let description = [{
+ The dispatch construct enables the invocation of a variant of a
+ base procedure. The structured block of a dispatch construct is a
+ single expression statement that contains a function call or a
+ subroutine call.
+ }];
+
+ let assemblyFormat = "$region attr-dict";
+}
+
//===----------------------------------------------------------------------===//
// [Spec 5.2] 6.5 allocate Directive
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index d35e8612e158b..12818a5e56ac6 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -761,6 +761,20 @@ static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind) {
llvm_unreachable("Unknown ClauseProcBindKind kind");
}
+/// Convert 'dispatch' operation into LLVM IR.
+static LogicalResult
+convertOmpDispatch(Operation &opInst, llvm::IRBuilderBase &builder,
+ LLVM::ModuleTranslation &moduleTranslation) {
+ auto dispatchOp = cast<omp::DispatchOp>(opInst);
+ auto ®ion = dispatchOp.getRegion();
+ auto result = convertOmpOpRegions(region, "omp.dispatch.region", builder,
+ moduleTranslation);
+ if (!result)
+ return handleError(result.takeError(), opInst);
+ builder.SetInsertPoint(*result);
+ return success();
+}
+
/// Converts an OpenMP 'masked' operation into LLVM IR using OpenMPIRBuilder.
static LogicalResult
convertOmpMasked(Operation &opInst, llvm::IRBuilderBase &builder,
@@ -8815,6 +8829,9 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
.Case([&](omp::ParallelOp op) {
return convertOmpParallel(op, builder, moduleTranslation);
})
+ .Case([&](omp::DispatchOp) {
+ return convertOmpDispatch(*op, builder, moduleTranslation);
+ })
.Case([&](omp::MaskedOp) {
return convertOmpMasked(*op, builder, moduleTranslation);
})
diff --git a/mlir/test/Dialect/OpenMP/dispatch.mlir b/mlir/test/Dialect/OpenMP/dispatch.mlir
new file mode 100644
index 0000000000000..c935f56836185
--- /dev/null
+++ b/mlir/test/Dialect/OpenMP/dispatch.mlir
@@ -0,0 +1,77 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// CHECK-LABEL: func @foo_dispatch
+// CHECK-SAME: (%[[X:.*]]: memref<i32>)
+func.func @foo_dispatch(%x : memref<i32>) -> () {
+ // CHECK: %[[V:.*]] = memref.load %[[X]][] : memref<i32>
+ // CHECK: %[[C1:.*]] = arith.constant 1 : i32
+ // CHECK: %[[CMP:.*]] = arith.cmpi eq, %[[V]], %[[C1]] : i32
+ // CHECK: cf.cond_br %[[CMP]], ^[[BB1:.*]], ^[[BB2:.*]]
+ %v = memref.load %x[] : memref<i32>
+ %c1 = arith.constant 1 : i32
+ %cmp = arith.cmpi eq, %v, %c1 : i32
+ cf.cond_br %cmp, ^bb1, ^bb2
+// CHECK: ^[[BB1]]:
+// CHECK: call @variant1() : () -> ()
+^bb1:
+ func.call @variant1() : () -> ()
+ cf.br ^bb3
+// CHECK: ^[[BB2]]:
+// CHECK: call @variant2() : () -> ()
+^bb2:
+ func.call @variant2() : () -> ()
+ cf.br ^bb3
+^bb3:
+ return
+}
+
+// Test that the generic form of omp.dispatch roundtrips to pretty-printed form.
+// CHECK-LABEL: func @omp_dispatch_generic_to_pretty
+// CHECK-SAME: (%[[X:.*]]: memref<i32>)
+func.func @omp_dispatch_generic_to_pretty(%x : memref<i32>) -> () {
+ // CHECK: omp.dispatch {
+ // CHECK-NEXT: func.call @foo_dispatch(%[[X]]) : (memref<i32>) -> ()
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ "omp.dispatch" () ({
+ func.call @foo_dispatch(%x) : (memref<i32>) -> ()
+ "omp.terminator" () : () -> ()
+ }) : () -> ()
+ return
+}
+
+// Test multiple dispatch regions with stores selecting different variants.
+// CHECK-LABEL: func @omp_dispatch_multiple
+// CHECK-SAME: (%[[X:.*]]: memref<i32>)
+func.func @omp_dispatch_multiple(%x : memref<i32>) -> () {
+ // CHECK: %[[C1:.*]] = arith.constant 1 : i32
+ // CHECK: memref.store %[[C1]], %[[X]][] : memref<i32>
+ %c1 = arith.constant 1 : i32
+ memref.store %c1, %x[] : memref<i32>
+ // CHECK: omp.dispatch {
+ // CHECK-NEXT: func.call @foo_dispatch(%[[X]]) : (memref<i32>) -> ()
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ "omp.dispatch" () ({
+ "func.call" (%x) {callee = @foo_dispatch} : (memref<i32>) -> ()
+ "omp.terminator" () : () -> ()
+ }) : () -> ()
+ // CHECK: %[[C2:.*]] = arith.constant 2 : i32
+ // CHECK: memref.store %[[C2]], %[[X]][] : memref<i32>
+ %c2 = arith.constant 2 : i32
+ memref.store %c2, %x[] : memref<i32>
+ // CHECK: omp.dispatch {
+ // CHECK-NEXT: func.call @foo_dispatch(%[[X]]) : (memref<i32>) -> ()
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+ "omp.dispatch" () ({
+ "func.call" (%x) {callee = @foo_dispatch} : (memref<i32>) -> ()
+ "omp.terminator" () : () -> ()
+ }) : () -> ()
+ return
+}
+
+// CHECK-LABEL: func private @variant1()
+// CHECK-LABEL: func private @variant2()
+func.func private @variant1() -> ()
+func.func private @variant2() -> ()
diff --git a/mlir/test/Target/LLVMIR/openmp-dispatch.mlir b/mlir/test/Target/LLVMIR/openmp-dispatch.mlir
new file mode 100644
index 0000000000000..8a3a7a6b5d8e6
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-dispatch.mlir
@@ -0,0 +1,81 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+llvm.mlir.global external @x() {addr_space = 0 : i32} : i32 {
+ %0 = llvm.mlir.constant(0 : i32) : i32
+ llvm.return %0 : i32
+}
+
+llvm.func @variant1() -> ()
+llvm.func @variant2() -> ()
+
+// CHECK-LABEL: define void @foo_dispatch()
+llvm.func @foo_dispatch() {
+ // CHECK: %[[ADDR:.*]] = load i32, ptr @x
+ // CHECK: %[[CMP:.*]] = icmp eq i32 %[[ADDR]], 1
+ // CHECK: br i1 %[[CMP]], label %[[BB1:.*]], label %[[BB2:.*]]
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ %1 = llvm.load %0 : !llvm.ptr -> i32
+ %c1 = llvm.mlir.constant(1 : i32) : i32
+ %cmp = llvm.icmp "eq" %1, %c1 : i32
+ llvm.cond_br %cmp, ^bb1, ^bb2
+// CHECK: [[BB1]]:
+// CHECK: call void @variant1()
+^bb1:
+ llvm.call @variant1() : () -> ()
+ llvm.br ^bb3
+// CHECK: [[BB2]]:
+// CHECK: call void @variant2()
+^bb2:
+ llvm.call @variant2() : () -> ()
+ llvm.br ^bb3
+^bb3:
+ llvm.return
+}
+
+// CHECK-LABEL: define void @test_omp_dispatch()
+llvm.func @test_omp_dispatch() {
+ // CHECK: store i32 1, ptr @x
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ %c1 = llvm.mlir.constant(1 : i32) : i32
+ llvm.store %c1, %0 : i32, !llvm.ptr
+ // CHECK: br label %omp.dispatch.region
+ omp.dispatch {
+ // CHECK: omp.dispatch.region:
+ // CHECK-NEXT: call void @foo_dispatch()
+ llvm.call @foo_dispatch() : () -> ()
+ // CHECK-NEXT: br label %omp.region.cont
+ omp.terminator
+ }
+ // CHECK: omp.region.cont:
+ llvm.return
+}
+
+// CHECK-LABEL: define void @test_omp_dispatch_multiple()
+llvm.func @test_omp_dispatch_multiple() {
+ // CHECK: store i32 1, ptr @x
+ %0 = llvm.mlir.addressof @x : !llvm.ptr
+ %c1 = llvm.mlir.constant(1 : i32) : i32
+ llvm.store %c1, %0 : i32, !llvm.ptr
+ // CHECK: br label %omp.dispatch.region
+ omp.dispatch {
+ // CHECK: omp.dispatch.region:
+ // CHECK-NEXT: call void @foo_dispatch()
+ llvm.call @foo_dispatch() : () -> ()
+ // CHECK-NEXT: br label %omp.region.cont
+ omp.terminator
+ }
+ // CHECK: omp.region.cont:
+ // CHECK: store i32 2, ptr @x
+ %c2 = llvm.mlir.constant(2 : i32) : i32
+ llvm.store %c2, %0 : i32, !llvm.ptr
+ // CHECK: br label %omp.dispatch.region2
+ omp.dispatch {
+ // CHECK: omp.dispatch.region2:
+ // CHECK-NEXT: call void @foo_dispatch()
+ llvm.call @foo_dispatch() : () -> ()
+ // CHECK-NEXT: br label %omp.region.cont1
+ omp.terminator
+ }
+ // CHECK: omp.region.cont1:
+ llvm.return
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/203320
More information about the flang-commits
mailing list