[flang-commits] [flang] [llvm] [Flang][OpenMP] Prevent unrequired implicit maps for private variables on composite directives (PR #217121)

via flang-commits flang-commits at lists.llvm.org
Sat Sep 12 02:58:48 PDT 2026


https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/217121

>From 9e634b18a0168e00f0ddf2f9e8e8971d9f9dc003 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Wed, 26 Aug 2026 13:37:55 -0500
Subject: [PATCH 1/2] [Flang][OpenMP] Prevent unrequired implicit maps for
 private variables on composite directives

Currently we are emitting implicit maps for private variables on composite directives, these maps are unrequired as the private clause does not require filling from the original clause item. They're default allocated and a user must assign to them.

The problem is that at the point we are processing implicit maps on the target region, the private symbol has not been marked appropriately for the DataSharingProcessor to connect the dots that it belongs to the target region (and technically other components of the composite directive) and not just the leaf construct. So, the DataSharingProcessor doesn't gather the symbol, and the implicit mapper generates a map as the symbol isn't in the privatized symbol list gathered for the directive.

The approach taken in this patch is to perform a pseudo privatization at the target level, skipping implicit maps for certain types and creating an intermediate allocation to avoid IFA issues with the nested private clauses pointing external to the target region.
---
 flang/include/flang/Utils/OpenMP.h            |  15 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 192 ++++++-
 flang/lib/Utils/OpenMP.cpp                    |  75 ++-
 .../target-composite-private-unified.f90      | 473 ++++++++++++++++++
 .../Lower/OpenMP/target-parallel-private.f90  |   2 +-
 .../Lower/OpenMP/target-teams-private.f90     |   2 +-
 6 files changed, 737 insertions(+), 22 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/target-composite-private-unified.f90

diff --git a/flang/include/flang/Utils/OpenMP.h b/flang/include/flang/Utils/OpenMP.h
index 0cb77e25af9475..6a31b489eed185 100644
--- a/flang/include/flang/Utils/OpenMP.h
+++ b/flang/include/flang/Utils/OpenMP.h
@@ -53,7 +53,9 @@ mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
 /// For values used inside a target region but defined outside, either clone
 /// these value inside the target region or map them to the region. This
 /// function first tries to clone values (if they are defined by
-/// memory-effect-free ops, otherwise, the values are mapped.
+/// memory-effect-free ops), otherwise, the values are mapped. It iterates to a
+/// fixpoint: every outsider is resolved (cloned or mapped) so the set of
+/// values-defined-above eventually drains.
 ///
 /// \param firOpBuilder - Operation builder.
 /// \param targetOp     - The target that needs to be extended by clones and/or
@@ -61,6 +63,17 @@ mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
 void cloneOrMapRegionOutsiders(
     fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp);
 
+/// A similar but lighter variation of cloneOrMapRegionOutsiders, which only
+/// clones values outside of the region that are memory effect free and does
+/// not resolve all values-defined-above if some require mapping. The intent
+/// is primarily to clone over constant values required for shape and extent
+/// creation.
+/// \param firOpBuilder - Operation builder.
+/// \param targetOp     - The target whose region-local clones need their
+/// defined-above operands sunk in.
+void cloneRegionOutsiders(
+    fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp);
+
 using RecordMemberMapperMangler =
     std::function<void(std::string &mapperId, llvm::StringRef memberName)>;
 
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index e0ee9d8249ee79..e8885c2c15cdd5 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2254,7 +2254,8 @@ static void genBodyOfTargetOp(
     semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
     mlir::omp::TargetOp &targetOp, const ObjectEntryBlockArgs &args,
     const mlir::Location &currentLocation, const ConstructQueue &queue,
-    ConstructQueue::const_iterator item, DataSharingProcessor &dsp) {
+    ConstructQueue::const_iterator item, DataSharingProcessor &dsp,
+    llvm::ArrayRef<const semantics::Symbol *> targetNestedPrivateSyms = {}) {
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
   auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
 
@@ -2301,6 +2302,13 @@ static void genBodyOfTargetOp(
   // Create the insertion point after the marker.
   firOpBuilder.setInsertionPointAfter(undefMarker.getDefiningOp());
 
+  // Materialize region-local copies for the private list items of inner leaf
+  // constructs (e.g. distribute) of a combined/composite target directive,
+  // with the intent of replacing a host to device data-mapping (map info
+  // emission).
+  for (const semantics::Symbol *sym : targetNestedPrivateSyms)
+    converter.createHostAssociateVarClone(*sym, /*skipDefaultInit=*/false);
+
   bool immediatelyNestsTeams = false;
   if (std::next(item) != queue.end()) {
     immediatelyNestsTeams = llvm::omp::topTeamsSet.test(std::next(item)->id);
@@ -2325,6 +2333,13 @@ static void genBodyOfTargetOp(
     genNestedEvaluations(converter, eval);
   }
 
+  // When materializing arrays inside of the target region for composite
+  // directives with leaf-bound private clauses, we can end up with the
+  // constants populating the shape being bound to constants external to the
+  // target region, so we perform a final clone step to resolve these, we
+  // intentionally avoid introducing new maps at this stage.
+  cloneRegionOutsiders(firOpBuilder, targetOp);
+
   dsp.processStep2(targetOp, /*isLoop=*/false);
 }
 
@@ -4060,6 +4075,147 @@ static void collectSymbolsWithDynamicSubstring(
   symbolsWithDynamicSubstring = visitor.symbolsWithDynamicSubstring;
 }
 
+// Reverse search the composite/combined directive and return the first leaf
+// carrying a private clause, the OpenMP specification dictates that the first
+// leaf that can legally have a private clause becomes the owner.
+//
+// The function intentionally skips the node representing the root target
+// directive by setting the end (begin) point to the second leaf, the private
+// clauses on a standalone target region should apply through regular
+// privatization means. Otherwise, if we find no relevant leaf node (carrying a
+// private clause) we return the end of the iterator.
+static ConstructQueue::const_iterator
+findInnermostPrivateLeaf(ConstructQueue::const_iterator item,
+                         const ConstructQueue &queue) {
+  auto hasPrivate = [](ConstructQueue::const_iterator it) {
+    return llvm::any_of(it->clauses, [](const Clause &clause) {
+      return std::holds_alternative<clause::Private>(clause.u);
+    });
+  };
+  auto begin = std::next(item);
+  for (auto it = queue.end(); it != begin;) {
+    --it;
+    if (hasPrivate(it))
+      return it;
+  }
+  return queue.end();
+}
+
+// Verify if it's safe to drop the map and materialize a clone. Certain cases
+// still currently require a map to be OpenMP specification compliant, a
+// rewording of the specfications privatization rules made to be a bit more
+// concise, if the type is an:
+//
+//  Allocatable -
+//    1) If the status is unallocated, the private allocatable is unallocated
+//    2) If the allocation status is allocated, the private allocatable is
+//    allocated 3) If it's an array, the allocatables shape and bounds will be
+//    the same.
+//  Pointer - The intial status of a private pointer is undefined.
+//  Other - If the type of the list item has default initialization, the new
+//  list item has default initialization. Otherwise, it's undefined.
+//
+// From the above list, it is currently fine to drop maps and materialize clones
+// for scalars, pointers, and constant arrays. As their creation does not
+// neccesitate referencing dynamic extent/shape/allocation-status values defined
+// outside the target region. Types that fall into this category and that need a
+// map still (just to populate the initial state) are allocatables (and by
+// extension this unfortunately precludes derived types with allocatables in
+// them for now), and assumed shape arrays (size being illegal on a private
+// clause). Currently we leave these as they were before, but in the future we
+// can minimize the mapping by sending across exactly what we require to be
+// specification compliant.
+static bool isTargetLocalCloneable(const semantics::Symbol &sym,
+                                   semantics::SemanticsContext &semaCtx) {
+  const semantics::Symbol &ult = sym.GetUltimate();
+  // Allocatable descriptors cannot be cloned and have their implicit map
+  // blocked, the clone requires the host descriptor for allocation
+  // status/bounds.
+  if (semantics::IsAllocatable(ult))
+    return false;
+
+  // A derived type with an allocatable ultimate component cannot be cloned and
+  // have its implicit map dropped for the same reasons we currently have to
+  // do it for the allocatable case.
+  if (const semantics::DeclTypeSpec *declType = ult.GetType())
+    if (const semantics::DerivedTypeSpec *derived = declType->AsDerived())
+      if (semantics::FindAllocatableUltimateComponent(*derived))
+        return false;
+
+  // Pointers initial status is undefined, so we can just materialize it with
+  // the correct typing, but we need to be a little more careful with anything
+  // else that isn't a scalar and verify that it has constant extents and shape.
+  if (ult.Rank() > 0 && !semantics::IsPointer(ult)) {
+    evaluate::FoldingContext &foldingContext = semaCtx.foldingContext();
+    std::optional<evaluate::Shape> shape =
+        evaluate::GetShape(foldingContext, ult);
+    std::optional<evaluate::ConstantSubscripts> extents =
+        evaluate::AsConstantExtents(foldingContext, shape);
+    if (!extents || evaluate::HasNegativeExtent(*extents))
+      return false;
+  }
+  return true;
+}
+
+// Discover the `private` list items of the inner leaf construct of a
+// combined/composite clause e.g. the "s" in `target teams distribute
+// private(a)`. These are not privatized on the target itself, and without
+// intervention would normally be implicitly mapped unnecesarily. This function
+// collects the relevant symbols so we can prevent their implicit mapping and
+// materialize in region replacements for the private clause to redirect to,
+// this prevents IFA errors during verification. The blocking of implicit maps
+// is done during implicit map generating utilising these symbols, and the
+// materialization occurs during the intitial stages of the targe body
+// generation, however, materializaiton only occurs in cases where the innerleaf
+// is not a team as it does its own materialization.
+static void collectTargetNestedPrivateSyms(
+    semantics::SemanticsContext &semaCtx, ConstructQueue::const_iterator item,
+    const ConstructQueue &queue, llvm::ArrayRef<Object> mapObjects,
+    const DataSharingProcessor &dsp,
+    llvm::SmallVectorImpl<const semantics::Symbol *> &targetNestedPrivateSyms,
+    bool &innermostLeafIsTeams) {
+  innermostLeafIsTeams = false;
+
+  // Avoid capturing symbols on anything with explicit mapping or privatization.
+  auto isExcluded = [&](const semantics::Symbol *sym) {
+    const semantics::Symbol &ult = sym->GetUltimate();
+    if (llvm::any_of(mapObjects, [&](const Object &o) {
+          return o.sym() && o.sym()->GetUltimate() == ult;
+        }))
+      return true;
+    return llvm::any_of(
+        dsp.getAllSymbolsToPrivatize(),
+        [&](const semantics::Symbol *p) { return p->GetUltimate() == ult; });
+  };
+
+  ConstructQueue::const_iterator innermostPrivateLeaf =
+      findInnermostPrivateLeaf(item, queue);
+
+  // No private clause owning leaf found.
+  if (innermostPrivateLeaf == queue.end())
+    return;
+
+  // if the leaf node is a teams leaf, it already performs what target region
+  // must do for other leaf nodes, creates new host-associate clones inside the
+  // region, altough, there is no redirection through inner private clauses in
+  // this case. The main caveat of this is that we can skip the inner clone step
+  // for teams, and simply have to skip the extra implicit maps.
+  innermostLeafIsTeams = llvm::omp::topTeamsSet.test(innermostPrivateLeaf->id);
+
+  for (const Clause &clause : innermostPrivateLeaf->clauses) {
+    if (const auto *priv = std::get_if<clause::Private>(&clause.u)) {
+      for (const Object &object : priv->v) {
+        const semantics::Symbol *sym = object.sym();
+        if (!sym || isExcluded(sym))
+          continue;
+        if (!isTargetLocalCloneable(*sym, semaCtx))
+          continue;
+        targetNestedPrivateSyms.push_back(sym);
+      }
+    }
+  }
+}
+
 static mlir::omp::TargetOp
 genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
             lower::StatementContext &stmtCtx,
@@ -4154,6 +4310,23 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
   collectSymbolsWithDynamicSubstring(semaCtx, eval,
                                      symbolsWithDynamicSubstring);
 
+  // Collect private clause symbols on the innermost leaf (that can legally own
+  // the clause) for composite directives. For example the "s" in
+  // "target teams distribute private(s)" belongs to the distribute directive
+  // and not the target region. So we would like to gather these symbols so we
+  // can appropriately block the unrequired implicit maps and create a seperate
+  // in region copy of the variable, which may then be further privatized or
+  // used directly. This is somewhat analogus to what the teams directive
+  // already does when privatizing, but our main reasons here are specification
+  // legality as the prviate clause shouldn't apply to the target region in this
+  // scenario and more importantly if there is no private clause we have to
+  // placate the target regions IFA restrictions with an alternative block
+  // argument or in this case materialize an in region replacement.
+  llvm::SmallVector<const semantics::Symbol *> targetNestedPrivateSyms;
+  bool innermostLeafIsTeams = false;
+  collectTargetNestedPrivateSyms(semaCtx, item, queue, mapObjects, dsp,
+                                 targetNestedPrivateSyms, innermostLeafIsTeams);
+
   // 5.8.1 Implicit Data-Mapping Attribute Rules
   // The following code follows the implicit data-mapping rules to map all the
   // symbols used inside the region that do not have explicit data-environment
@@ -4208,6 +4381,17 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
     if (sym.GetUltimate().test(semantics::Symbol::Flag::OmpGroupPrivate))
       return;
 
+    // Skip mapping of symbols that appear in private clauses of composite
+    // directive leaf nodes. For example "target teams distribute private(s)",
+    // in this case "s" does not need a map as any usage at a user-level is
+    // privatized and does not neccesitate a data transfer in most cases
+    // (assumed shape arrays being an exception as we need there shape to create
+    // the private copy).
+    if (llvm::any_of(targetNestedPrivateSyms, [&](const semantics::Symbol *s) {
+          return s == &sym || s->GetUltimate() == sym.GetUltimate();
+        }))
+      return;
+
     if (!isDuplicateMappedSymbol(sym, dsp.getAllSymbolsToPrivatize(),
                                  hasDeviceAddrObjects, mapObjects,
                                  isDevicePtrObjects)) {
@@ -4369,8 +4553,10 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
   args.priv.objects = makeObjects(dsp.getDelayedPrivSymbols());
   args.priv.vars = clauseOps.privateVars;
 
-  genBodyOfTargetOp(converter, symTable, semaCtx, eval, targetOp, args, loc,
-                    queue, item, dsp);
+  genBodyOfTargetOp(
+      converter, symTable, semaCtx, eval, targetOp, args, loc, queue, item, dsp,
+      innermostLeafIsTeams ? llvm::ArrayRef<const semantics::Symbol *>{}
+                           : targetNestedPrivateSyms);
 
   // Remove the host_eval information structure created for this target region.
   if (!isTargetDevice)
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index aa5ef994252f76..778853fb1df121 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -164,14 +164,27 @@ mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
   return loadOp.getResult();
 }
 
-void cloneOrMapRegionOutsiders(
-    fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {
+namespace {
+/// Helper function for resolving values used inside a target region but defined
+/// above it. It can resolve through cloning or generating new map info
+/// operations. It will opt for cloning when provably memory effect free,
+/// otherwise it will generate a map, however, only if requested.
+///
+/// \param mapNonClonable - When true, non-clonable outsiders are mapped into
+/// the region; when false they are left untouched.
+/// \param iterateToFixpoint - When true, the set of values-defined-above is
+/// re-queried and reprocessed until emptied. Otherwise a single pass is done.
+/// \param inScope - Predicate selecting which uses of an outsider should be
+/// rewired to the sunk/mapped replacement.
+void resolveRegionOutsiders(fir::FirOpBuilder &firOpBuilder,
+    mlir::omp::TargetOp targetOp, bool mapNonClonable, bool iterateToFixpoint,
+    llvm::function_ref<bool(mlir::OpOperand &)> inScope) {
   mlir::Region &region = targetOp.getRegion();
   mlir::Block *entryBlock = &region.getBlocks().front();
 
   llvm::SetVector<mlir::Value> valuesDefinedAbove;
   mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
-  while (!valuesDefinedAbove.empty()) {
+  do {
     for (mlir::Value val : valuesDefinedAbove) {
       mlir::Operation *valOp = val.getDefiningOp();
 
@@ -180,28 +193,58 @@ void cloneOrMapRegionOutsiders(
       // which comes with a fairly large overhead comparatively. We could be
       // more robust about this and check using a BackwardsSlice to see if we
       // run the risk of mapping a box.
-      if (valOp && mlir::isMemoryEffectFree(valOp) &&
-          !mlir::isa<fir::BoxDimsOp>(valOp)) {
+      bool clonable = valOp && mlir::isMemoryEffectFree(valOp) &&
+          !mlir::isa<fir::BoxDimsOp>(valOp);
+
+      if (clonable) {
         mlir::Operation *clonedOp = valOp->clone();
         entryBlock->push_front(clonedOp);
 
-        auto replace = [entryBlock](mlir::OpOperand &use) {
-          return use.getOwner()->getBlock() == entryBlock;
-        };
-
-        valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
-        valOp->replaceUsesWithIf(clonedOp, replace);
-      } else {
+        valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), inScope);
+        valOp->replaceUsesWithIf(clonedOp, inScope);
+      } else if (mapNonClonable) {
         mlir::Value mappedTemp = mapTemporaryValue(firOpBuilder, targetOp, val,
             /*name=*/{});
-        val.replaceUsesWithIf(mappedTemp, [entryBlock](mlir::OpOperand &use) {
-          return use.getOwner()->getBlock() == entryBlock;
-        });
+        val.replaceUsesWithIf(mappedTemp, inScope);
       }
     }
+
+    if (!iterateToFixpoint)
+      break;
+
     valuesDefinedAbove.clear();
     mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
-  }
+  } while (!valuesDefinedAbove.empty());
+}
+} // namespace
+
+void cloneOrMapRegionOutsiders(
+    fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {
+  mlir::Block *entryBlock = &targetOp.getRegion().getBlocks().front();
+
+  // Iterate to a fixpoint, mapping any non-clonable outsiders. Uses are only
+  // rewired within the entry block itself.
+  resolveRegionOutsiders(firOpBuilder, targetOp, /*mapNonClonable=*/true,
+      /*iterateToFixpoint=*/true, [entryBlock](mlir::OpOperand &use) {
+        return use.getOwner()->getBlock() == entryBlock;
+      });
+}
+
+void cloneRegionOutsiders(
+    fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {
+  mlir::Region &region = targetOp.getRegion();
+  // Single, non-iterating pass. We deliberately do NOT map non-clonable
+  // outsiders here, so re-querying and looping until the set drains could never
+  // terminate. Clonable ops we do sink do not themselves reference other
+  // defined-above values, so one pass is sufficient.
+  //
+  // The clone is pushed to the front of the entry block, which dominates every
+  // nested block of the region, so rewire any use contained anywhere within the
+  // target region.
+  resolveRegionOutsiders(firOpBuilder, targetOp, /*mapNonClonable=*/false,
+      /*iterateToFixpoint=*/false, [&region](mlir::OpOperand &use) {
+        return region.findAncestorOpInRegion(*use.getOwner()) != nullptr;
+      });
 }
 
 /// Gets or generates a default declare mapper for a given record type.
diff --git a/flang/test/Lower/OpenMP/target-composite-private-unified.f90 b/flang/test/Lower/OpenMP/target-composite-private-unified.f90
new file mode 100644
index 00000000000000..27e626b45ce3cc
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-composite-private-unified.f90
@@ -0,0 +1,473 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+module types
+  type :: dt
+    integer :: a
+    real :: b
+  end type
+  type :: dt_alloc
+    integer, allocatable :: a
+  end type
+  type :: dt_alloc_arr
+    integer, allocatable :: a(:)
+  end type
+end module
+
+subroutine target_teams(n, assumed)
+  use types
+  integer :: n, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target teams private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  s = 1
+  !$omp end target teams
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_teams
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[TEAMS_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TEAMS_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TEAMS_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[TEAMS_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[TEAMS_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[TEAMS_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TEAMS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TEAMS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TEAMS_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[TEAMS_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TEAMS_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TEAMS_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[TEAMS_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[TEAMS_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[TEAMS_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[TEAMS_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(generic) map_entries(%[[TEAMS_ALLOC_MAP]] -> %{{.*}}, %[[TEAMS_DA_MAP]] -> %{{.*}}, %[[TEAMS_ASSUMED_MAP]] -> %{{.*}}, %[[TEAMS_ALLOC_ARR_MAP]] -> %{{.*}}, %[[TEAMS_DAA_MAP]] -> %{{.*}}, %[[TEAMS_AUTO_ARR_MAP]] -> %{{.*}}, %[[TEAMS_N_MAP]] -> %{{.*}}, %[[TEAMS_ALLOC_ATTACH]] -> %{{.*}}, %[[TEAMS_ASSUMED_ATTACH]] -> %{{.*}}, %[[TEAMS_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[TEAMS_ALLOC_MEMBER]] -> %{{.*}}, %[[TEAMS_ASSUMED_MEMBER]] -> %{{.*}}, %[[TEAMS_ALLOC_ARR_MEMBER]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teamsEalloc"}
+! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teamsEda"}
+! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teamsEassumed"}
+! CHECK: hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teamsEalloc_arr"}
+! CHECK: hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teamsEdaa"}
+! CHECK: hlfir.declare %arg{{[0-9]+}}(%{{.*}}) {uniq_name = "_QFtarget_teamsEauto_arr"}
+! CHECK: omp.teams {
+! CHECK: fir.alloca i32 {bindc_name = "s", pinned, uniq_name = "_QFtarget_teamsEs"}
+! CHECK: fir.alloca !fir.array<10xi32> {bindc_name = "arr", pinned, uniq_name = "_QFtarget_teamsEarr"}
+! CHECK: fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "alloc", pinned, uniq_name = "_QFtarget_teamsEalloc"}
+! CHECK: fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "ptr", pinned, uniq_name = "_QFtarget_teamsEptr"}
+! CHECK: fir.alloca !fir.type<_QMtypesTdt{a:i32,b:f32}> {bindc_name = "d", pinned, uniq_name = "_QFtarget_teamsEd"}
+! CHECK: fir.alloca !fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}> {bindc_name = "da", pinned, uniq_name = "_QFtarget_teamsEda"}
+! CHECK: fir.alloca !fir.array<?xi32>, %{{.*}} {bindc_name = "assumed", pinned, uniq_name = "_QFtarget_teamsEassumed"}
+! CHECK: fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "alloc_arr", pinned, uniq_name = "_QFtarget_teamsEalloc_arr"}
+! CHECK: fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "ptr_arr", pinned, uniq_name = "_QFtarget_teamsEptr_arr"}
+! CHECK: fir.alloca !fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}> {bindc_name = "daa", pinned, uniq_name = "_QFtarget_teamsEdaa"}
+! CHECK: fir.alloca !fir.array<?xi32>, %{{.*}} {bindc_name = "auto_arr", pinned, uniq_name = "_QFtarget_teamsEauto_arr"}
+
+subroutine target_parallel(n, assumed)
+  use types
+  integer :: n, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target parallel private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  s = 1
+  !$omp end target parallel
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_parallel
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[PAR_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PAR_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PAR_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[PAR_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[PAR_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[PAR_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PAR_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PAR_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[PAR_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[PAR_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PAR_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PAR_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[PAR_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[PAR_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[PAR_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[PAR_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(generic) map_entries(%[[PAR_ALLOC_MAP]] -> %{{.*}}, %[[PAR_DA_MAP]] -> %{{.*}}, %[[PAR_ASSUMED_MAP]] -> %{{.*}}, %[[PAR_ALLOC_ARR_MAP]] -> %{{.*}}, %[[PAR_DAA_MAP]] -> %{{.*}}, %[[PAR_AUTO_ARR_MAP]] -> %{{.*}}, %[[PAR_N_MAP]] -> %{{.*}}, %[[PAR_ALLOC_ATTACH]] -> %{{.*}}, %[[PAR_ASSUMED_ATTACH]] -> %{{.*}}, %[[PAR_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[PAR_ALLOC_MEMBER]] -> %{{.*}}, %[[PAR_ASSUMED_MEMBER]] -> %{{.*}}, %[[PAR_ALLOC_ARR_MEMBER]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: %[[PAR_ALLOC_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_parallelEalloc"}
+! CHECK: %[[PAR_DA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallelEda"}
+! CHECK: %[[PAR_ASSUMED_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallelEassumed"}
+! CHECK: %[[PAR_ALLOC_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_parallelEalloc_arr"}
+! CHECK: %[[PAR_DAA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallelEdaa"}
+! CHECK: %[[PAR_AUTO_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}}(%{{.*}}) {uniq_name = "_QFtarget_parallelEauto_arr"}
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "da", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "assumed", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc_arr", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "daa", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "auto_arr", pinned
+! CHECK: %[[PAR_S_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "s", pinned, uniq_name = "_QFtarget_parallelEs"}
+! CHECK: %[[PAR_S_DECL:.*]]:2 = hlfir.declare %[[PAR_S_ALLOCA]]
+! CHECK: %[[PAR_ARR_ALLOCA:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "arr", pinned, uniq_name = "_QFtarget_parallelEarr"}
+! CHECK: %[[PAR_ARR_DECL:.*]]:2 = hlfir.declare %[[PAR_ARR_ALLOCA]]
+! CHECK: %[[PAR_PTR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "ptr", pinned, uniq_name = "_QFtarget_parallelEptr"}
+! CHECK: %[[PAR_PTR_DECL:.*]]:2 = hlfir.declare %[[PAR_PTR_ALLOCA]]
+! CHECK: %[[PAR_D_ALLOCA:.*]] = fir.alloca !fir.type<_QMtypesTdt{a:i32,b:f32}> {bindc_name = "d", pinned, uniq_name = "_QFtarget_parallelEd"}
+! CHECK: %[[PAR_D_DECL:.*]]:2 = hlfir.declare %[[PAR_D_ALLOCA]]
+! CHECK: %[[PAR_PTR_ARR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "ptr_arr", pinned, uniq_name = "_QFtarget_parallelEptr_arr"}
+! CHECK: %[[PAR_PTR_ARR_DECL:.*]]:2 = hlfir.declare %[[PAR_PTR_ARR_ALLOCA]]
+! CHECK: fir.store %[[PAR_ASSUMED_DECL]]#0 to %[[PAR_ASSUMED_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: fir.store %[[PAR_AUTO_ARR_DECL]]#0 to %[[PAR_AUTO_ARR_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: omp.parallel private(
+! CHECK-SAME: @_QFtarget_parallelEs_private_i32 %[[PAR_S_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEarr_private_10xi32 %[[PAR_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEalloc_private_box_heap_i32 %[[PAR_ALLOC_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEptr_private_box_ptr_i32 %[[PAR_PTR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEd_private_rec__QMtypesTdt %[[PAR_D_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEda_private_rec__QMtypesTdt_alloc %[[PAR_DA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEassumed_private_box_Uxi32 %[[PAR_ASSUMED_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEalloc_arr_private_box_heap_Uxi32 %[[PAR_ALLOC_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEptr_arr_private_box_ptr_Uxi32 %[[PAR_PTR_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEdaa_private_rec__QMtypesTdt_alloc_arr %[[PAR_DAA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallelEauto_arr_private_box_Uxi32 %[[PAR_AUTO_ARR_COPY]] -> %arg{{[0-9]+}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>) {
+
+subroutine target_teams_distribute(n, assumed)
+  use types
+  integer :: n, i, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target teams distribute private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  do i = 1, n
+    s = i
+  end do
+  !$omp end target teams distribute
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_teams_distribute
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[TTD_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTD_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTD_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[TTD_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[TTD_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[TTD_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTD_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTD_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TTD_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[TTD_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTD_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTD_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[TTD_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[TTD_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[TTD_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[TTD_I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: %[[TTD_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[TTD_BOUND_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(generic) host_eval({{.*}}) map_entries(%[[TTD_ALLOC_MAP]] -> %{{.*}}, %[[TTD_DA_MAP]] -> %{{.*}}, %[[TTD_ASSUMED_MAP]] -> %{{.*}}, %[[TTD_ALLOC_ARR_MAP]] -> %{{.*}}, %[[TTD_DAA_MAP]] -> %{{.*}}, %[[TTD_AUTO_ARR_MAP]] -> %{{.*}}, %[[TTD_I_MAP]] -> %{{.*}}, %[[TTD_N_MAP]] -> %{{.*}}, %[[TTD_BOUND_N_MAP]] -> %{{.*}}, %[[TTD_ALLOC_ATTACH]] -> %{{.*}}, %[[TTD_ASSUMED_ATTACH]] -> %{{.*}}, %[[TTD_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[TTD_ALLOC_MEMBER]] -> %{{.*}}, %[[TTD_ASSUMED_MEMBER]] -> %{{.*}}, %[[TTD_ALLOC_ARR_MEMBER]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: %[[TTD_ALLOC_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teams_distributeEalloc"}
+! CHECK: %[[TTD_DA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distributeEda"}
+! CHECK: %[[TTD_ASSUMED_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distributeEassumed"}
+! CHECK: %[[TTD_ALLOC_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teams_distributeEalloc_arr"}
+! CHECK: %[[TTD_DAA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distributeEdaa"}
+! CHECK: %[[TTD_AUTO_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}}(%{{.*}}) {uniq_name = "_QFtarget_teams_distributeEauto_arr"}
+! CHECK: %[[TTD_I_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distributeEi"}
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "da", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "assumed", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc_arr", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "daa", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "auto_arr", pinned
+! CHECK: %[[TTD_S_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "s", pinned, uniq_name = "_QFtarget_teams_distributeEs"}
+! CHECK: %[[TTD_S_DECL:.*]]:2 = hlfir.declare %[[TTD_S_ALLOCA]]
+! CHECK: %[[TTD_ARR_ALLOCA:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "arr", pinned, uniq_name = "_QFtarget_teams_distributeEarr"}
+! CHECK: %[[TTD_ARR_DECL:.*]]:2 = hlfir.declare %[[TTD_ARR_ALLOCA]]
+! CHECK: %[[TTD_PTR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "ptr", pinned, uniq_name = "_QFtarget_teams_distributeEptr"}
+! CHECK: %[[TTD_PTR_DECL:.*]]:2 = hlfir.declare %[[TTD_PTR_ALLOCA]]
+! CHECK: %[[TTD_D_ALLOCA:.*]] = fir.alloca !fir.type<_QMtypesTdt{a:i32,b:f32}> {bindc_name = "d", pinned, uniq_name = "_QFtarget_teams_distributeEd"}
+! CHECK: %[[TTD_D_DECL:.*]]:2 = hlfir.declare %[[TTD_D_ALLOCA]]
+! CHECK: %[[TTD_PTR_ARR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "ptr_arr", pinned, uniq_name = "_QFtarget_teams_distributeEptr_arr"}
+! CHECK: %[[TTD_PTR_ARR_DECL:.*]]:2 = hlfir.declare %[[TTD_PTR_ARR_ALLOCA]]
+! CHECK: omp.teams {
+! CHECK: fir.store %[[TTD_ASSUMED_DECL]]#0 to %[[TTD_ASSUMED_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: fir.store %[[TTD_AUTO_ARR_DECL]]#0 to %[[TTD_AUTO_ARR_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: omp.distribute private(
+! CHECK-SAME: @_QFtarget_teams_distributeEs_private_i32 %[[TTD_S_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEarr_private_10xi32 %[[TTD_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEalloc_private_box_heap_i32 %[[TTD_ALLOC_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEptr_private_box_ptr_i32 %[[TTD_PTR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEd_private_rec__QMtypesTdt %[[TTD_D_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEda_private_rec__QMtypesTdt_alloc %[[TTD_DA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEassumed_private_box_Uxi32 %[[TTD_ASSUMED_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEalloc_arr_private_box_heap_Uxi32 %[[TTD_ALLOC_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEptr_arr_private_box_ptr_Uxi32 %[[TTD_PTR_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEdaa_private_rec__QMtypesTdt_alloc_arr %[[TTD_DAA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEauto_arr_private_box_Uxi32 %[[TTD_AUTO_ARR_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distributeEi_private_i32 %[[TTD_I_DECL]]#0 -> %arg{{[0-9]+}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<i32>) {
+
+subroutine target_only(n, assumed)
+  use types
+  integer :: n, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  s = 1
+  !$omp end target
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_only
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[ONLY_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(tofrom) capture(ByRef) var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<i32>>, i32) name("")
+! CHECK: %[[ONLY_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, to) {{.*}} members(%[[ONLY_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>)
+! CHECK: %[[ONLY_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<i32>>, i32)
+! CHECK: %[[ONLY_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) capture(ByRef) mapper(@_QMtypesTdt_alloc_omp_default_mapper)
+! CHECK: %[[ONLY_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("")
+! CHECK: %[[ONLY_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, to) {{.*}} members(%[[ONLY_ASSUMED_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>)
+! CHECK: %[[ONLY_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, i32)
+! CHECK: %[[ONLY_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("")
+! CHECK: %[[ONLY_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, to) {{.*}} members(%[[ONLY_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>)
+! CHECK: %[[ONLY_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, i32)
+! CHECK: %[[ONLY_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) capture(ByRef) mapper(@_QMtypesTdt_alloc_arr_omp_default_mapper)
+! CHECK: %[[ONLY_AUTO_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("")
+! CHECK: %[[ONLY_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, to) {{.*}} members(%[[ONLY_AUTO_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>)
+! CHECK: %[[ONLY_AUTO_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, i32)
+! CHECK: omp.target kernel_type(generic) map_entries(%[[ONLY_ALLOC_MAP]] -> %{{.*}}, %[[ONLY_DA_MAP]] -> %{{.*}}, %[[ONLY_ASSUMED_MAP]] -> %{{.*}}, %[[ONLY_ALLOC_ARR_MAP]] -> %{{.*}}, %[[ONLY_DAA_MAP]] -> %{{.*}}, %[[ONLY_AUTO_ARR_MAP]] -> %{{.*}}, %[[ONLY_ALLOC_ATTACH]] -> %{{.*}}, %[[ONLY_ASSUMED_ATTACH]] -> %{{.*}}, %[[ONLY_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[ONLY_AUTO_ARR_ATTACH]] -> %{{.*}}, %[[ONLY_ALLOC_MEMBER]] -> %{{.*}}, %[[ONLY_ASSUMED_MEMBER]] -> %{{.*}}, %[[ONLY_ALLOC_ARR_MEMBER]] -> %{{.*}}, %[[ONLY_AUTO_ARR_MEMBER]] -> %{{.*}} : {{.*}}) private(
+! CHECK-SAME: @_QFtarget_onlyEs_private_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_onlyEarr_private_10xi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_onlyEalloc_private_box_heap_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}} [map_idx=0],
+! CHECK-SAME: @_QFtarget_onlyEptr_private_box_ptr_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_onlyEd_private_rec__QMtypesTdt %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_onlyEda_private_rec__QMtypesTdt_alloc %{{[0-9]+}}#0 -> %arg{{[0-9]+}} [map_idx=1],
+! CHECK-SAME: @_QFtarget_onlyEassumed_private_box_Uxi32 %{{[0-9]+}} -> %arg{{[0-9]+}} [map_idx=2],
+! CHECK-SAME: @_QFtarget_onlyEalloc_arr_private_box_heap_Uxi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}} [map_idx=3],
+! CHECK-SAME: @_QFtarget_onlyEptr_arr_private_box_ptr_Uxi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_onlyEdaa_private_rec__QMtypesTdt_alloc_arr %{{[0-9]+}}#0 -> %arg{{[0-9]+}} [map_idx=4],
+! CHECK-SAME: @_QFtarget_onlyEauto_arr_private_box_Uxi32 %{{[0-9]+}} -> %arg{{[0-9]+}} [map_idx=5] : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>) {
+
+subroutine target_nested(n, assumed)
+  use types
+  integer :: n, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target
+  !$omp parallel private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  s = 1
+  !$omp end parallel
+  !$omp end target
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_nested
+! CHECK: %[[NEST_S_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("s")
+! CHECK: %[[NEST_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("arr")
+! CHECK: %[[NEST_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[NEST_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[NEST_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[NEST_PTR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[NEST_PTR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_PTR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("ptr")
+! CHECK: %[[NEST_PTR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("ptr")
+! CHECK: %[[NEST_D_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("d")
+! CHECK: %[[NEST_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[NEST_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[NEST_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[NEST_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[NEST_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[NEST_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[NEST_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[NEST_PTR_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[NEST_PTR_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_PTR_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("ptr_arr")
+! CHECK: %[[NEST_PTR_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("ptr_arr")
+! CHECK: %[[NEST_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[NEST_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[NEST_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(generic) map_entries(%[[NEST_S_MAP]] -> %{{.*}}, %[[NEST_ARR_MAP]] -> %{{.*}}, %[[NEST_ALLOC_MAP]] -> %{{.*}}, %[[NEST_PTR_MAP]] -> %{{.*}}, %[[NEST_D_MAP]] -> %{{.*}}, %[[NEST_DA_MAP]] -> %{{.*}}, %[[NEST_ASSUMED_MAP]] -> %{{.*}}, %[[NEST_ALLOC_ARR_MAP]] -> %{{.*}}, %[[NEST_PTR_ARR_MAP]] -> %{{.*}}, %[[NEST_DAA_MAP]] -> %{{.*}}, %[[NEST_AUTO_ARR_MAP]] -> %{{.*}}, %[[NEST_N_MAP]] -> %{{.*}}, %[[NEST_ALLOC_ATTACH]] -> %{{.*}}, %[[NEST_PTR_ATTACH]] -> %{{.*}}, %[[NEST_ASSUMED_ATTACH]] -> %{{.*}}, %[[NEST_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[NEST_PTR_ARR_ATTACH]] -> %{{.*}}, %[[NEST_ALLOC_MEMBER]] -> %{{.*}}, %[[NEST_PTR_MEMBER]] -> %{{.*}}, %[[NEST_ASSUMED_MEMBER]] -> %{{.*}}, %[[NEST_ALLOC_ARR_MEMBER]] -> %{{.*}}, %[[NEST_PTR_ARR_MEMBER]] -> %{{.*}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: omp.parallel private(
+! CHECK-SAME: @_QFtarget_nestedEs_private_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEarr_private_10xi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEalloc_private_box_heap_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEptr_private_box_ptr_i32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEd_private_rec__QMtypesTdt %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEda_private_rec__QMtypesTdt_alloc %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEassumed_private_box_Uxi32 %{{[0-9]+}} -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEalloc_arr_private_box_heap_Uxi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEptr_arr_private_box_ptr_Uxi32 %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEdaa_private_rec__QMtypesTdt_alloc_arr %{{[0-9]+}}#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_nestedEauto_arr_private_box_Uxi32 %{{[0-9]+}} -> %arg{{[0-9]+}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>) {
+
+subroutine target_teams_distribute_simd(n, assumed)
+  use types
+  integer :: n, i, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target teams distribute simd private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  do i = 1, n
+    s = i
+  end do
+  !$omp end target teams distribute simd
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_teams_distribute_simd
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[TTDS_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTDS_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTDS_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[TTDS_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[TTDS_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[TTDS_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTDS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTDS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TTDS_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[TTDS_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[TTDS_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTDS_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[TTDS_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[TTDS_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[TTDS_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[TTDS_I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: %[[TTDS_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[TTDS_BOUND_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(generic) host_eval({{.*}}) map_entries(%[[TTDS_ALLOC_MAP]] -> %{{.*}}, %[[TTDS_DA_MAP]] -> %{{.*}}, %[[TTDS_ASSUMED_MAP]] -> %{{.*}}, %[[TTDS_ALLOC_ARR_MAP]] -> %{{.*}}, %[[TTDS_DAA_MAP]] -> %{{.*}}, %[[TTDS_AUTO_ARR_MAP]] -> %{{.*}}, %[[TTDS_I_MAP]] -> %{{.*}}, %[[TTDS_N_MAP]] -> %{{.*}}, %[[TTDS_BOUND_N_MAP]] -> %{{.*}}, %[[TTDS_ALLOC_ATTACH]] -> %{{.*}}, %[[TTDS_ASSUMED_ATTACH]] -> %{{.*}}, %[[TTDS_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[TTDS_ALLOC_MEMBER]] -> %{{.*}}, %[[TTDS_ASSUMED_MEMBER]] -> %{{.*}}, %[[TTDS_ALLOC_ARR_MEMBER]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: %[[TTDS_ALLOC_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teams_distribute_simdEalloc"}
+! CHECK: %[[TTDS_DA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distribute_simdEda"}
+! CHECK: %[[TTDS_ASSUMED_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distribute_simdEassumed"}
+! CHECK: %[[TTDS_ALLOC_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_teams_distribute_simdEalloc_arr"}
+! CHECK: %[[TTDS_DAA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distribute_simdEdaa"}
+! CHECK: %[[TTDS_AUTO_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}}(%{{.*}}) {uniq_name = "_QFtarget_teams_distribute_simdEauto_arr"}
+! CHECK: %[[TTDS_I_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_teams_distribute_simdEi"}
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "da", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "assumed", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc_arr", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "daa", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "auto_arr", pinned
+! CHECK: %[[TTDS_S_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "s", pinned, uniq_name = "_QFtarget_teams_distribute_simdEs"}
+! CHECK: %[[TTDS_S_DECL:.*]]:2 = hlfir.declare %[[TTDS_S_ALLOCA]]
+! CHECK: %[[TTDS_ARR_ALLOCA:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "arr", pinned, uniq_name = "_QFtarget_teams_distribute_simdEarr"}
+! CHECK: %[[TTDS_ARR_DECL:.*]]:2 = hlfir.declare %[[TTDS_ARR_ALLOCA]]
+! CHECK: %[[TTDS_PTR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "ptr", pinned, uniq_name = "_QFtarget_teams_distribute_simdEptr"}
+! CHECK: %[[TTDS_PTR_DECL:.*]]:2 = hlfir.declare %[[TTDS_PTR_ALLOCA]]
+! CHECK: %[[TTDS_D_ALLOCA:.*]] = fir.alloca !fir.type<_QMtypesTdt{a:i32,b:f32}> {bindc_name = "d", pinned, uniq_name = "_QFtarget_teams_distribute_simdEd"}
+! CHECK: %[[TTDS_D_DECL:.*]]:2 = hlfir.declare %[[TTDS_D_ALLOCA]]
+! CHECK: %[[TTDS_PTR_ARR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "ptr_arr", pinned, uniq_name = "_QFtarget_teams_distribute_simdEptr_arr"}
+! CHECK: %[[TTDS_PTR_ARR_DECL:.*]]:2 = hlfir.declare %[[TTDS_PTR_ARR_ALLOCA]]
+! CHECK: omp.teams {
+! CHECK: fir.store %[[TTDS_ASSUMED_DECL]]#0 to %[[TTDS_ASSUMED_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: fir.store %[[TTDS_AUTO_ARR_DECL]]#0 to %[[TTDS_AUTO_ARR_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: omp.distribute {
+! CHECK: omp.simd private(
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEs_private_i32 %[[TTDS_S_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEarr_private_10xi32 %[[TTDS_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEalloc_private_box_heap_i32 %[[TTDS_ALLOC_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEptr_private_box_ptr_i32 %[[TTDS_PTR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEd_private_rec__QMtypesTdt %[[TTDS_D_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEda_private_rec__QMtypesTdt_alloc %[[TTDS_DA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEassumed_private_box_Uxi32 %[[TTDS_ASSUMED_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEalloc_arr_private_box_heap_Uxi32 %[[TTDS_ALLOC_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEptr_arr_private_box_ptr_Uxi32 %[[TTDS_PTR_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEdaa_private_rec__QMtypesTdt_alloc_arr %[[TTDS_DAA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEauto_arr_private_box_Uxi32 %[[TTDS_AUTO_ARR_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_teams_distribute_simdEi_private_i32 %[[TTDS_I_DECL]]#0 -> %arg{{[0-9]+}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<i32>) {
+
+subroutine target_parallel_do(n, assumed)
+  use types
+  integer :: n, i, s, arr(10), assumed(:)
+  integer, allocatable :: alloc, alloc_arr(:)
+  integer, pointer :: ptr, ptr_arr(:)
+  type(dt) :: d
+  type(dt_alloc) :: da
+  type(dt_alloc_arr) :: daa
+  integer :: auto_arr(n)
+  !$omp target parallel do private(s, arr, alloc, ptr, d, da, assumed, alloc_arr, ptr_arr, daa, auto_arr)
+  do i = 1, n
+    s = i
+  end do
+  !$omp end target parallel do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_parallel_do
+! CHECK-NOT: omp.map.info {{.*}} name("s")
+! CHECK-NOT: omp.map.info {{.*}} name("arr")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr")
+! CHECK-NOT: omp.map.info {{.*}} name("d")
+! CHECK-NOT: omp.map.info {{.*}} name("ptr_arr")
+! CHECK: %[[PDO_ALLOC_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PDO_ALLOC_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PDO_ALLOC_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) name("alloc")
+! CHECK: %[[PDO_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
+! CHECK: %[[PDO_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
+! CHECK: %[[PDO_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PDO_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PDO_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[PDO_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
+! CHECK: %[[PDO_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
+! CHECK: %[[PDO_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PDO_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
+! CHECK: %[[PDO_ALLOC_ARR_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc_arr")
+! CHECK: %[[PDO_DAA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("daa")
+! CHECK: %[[PDO_AUTO_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("auto_arr")
+! CHECK: %[[PDO_I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: %[[PDO_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[PDO_BOUND_N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("")
+! CHECK: omp.target kernel_type(spmd) host_eval({{.*}}) map_entries(%[[PDO_ALLOC_MAP]] -> %{{.*}}, %[[PDO_DA_MAP]] -> %{{.*}}, %[[PDO_ASSUMED_MAP]] -> %{{.*}}, %[[PDO_ALLOC_ARR_MAP]] -> %{{.*}}, %[[PDO_DAA_MAP]] -> %{{.*}}, %[[PDO_AUTO_ARR_MAP]] -> %{{.*}}, %[[PDO_I_MAP]] -> %{{.*}}, %[[PDO_N_MAP]] -> %{{.*}}, %[[PDO_BOUND_N_MAP]] -> %{{.*}}, %[[PDO_ALLOC_ATTACH]] -> %{{.*}}, %[[PDO_ASSUMED_ATTACH]] -> %{{.*}}, %[[PDO_ALLOC_ARR_ATTACH]] -> %{{.*}}, %[[PDO_ALLOC_MEMBER]] -> %{{.*}}, %[[PDO_ASSUMED_MEMBER]] -> %{{.*}}, %[[PDO_ALLOC_ARR_MEMBER]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<i32>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+! CHECK: %[[PDO_ALLOC_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_parallel_doEalloc"}
+! CHECK: %[[PDO_DA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallel_doEda"}
+! CHECK: %[[PDO_ASSUMED_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallel_doEassumed"}
+! CHECK: %[[PDO_ALLOC_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtarget_parallel_doEalloc_arr"}
+! CHECK: %[[PDO_DAA_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallel_doEdaa"}
+! CHECK: %[[PDO_AUTO_ARR_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}}(%{{.*}}) {uniq_name = "_QFtarget_parallel_doEauto_arr"}
+! CHECK: %[[PDO_I_DECL:.*]]:2 = hlfir.declare %arg{{[0-9]+}} {uniq_name = "_QFtarget_parallel_doEi"}
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "da", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "assumed", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "alloc_arr", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "daa", pinned
+! CHECK-NOT: fir.alloca {{.*}} {bindc_name = "auto_arr", pinned
+! CHECK: %[[PDO_S_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "s", pinned, uniq_name = "_QFtarget_parallel_doEs"}
+! CHECK: %[[PDO_S_DECL:.*]]:2 = hlfir.declare %[[PDO_S_ALLOCA]]
+! CHECK: %[[PDO_ARR_ALLOCA:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "arr", pinned, uniq_name = "_QFtarget_parallel_doEarr"}
+! CHECK: %[[PDO_ARR_DECL:.*]]:2 = hlfir.declare %[[PDO_ARR_ALLOCA]]
+! CHECK: %[[PDO_PTR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "ptr", pinned, uniq_name = "_QFtarget_parallel_doEptr"}
+! CHECK: %[[PDO_PTR_DECL:.*]]:2 = hlfir.declare %[[PDO_PTR_ALLOCA]]
+! CHECK: %[[PDO_D_ALLOCA:.*]] = fir.alloca !fir.type<_QMtypesTdt{a:i32,b:f32}> {bindc_name = "d", pinned, uniq_name = "_QFtarget_parallel_doEd"}
+! CHECK: %[[PDO_D_DECL:.*]]:2 = hlfir.declare %[[PDO_D_ALLOCA]]
+! CHECK: %[[PDO_PTR_ARR_ALLOCA:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "ptr_arr", pinned, uniq_name = "_QFtarget_parallel_doEptr_arr"}
+! CHECK: %[[PDO_PTR_ARR_DECL:.*]]:2 = hlfir.declare %[[PDO_PTR_ARR_ALLOCA]]
+! CHECK: omp.parallel {
+! CHECK: fir.store %[[PDO_ASSUMED_DECL]]#0 to %[[PDO_ASSUMED_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: fir.store %[[PDO_AUTO_ARR_DECL]]#0 to %[[PDO_AUTO_ARR_COPY:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+! CHECK: omp.wsloop private(
+! CHECK-SAME: @_QFtarget_parallel_doEs_private_i32 %[[PDO_S_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEarr_private_10xi32 %[[PDO_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEalloc_private_box_heap_i32 %[[PDO_ALLOC_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEptr_private_box_ptr_i32 %[[PDO_PTR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEd_private_rec__QMtypesTdt %[[PDO_D_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEda_private_rec__QMtypesTdt_alloc %[[PDO_DA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEassumed_private_box_Uxi32 %[[PDO_ASSUMED_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEalloc_arr_private_box_heap_Uxi32 %[[PDO_ALLOC_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEptr_arr_private_box_ptr_Uxi32 %[[PDO_PTR_ARR_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEdaa_private_rec__QMtypesTdt_alloc_arr %[[PDO_DAA_DECL]]#0 -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEauto_arr_private_box_Uxi32 %[[PDO_AUTO_ARR_COPY]] -> %arg{{[0-9]+}},
+! CHECK-SAME: @_QFtarget_parallel_doEi_private_i32 %[[PDO_I_DECL]]#0 -> %arg{{[0-9]+}} : !fir.ref<i32>, !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.type<_QMtypesTdt{a:i32,b:f32}>>, !fir.ref<!fir.type<_QMtypesTdt_alloc{a:!fir.box<!fir.heap<i32>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.type<_QMtypesTdt_alloc_arr{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<i32>) {
diff --git a/flang/test/Lower/OpenMP/target-parallel-private.f90 b/flang/test/Lower/OpenMP/target-parallel-private.f90
index f1b7959cee83be..0aba046585bcfb 100644
--- a/flang/test/Lower/OpenMP/target-parallel-private.f90
+++ b/flang/test/Lower/OpenMP/target-parallel-private.f90
@@ -15,7 +15,7 @@ subroutine target_parallel_private()
 
 ! CHECK: omp.private {type = private} @[[PRIVATIZER:.*]] : {{.*}}
 
-! CHECK: omp.target kernel_type(generic) {{.*}} {
+! CHECK: omp.target kernel_type(generic) {
 ! CHECK:   omp.parallel private(@[[PRIVATIZER]] %{{.*}} -> %{{.*}} : {{.*}}) {
 ! CHECK:   }
 ! CHECK: }
diff --git a/flang/test/Lower/OpenMP/target-teams-private.f90 b/flang/test/Lower/OpenMP/target-teams-private.f90
index c4306348c6d446..8a0e82514fbda8 100644
--- a/flang/test/Lower/OpenMP/target-teams-private.f90
+++ b/flang/test/Lower/OpenMP/target-teams-private.f90
@@ -13,7 +13,7 @@ subroutine target_teams_private()
 !$omp end target teams
 end subroutine
 
-! CHECK: omp.target kernel_type(generic) {{.*}} {
+! CHECK: omp.target kernel_type(generic) {
 ! CHECK:   omp.teams {
 ! CHECK:     %{{.*}} = fir.alloca !fir.array<3xi32> {bindc_name = "i", {{.*}}}
 ! CHECK:   }

>From e45b94778e5c624d7ceac61f6ebb3e860767793a Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 11 Sep 2026 15:46:42 -0500
Subject: [PATCH 2/2] [Flang][OpenMP] Update to support exclusion of private
 variables that also show up in other clauses on directive

---
 flang/include/flang/Lower/OpenMP/Clauses.h    | 110 ++++++++++++++++++
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  43 ++++++-
 ...target-composite-private-host-eval-map.f90 |  61 ++++++++++
 .../target-composite-private-unified.f90      |  12 +-
 ...target-composite-private-host-eval-map.f90 |  62 ++++++++++
 5 files changed, 278 insertions(+), 10 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/target-composite-private-host-eval-map.f90
 create mode 100644 offload/test/offloading/fortran/target-composite-private-host-eval-map.f90

diff --git a/flang/include/flang/Lower/OpenMP/Clauses.h b/flang/include/flang/Lower/OpenMP/Clauses.h
index f2ce74301a2388..21718e9cd1836a 100644
--- a/flang/include/flang/Lower/OpenMP/Clauses.h
+++ b/flang/include/flang/Lower/OpenMP/Clauses.h
@@ -9,6 +9,7 @@
 #define FORTRAN_LOWER_OPENMP_CLAUSES_H
 
 #include "flang/Evaluate/expression.h"
+#include "flang/Evaluate/tools.h"
 #include "flang/Evaluate/type.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/expression.h"
@@ -20,6 +21,7 @@
 #include "llvm/Frontend/OpenMP/OMP.h.inc"
 
 #include <optional>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -378,6 +380,114 @@ struct Clause : public ClauseBase {
   parser::CharBlock source;
 };
 
+namespace detail {
+template <typename T, typename = void>
+struct HasClauseWrapperTrait : std::false_type {};
+template <typename T>
+struct HasClauseWrapperTrait<T, std::void_t<typename T::WrapperTrait>>
+    : T::WrapperTrait {};
+
+template <typename T, typename = void>
+struct HasClauseTupleTrait : std::false_type {};
+template <typename T>
+struct HasClauseTupleTrait<T, std::void_t<typename T::TupleTrait>>
+    : T::TupleTrait {};
+
+template <typename T, typename = void>
+struct HasClauseUnionTrait : std::false_type {};
+template <typename T>
+struct HasClauseUnionTrait<T, std::void_t<typename T::UnionTrait>>
+    : T::UnionTrait {};
+
+template <typename T>
+struct IsStdOptional : std::false_type {};
+template <typename T>
+struct IsStdOptional<std::optional<T>> : std::true_type {};
+
+template <typename T>
+struct IsStdTuple : std::false_type {};
+template <typename... Ts>
+struct IsStdTuple<std::tuple<Ts...>> : std::true_type {};
+} // namespace detail
+
+template <typename T, typename Callback>
+bool visitSymbolsInClausePayload(const T &value, Callback callback);
+
+template <typename Callback>
+bool visitSymbolsInClausePayload(const SomeExpr &expr, Callback callback) {
+  for (semantics::SymbolRef ref : evaluate::CollectSymbols(expr))
+    if (callback(*ref))
+      return true;
+  return false;
+}
+
+template <typename Callback>
+bool visitSymbolsInClausePayload(const Object &object, Callback callback) {
+  if (const semantics::Symbol *sym = object.sym())
+    if (callback(*sym))
+      return true;
+
+  // Include references appearing in designators, such as array section bounds
+  // or subscripts in map/depend list items.
+  if (object.ref())
+    return visitSymbolsInClausePayload(*object.ref(), callback);
+
+  return false;
+}
+
+template <typename Callback>
+bool visitSymbolsInClausePayload(const ObjectList &objects, Callback callback) {
+  for (const Object &object : objects)
+    if (visitSymbolsInClausePayload(object, callback))
+      return true;
+  return false;
+}
+
+template <typename T, unsigned N, typename Callback>
+bool visitSymbolsInClausePayload(const llvm::SmallVector<T, N> &values,
+                                 Callback callback) {
+  for (const T &value : values)
+    if (visitSymbolsInClausePayload(value, callback))
+      return true;
+  return false;
+}
+
+template <typename T, typename Callback>
+bool visitSymbolsInClausePayload(const T &value, Callback callback) {
+  using U = llvm::remove_cvref_t<T>;
+
+  if constexpr (detail::IsStdOptional<U>::value) {
+    return value && visitSymbolsInClausePayload(*value, callback);
+  } else if constexpr (detail::IsStdTuple<U>::value) {
+    return std::apply(
+        [&](const auto &...tupleValues) {
+          return (visitSymbolsInClausePayload(tupleValues, callback) || ...);
+        },
+        value);
+  } else if constexpr (detail::HasClauseWrapperTrait<U>::value) {
+    return visitSymbolsInClausePayload(value.v, callback);
+  } else if constexpr (detail::HasClauseTupleTrait<U>::value) {
+    return visitSymbolsInClausePayload(value.t, callback);
+  } else if constexpr (detail::HasClauseUnionTrait<U>::value) {
+    return Fortran::common::visit(
+        [&](const auto &variantValue) {
+          return visitSymbolsInClausePayload(variantValue, callback);
+        },
+        value.u);
+  } else {
+    return false;
+  }
+}
+
+template <typename Callback>
+bool visitSymbolsInClause(const Clause &clause, Callback callback) {
+  return Fortran::common::visit(
+      [&](const auto &specificClause) {
+        return visitSymbolsInClausePayload(specificClause, callback);
+      },
+      clause.u);
+}
+
 template <typename Specific>
 Clause makeClause(llvm::omp::Clause id, Specific &&specific,
                   parser::CharBlock source = {}) {
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index e8885c2c15cdd5..d01193b7db0554 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -69,6 +69,8 @@
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Frontend/OpenMP/OMP.h"
 #include <atomic>
+#include <tuple>
+#include <type_traits>
 
 using namespace Fortran::lower::omp;
 using namespace Fortran::common::openmp;
@@ -4125,6 +4127,35 @@ findInnermostPrivateLeaf(ConstructQueue::const_iterator item,
 // clause). Currently we leave these as they were before, but in the future we
 // can minimize the mapping by sending across exactly what we require to be
 // specification compliant.
+static bool isSymbolUsedInNonPrivateClause(const semantics::Symbol &target,
+                                           ConstructQueue::const_iterator item,
+                                           const ConstructQueue &queue) {
+  const semantics::Symbol &ultimateTarget = target.GetUltimate();
+
+  // Start at the first nested leaf. The target leaf may contain implementation
+  // clauses synthesized while decomposing private list items on nested leaves;
+  // those should not make a private-only source variable look like it also
+  // appeared in another user clause.
+  for (ConstructQueue::const_iterator it = std::next(item); it != queue.end();
+       ++it) {
+    for (const Clause &clause : it->clauses) {
+      // Do not consider private itself. Also do not consider map clauses here:
+      // explicit target-level maps are already accounted for via mapObjects,
+      // and construct decomposition may synthesize map-like clauses for nested
+      // private list items.
+      if (clause.id == llvm::omp::Clause::OMPC_private ||
+          clause.id == llvm::omp::Clause::OMPC_map)
+        continue;
+
+      if (visitSymbolsInClause(clause, [&](const semantics::Symbol &sym) {
+            return sym.GetUltimate() == ultimateTarget;
+          }))
+        return true;
+    }
+  }
+  return false;
+}
+
 static bool isTargetLocalCloneable(const semantics::Symbol &sym,
                                    semantics::SemanticsContext &semaCtx) {
   const semantics::Symbol &ult = sym.GetUltimate();
@@ -4176,16 +4207,20 @@ static void collectTargetNestedPrivateSyms(
     bool &innermostLeafIsTeams) {
   innermostLeafIsTeams = false;
 
-  // Avoid capturing symbols on anything with explicit mapping or privatization.
+  // Avoid capturing symbols on anything with explicit mapping, privatization,
+  // or any other clause-level use that relies on the original symbol.
   auto isExcluded = [&](const semantics::Symbol *sym) {
     const semantics::Symbol &ult = sym->GetUltimate();
     if (llvm::any_of(mapObjects, [&](const Object &o) {
           return o.sym() && o.sym()->GetUltimate() == ult;
         }))
       return true;
-    return llvm::any_of(
-        dsp.getAllSymbolsToPrivatize(),
-        [&](const semantics::Symbol *p) { return p->GetUltimate() == ult; });
+    if (llvm::any_of(dsp.getAllSymbolsToPrivatize(),
+                     [&](const semantics::Symbol *p) {
+                       return p->GetUltimate() == ult;
+                     }))
+      return true;
+    return isSymbolUsedInNonPrivateClause(*sym, item, queue);
   };
 
   ConstructQueue::const_iterator innermostPrivateLeaf =
diff --git a/flang/test/Lower/OpenMP/target-composite-private-host-eval-map.f90 b/flang/test/Lower/OpenMP/target-composite-private-host-eval-map.f90
new file mode 100644
index 00000000000000..a48c9963b77c03
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-composite-private-host-eval-map.f90
@@ -0,0 +1,61 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+subroutine target_parallel_do_private_num_threads(n, out)
+  integer :: n, out, i
+  out = 0
+  !$omp target parallel do private(n) num_threads(n) map(tofrom: out)
+  do i = 1, 4
+    n = i
+    out = out + n
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_parallel_do_private_num_threads
+! CHECK: %[[N_VAL:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK: %[[OUT_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("out")
+! CHECK: %[[N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: omp.target kernel_type(spmd) host_eval({{.*}}, %[[N_VAL]] -> %[[N_HOST_ARG:arg[0-9]+]] : {{.*}}) map_entries(%[[OUT_MAP]] -> %{{.*}}, %[[N_MAP]] -> %[[N_MAP_ARG:arg[0-9]+]], %[[I_MAP]] -> %{{.*}} : {{.*}}) {
+! CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %[[N_MAP_ARG]] {uniq_name = "_QFtarget_parallel_do_private_num_threadsEn"}
+! CHECK: omp.parallel num_threads(%[[N_HOST_ARG]] : i32) {
+! CHECK: omp.wsloop private({{.*}}@_QFtarget_parallel_do_private_num_threadsEn_private_i32 %[[N_DECL]]#0 -> %arg{{[0-9]+}}
+
+subroutine target_teams_distribute_private_thread_limit(n, out)
+  integer :: n, out, i
+  out = 0
+  !$omp target teams distribute private(n) thread_limit(n) map(tofrom: out)
+  do i = 1, 4
+    n = i
+    out = out + n
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_teams_distribute_private_thread_limit
+! CHECK: %[[OUT_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("out")
+! CHECK: %[[N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: omp.target kernel_type(generic) host_eval({{.*}}) map_entries(%[[OUT_MAP]] -> %{{.*}}, %[[N_MAP]] -> %[[N_MAP_ARG:arg[0-9]+]], %[[I_MAP]] -> %{{.*}} : {{.*}}) {
+! CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %[[N_MAP_ARG]] {uniq_name = "_QFtarget_teams_distribute_private_thread_limitEn"}
+! CHECK: %[[N_LOAD:.*]] = fir.load %[[N_DECL]]#0 : !fir.ref<i32>
+! CHECK: omp.teams thread_limit(%[[N_LOAD]] : i32) {
+! CHECK: omp.distribute private({{.*}}@_QFtarget_teams_distribute_private_thread_limitEn_private_i32 %[[N_DECL]]#0 -> %arg{{[0-9]+}}
+
+subroutine target_teams_distribute_private_num_teams(n, out)
+  integer :: n, out, i
+  out = 0
+  !$omp target teams distribute private(n) num_teams(n) map(tofrom: out)
+  do i = 1, 4
+    n = i
+    out = out + n
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtarget_teams_distribute_private_num_teams
+! CHECK: %[[N_VAL:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK: %[[OUT_MAP:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} name("out")
+! CHECK: %[[N_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("n")
+! CHECK: %[[I_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit) capture(ByCopy) name("i")
+! CHECK: omp.target kernel_type(generic) host_eval({{.*}}, %[[N_VAL]] -> %[[N_HOST_ARG:arg[0-9]+]] : {{.*}}) map_entries(%[[OUT_MAP]] -> %{{.*}}, %[[N_MAP]] -> %[[N_MAP_ARG:arg[0-9]+]], %[[I_MAP]] -> %{{.*}} : {{.*}}) {
+! CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %[[N_MAP_ARG]] {uniq_name = "_QFtarget_teams_distribute_private_num_teamsEn"}
+! CHECK: omp.teams num_teams( to %[[N_HOST_ARG]] : i32) {
+! CHECK: omp.distribute private({{.*}}@_QFtarget_teams_distribute_private_num_teamsEn_private_i32 %[[N_DECL]]#0 -> %arg{{[0-9]+}}
diff --git a/flang/test/Lower/OpenMP/target-composite-private-unified.f90 b/flang/test/Lower/OpenMP/target-composite-private-unified.f90
index 27e626b45ce3cc..da2c082f61b817 100644
--- a/flang/test/Lower/OpenMP/target-composite-private-unified.f90
+++ b/flang/test/Lower/OpenMP/target-composite-private-unified.f90
@@ -38,7 +38,7 @@ subroutine target_teams(n, assumed)
 ! CHECK: %[[TEAMS_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
 ! CHECK: %[[TEAMS_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[TEAMS_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[TEAMS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TEAMS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TEAMS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[TEAMS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[TEAMS_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[TEAMS_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[TEAMS_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TEAMS_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
@@ -91,7 +91,7 @@ subroutine target_parallel(n, assumed)
 ! CHECK: %[[PAR_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
 ! CHECK: %[[PAR_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[PAR_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[PAR_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PAR_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[PAR_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[PAR_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[PAR_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[PAR_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[PAR_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PAR_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
@@ -164,7 +164,7 @@ subroutine target_teams_distribute(n, assumed)
 ! CHECK: %[[TTD_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
 ! CHECK: %[[TTD_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[TTD_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[TTD_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTD_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TTD_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[TTD_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[TTD_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[TTD_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[TTD_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTD_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
@@ -290,7 +290,7 @@ subroutine target_nested(n, assumed)
 ! CHECK: %[[NEST_D_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("d")
 ! CHECK: %[[NEST_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[NEST_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[NEST_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[NEST_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[NEST_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[NEST_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[NEST_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[NEST_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[NEST_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
@@ -342,7 +342,7 @@ subroutine target_teams_distribute_simd(n, assumed)
 ! CHECK: %[[TTDS_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
 ! CHECK: %[[TTDS_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[TTDS_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[TTDS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTDS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[TTDS_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[TTDS_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[TTDS_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[TTDS_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[TTDS_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[TTDS_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
@@ -421,7 +421,7 @@ subroutine target_parallel_do(n, assumed)
 ! CHECK: %[[PDO_ALLOC_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("alloc")
 ! CHECK: %[[PDO_DA_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("da")
 ! CHECK: %[[PDO_ASSUMED_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
-! CHECK: %[[PDO_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PDO_ASSUMED_MEMBER]] {{.*}}) name("assumed")
+! CHECK: %[[PDO_ASSUMED_MAP:.*]] = omp.map.info {{.*}} map_clauses(implicit, target_param, private, attach) {{.*}} members(%[[PDO_ASSUMED_MEMBER]] {{.*}}) name("assumed")
 ! CHECK: %[[PDO_ASSUMED_ATTACH:.*]] = omp.map.info {{.*}} map_clauses(attach, ref_ptr, ref_ptee) {{.*}} name("assumed")
 ! CHECK: %[[PDO_ALLOC_ARR_MEMBER:.*]] = omp.map.info {{.*}} map_clauses(implicit, tofrom) {{.*}} name("")
 ! CHECK: %[[PDO_ALLOC_ARR_MAP:.*]] = omp.map.info {{.*}} map_clauses(always, implicit, to) {{.*}} members(%[[PDO_ALLOC_ARR_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) name("alloc_arr")
diff --git a/offload/test/offloading/fortran/target-composite-private-host-eval-map.f90 b/offload/test/offloading/fortran/target-composite-private-host-eval-map.f90
new file mode 100644
index 00000000000000..3817b0046e1d42
--- /dev/null
+++ b/offload/test/offloading/fortran/target-composite-private-host-eval-map.f90
@@ -0,0 +1,62 @@
+! Test that host-evaluated clause operands are still available when the
+! referenced scalar is also privatized on an inner leaf of a composite target
+! construct. Indicating that we have not optimized the implicit map out due
+! to privatization.
+!
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+! XFAIL: intelgpu
+
+program main
+  implicit none
+  integer :: errors
+
+  errors = 0
+
+  call check_parallel_do_num_threads(4, errors)
+  call check_teams_num_teams(4, errors)
+
+  print *, "errors:", errors
+
+contains
+  subroutine check_parallel_do_num_threads(n, errors)
+    use omp_lib
+    implicit none
+    integer :: n
+    integer, intent(inout) :: errors
+    integer :: observed
+    integer :: i
+
+    observed = -1
+    !$omp target parallel do private(n) num_threads(n) map(tofrom: observed)
+    do i = 1, 1
+      observed = omp_get_num_threads()
+      n = 99
+    end do
+    !$omp end target parallel do
+
+    if (observed .ne. n) errors = errors + 1
+  end subroutine
+
+  subroutine check_teams_num_teams(n, errors)
+    use omp_lib
+    implicit none
+    integer :: n
+    integer, intent(inout) :: errors
+    integer :: observed
+    integer :: i
+
+    observed = -1
+    !$omp target teams distribute private(n) num_teams(n) map(tofrom: observed)
+    do i = 1, 1
+      observed = omp_get_num_teams()
+      n = 99
+    end do
+    !$omp end target teams distribute
+
+    if (observed .ne. n) errors = errors + 1
+  end subroutine
+end program main
+
+! CHECK: errors: 0



More information about the flang-commits mailing list