[flang-commits] [flang] [flang][OpenMP] - Transform target offloading directives with dependencies during PFT to MLIR conversion (PR #85130)
Pranav Bhandarkar via flang-commits
flang-commits at lists.llvm.org
Tue Apr 30 14:42:34 PDT 2024
https://github.com/bhandarkar-pranav updated https://github.com/llvm/llvm-project/pull/85130
>From dc4f90dbf3f59132bcf199ac6d40f59497c5507c Mon Sep 17 00:00:00 2001
From: Pranav Bhandarkar <pranav.bhandarkar at amd.com>
Date: Wed, 13 Mar 2024 00:26:53 -0500
Subject: [PATCH 1/5] [mlir][OpenMP] - Transform target offloading directives
with dependencies during PFT to MLIR conversion
This patch changes PFT to MLIR lowering for the following directives
when they have the `depend` clause on them.
!$ omp target depend(..)
!$ omp target enter data depend(..)
!$ omp target update data depend(..)
!$ omp target exit data depend(..)
Lowering now involves the creation of an `omp.task` operation that encloses
the `omp.target` operation that is otherwise generated for the target construct.
In addition, the depend clause from the target is moved to the enclosing
new `omp.task`. The new `omp.task` is a mergeable task.
```
!$ omp target map(..) depend(in:a)
b = a
```
is transformed to the following MLIR
```
omp.task mergeable depend(in:a) {
omp.target map(..) {
//MLIR for b = a;
}
omp.terminator
}
```
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 35 ++++++++++++++++++++++
flang/lib/Lower/OpenMP/ClauseProcessor.h | 6 ++++
flang/lib/Lower/OpenMP/OpenMP.cpp | 4 +--
flang/test/Lower/OpenMP/target.f90 | 14 ++++++---
4 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 4c51b61f6bf029..8aa10951fc2022 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -761,8 +761,43 @@ bool ClauseProcessor::processHasDeviceAddr(
addUseDeviceClause(converter, devAddrClause.v, result.hasDeviceAddrVars,
isDeviceTypes, isDeviceLocs, isDeviceSymbols);
});
+
}
+bool ClauseProcessor::processTargetDepend(
+ mlir::Location currentLocation, mlir::omp::DependClauseOps &clauseOps) const {
+
+ processDepend(clauseOps);
+ if (clauseOps.dependTypeAttrs.empty())
+ return false;
+
+ // If 'dependTypeOperands' is not empty, this means the depend
+ // clause was used and we create an omp.task operation that'll
+ // enclose the omp.target operation corresponding to the target
+ // construct used. This new omp.task will be a mergeable task
+ // on which the depend clause will be tacked on. The depend
+ // clause on the original target construct is dropped.
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+
+ // Create the new omp.task op.
+ // As per the OpenMP Spec a target directive creates a mergeable 'target
+ // task'
+ mlir::omp::TaskOp taskOp = firOpBuilder.create<mlir::omp::TaskOp>(
+ currentLocation, /*if_expr*/ mlir::Value(),
+ /*final_expr*/ mlir::Value(), /*untied*/ mlir::UnitAttr(),
+ /*mergeable*/ firOpBuilder.getUnitAttr(),
+ /*in_reduction_vars*/ mlir::ValueRange(), /*in_reductions*/ nullptr,
+ /*priority*/ mlir::Value(),
+ mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
+ clauseOps.dependTypeAttrs),
+ clauseOps.dependVars, /*allocate_vars*/ mlir::ValueRange(),
+ /*allocate_vars*/ mlir::ValueRange());
+
+ firOpBuilder.createBlock(&taskOp.getRegion());
+ firOpBuilder.create<mlir::omp::TerminatorOp>(currentLocation);
+ firOpBuilder.setInsertionPointToStart(&taskOp.getRegion().front());
+ return true;
+}
bool ClauseProcessor::processIf(
omp::clause::If::DirectiveNameModifier directiveName,
mlir::omp::IfClauseOps &result) const {
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 78c148ab021631..24d8e9f1b5dea9 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -94,6 +94,12 @@ class ClauseProcessor {
bool processCopyprivate(mlir::Location currentLocation,
mlir::omp::CopyprivateClauseOps &result) const;
bool processDepend(mlir::omp::DependClauseOps &result) const;
+ // This is a special case of processDepend that processes the depend
+ // clause on Target ops - TargetOp, EnterDataOp, ExitDataOp, UpdateDataOp
+ // It sets up the generation of MLIR code for the target construct
+ // in question by first creating an enclosing omp.task operation and transfers
+ // the 'depend' clause and its arguments to this new omp.task operation.
+ bool processTargetDepend(mlir::Location currentLocation, mlir::omp::DependClauseOps &clauseOps) const;
bool
processEnter(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index e932f7c284bca8..afe467f8e53e44 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1140,7 +1140,7 @@ static void genTargetClauses(
llvm::SmallVectorImpl<mlir::Location> &devicePtrLocs,
llvm::SmallVectorImpl<mlir::Type> &devicePtrTypes) {
ClauseProcessor cp(converter, semaCtx, clauses);
- cp.processDepend(clauseOps);
+ cp.processTargetDepend(loc, clauseOps);
cp.processDevice(stmtCtx, clauseOps);
cp.processHasDeviceAddr(clauseOps, deviceAddrTypes, deviceAddrLocs,
deviceAddrSyms);
@@ -1199,7 +1199,7 @@ static void genTargetEnterExitUpdateDataClauses(
mlir::Location loc, llvm::omp::Directive directive,
mlir::omp::TargetEnterExitUpdateDataClauseOps &clauseOps) {
ClauseProcessor cp(converter, semaCtx, clauses);
- cp.processDepend(clauseOps);
+ cp.processTargetDepend(loc, clauseOps);
cp.processDevice(stmtCtx, clauseOps);
cp.processIf(directive, clauseOps);
cp.processNowait(clauseOps);
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 51b66327dfb24b..af24546d712ced 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -27,9 +27,10 @@ subroutine omp_target_enter_depend
!$omp task depend(out: a)
call foo(a)
!$omp end task
+ !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
- !CHECK: omp.target_enter_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
+ !CHECK: omp.target_enter_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
!$omp target enter data map(to: a) depend(in: a)
return
end subroutine omp_target_enter_depend
@@ -166,9 +167,11 @@ subroutine omp_target_exit_depend
!$omp task depend(out: a)
call foo(a)
!$omp end task
+
+ !CHECK: omp.task mergeable depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
- !CHECK: omp.target_exit_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
+ !CHECK: omp.target_exit_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
!$omp target exit data map(from: a) depend(out: a)
end subroutine omp_target_exit_depend
@@ -187,9 +190,10 @@ subroutine omp_target_update_depend
call foo(a)
!$omp end task
+ !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
- !CHECK: omp.target_update motion_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
+ !CHECK: omp.target_update motion_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
!$omp target update to(a) depend(in:a)
end subroutine omp_target_update_depend
@@ -367,12 +371,14 @@ subroutine omp_target_depend
!$omp task depend(out: a)
call foo(a)
!$omp end task
+
+ !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[STRIDE_A:.*]] = arith.constant 1 : index
!CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index
!CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index
!CHECK: %[[BOUNDS_A:.*]] = omp.map.bounds lower_bound(%[[LBOUND_A]] : index) upper_bound(%[[UBOUND_A]] : index) extent(%[[EXTENT_A]] : index) stride(%[[STRIDE_A]] : index) start_idx(%[[STRIDE_A]] : index)
!CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
- !CHECK: omp.target map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !CHECK: omp.target map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref<!fir.array<1024xi32>>)
!$omp target map(tofrom: a) depend(in: a)
a(1) = 10
!CHECK: omp.terminator
>From b1d66da07b8b2920828206e7c3b2e05c16faed2f Mon Sep 17 00:00:00 2001
From: Pranav Bhandarkar <pranav.bhandarkar at amd.com>
Date: Tue, 30 Apr 2024 13:11:11 -0500
Subject: [PATCH 2/5] Handle nowait and use it to add an if clause when
creating an outer task around offloading ops like target"rgett
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 27 ++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 8aa10951fc2022..d4bcfc714a816e 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -780,12 +780,26 @@ bool ClauseProcessor::processTargetDepend(
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
// Create the new omp.task op.
- // As per the OpenMP Spec a target directive creates a mergeable 'target
- // task'
+ // Whether we create a mergeable task or not depends upon the presence of the
+ // nowait clause on the target construct.
+ // If the nowait clause is not present on the target construct, then as per
+ // the spec, the target task is an included task. We add if(0) clause to the
+ // task that we create. A task with an if clause that evaluates to false is
+ // undeferred and because this value is known at compile time, it is an
+ // included task. And an included task is also mergeable. So, we don't bother
+ // with the mergeable clause here. If the nowait clause is present on the
+ // target construct, then as per the spec, the execution of the target task
+ // may be deferred. This makes it trivially not mergeable.
+ mlir::omp::NowaitClauseOps nowaitClauseOp;
+ markClauseOccurrence<omp::clause::Nowait>(nowaitClauseOp.nowaitAttr);
+
mlir::omp::TaskOp taskOp = firOpBuilder.create<mlir::omp::TaskOp>(
- currentLocation, /*if_expr*/ mlir::Value(),
+ currentLocation,
+ /*if_expr*/ nowaitClauseOp.nowaitAttr
+ ? firOpBuilder.createBool(currentLocation, true)
+ : firOpBuilder.createBool(currentLocation, false),
/*final_expr*/ mlir::Value(), /*untied*/ mlir::UnitAttr(),
- /*mergeable*/ firOpBuilder.getUnitAttr(),
+ /*mergeable*/ mlir::UnitAttr(),
/*in_reduction_vars*/ mlir::ValueRange(), /*in_reductions*/ nullptr,
/*priority*/ mlir::Value(),
mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
@@ -793,6 +807,11 @@ bool ClauseProcessor::processTargetDepend(
clauseOps.dependVars, /*allocate_vars*/ mlir::ValueRange(),
/*allocate_vars*/ mlir::ValueRange());
+ // Clear the dependencies so that the subsequent omp.target op doesn't have
+ // dependencies
+ clauseOps.dependTypeAttrs.clear();
+ clauseOps.dependVars.clear();
+
firOpBuilder.createBlock(&taskOp.getRegion());
firOpBuilder.create<mlir::omp::TerminatorOp>(currentLocation);
firOpBuilder.setInsertionPointToStart(&taskOp.getRegion().front());
>From b5d2c843062815019a2251ff5f890f2bbbb97543 Mon Sep 17 00:00:00 2001
From: Pranav Bhandarkar <pranav.bhandarkar at amd.com>
Date: Wed, 13 Mar 2024 00:26:53 -0500
Subject: [PATCH 3/5] [mlir][OpenMP] - Transform target offloading directives
with dependencies during PFT to MLIR conversion
This patch changes PFT to MLIR lowering for the following directives
when they have the `depend` clause on them.
!$ omp target depend(..)
!$ omp target enter data depend(..)
!$ omp target update data depend(..)
!$ omp target exit data depend(..)
Lowering now involves the creation of an `omp.task` operation that encloses
the `omp.target` operation that is otherwise generated for the target construct.
In addition, the depend clause from the target is moved to the enclosing
new `omp.task`. The new `omp.task` is a mergeable task.
```
!$ omp target map(..) depend(in:a)
b = a
```
is transformed to the following MLIR
```
omp.task mergeable depend(in:a) {
omp.target map(..) {
//MLIR for b = a;
}
omp.terminator
}
```
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index d4bcfc714a816e..d3f45cdd14ff82 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -817,6 +817,7 @@ bool ClauseProcessor::processTargetDepend(
firOpBuilder.setInsertionPointToStart(&taskOp.getRegion().front());
return true;
}
+
bool ClauseProcessor::processIf(
omp::clause::If::DirectiveNameModifier directiveName,
mlir::omp::IfClauseOps &result) const {
>From 028fd9c77e12faf1d97067a4e3cfa3a2f857acfe Mon Sep 17 00:00:00 2001
From: Pranav Bhandarkar <pranav.bhandarkar at amd.com>
Date: Tue, 30 Apr 2024 14:31:03 -0500
Subject: [PATCH 4/5] update flang/test/Lower/OpenMP/target.f90
---
flang/test/Lower/OpenMP/target.f90 | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index af24546d712ced..3766f1b0ad79b1 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -27,7 +27,7 @@ subroutine omp_target_enter_depend
!$omp task depend(out: a)
call foo(a)
!$omp end task
- !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !CHECK: omp.task if(%false) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_enter_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
@@ -168,7 +168,7 @@ subroutine omp_target_exit_depend
call foo(a)
!$omp end task
- !CHECK: omp.task mergeable depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
+ !CHECK: omp.task if(%false) depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}}) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_exit_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
@@ -190,7 +190,7 @@ subroutine omp_target_update_depend
call foo(a)
!$omp end task
- !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !CHECK: omp.task if(%false) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
!CHECK: omp.target_update motion_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>)
@@ -372,7 +372,7 @@ subroutine omp_target_depend
call foo(a)
!$omp end task
- !CHECK: omp.task mergeable depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !CHECK: omp.task if(%false) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
!CHECK: %[[STRIDE_A:.*]] = arith.constant 1 : index
!CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index
!CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index
>From 8ec38538f2e44c2196c21dcdcc4d06b69cb08ef9 Mon Sep 17 00:00:00 2001
From: Pranav Bhandarkar <pranav.bhandarkar at amd.com>
Date: Tue, 30 Apr 2024 16:42:16 -0500
Subject: [PATCH 5/5] Add an opemp flang lowering test that uses the target
construct with depend and nowait
---
flang/test/Lower/OpenMP/target.f90 | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 3766f1b0ad79b1..5ee76c136189b6 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -386,6 +386,34 @@ subroutine omp_target_depend
!CHECK: }
end subroutine omp_target_depend
+!===============================================================================
+! Target with region `depend` clause and nowait
+!===============================================================================
+
+!CHECK-LABEL: func.func @_QPomp_target_depend_nowait() {
+subroutine omp_target_depend_nowait
+ !CHECK: %[[EXTENT_A:.*]] = arith.constant 1024 : index
+ !CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_depend_nowaitEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
+ integer :: a(1024)
+ !CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !$omp task depend(out: a)
+ call foo(a)
+ !$omp end task
+
+ !CHECK: omp.task if(%true) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
+ !CHECK: %[[STRIDE_A:.*]] = arith.constant 1 : index
+ !CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index
+ !CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index
+ !CHECK: %[[BOUNDS_A:.*]] = omp.map.bounds lower_bound(%[[LBOUND_A]] : index) upper_bound(%[[UBOUND_A]] : index) extent(%[[EXTENT_A]] : index) stride(%[[STRIDE_A]] : index) start_idx(%[[STRIDE_A]] : index)
+ !CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+ !CHECK: omp.target nowait map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref<!fir.array<1024xi32>>)
+ !$omp target map(tofrom: a) depend(in: a) nowait
+ a(1) = 10
+ !CHECK: omp.terminator
+ !$omp end target
+ !CHECK: }
+ end subroutine omp_target_depend_nowait
+
!===============================================================================
! Target implicit capture
!===============================================================================
More information about the flang-commits
mailing list