[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