https://github.com/jeanPerier updated 
https://github.com/llvm/llvm-project/pull/171501

>From 9dd6758cb6322eb3224794657e5122c7d689c309 Mon Sep 17 00:00:00 2001
From: Jean Perier <[email protected]>
Date: Mon, 8 Dec 2025 07:59:43 -0800
Subject: [PATCH 1/2] [flang][OpenACC] remap component references in structured
 constructs

---
 flang/include/flang/Lower/AbstractConverter.h |   1 +
 flang/include/flang/Lower/Support/Utils.h     |  43 +-
 flang/include/flang/Lower/SymbolMap.h         |  74 +++
 flang/lib/Lower/ConvertExprToHLFIR.cpp        |  16 +-
 flang/lib/Lower/OpenACC.cpp                   | 565 ++++++++++--------
 flang/lib/Lower/Support/Utils.cpp             |  15 +
 flang/lib/Lower/SymbolMap.cpp                 |  22 +
 flang/test/Lower/OpenACC/acc-host-data.f90    |  13 +-
 .../OpenACC/acc-use-device-remapping.f90      | 156 +++++
 flang/test/Lower/OpenACC/acc-use-device.f90   |  12 +-
 .../acc-implicit-data-derived-type-member.F90 |   2 +-
 11 files changed, 637 insertions(+), 282 deletions(-)
 create mode 100644 flang/test/Lower/OpenACC/acc-use-device-remapping.f90

diff --git a/flang/include/flang/Lower/AbstractConverter.h 
b/flang/include/flang/Lower/AbstractConverter.h
index f93f7ad867b30..8109ebdc75688 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -16,6 +16,7 @@
 #include "flang/Lower/LoweringOptions.h"
 #include "flang/Lower/PFTDefs.h"
 #include "flang/Lower/Support/Utils.h"
+#include "flang/Lower/SymbolMap.h"
 #include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Dialect/FIRAttr.h"
 #include "flang/Semantics/symbol.h"
diff --git a/flang/include/flang/Lower/Support/Utils.h 
b/flang/include/flang/Lower/Support/Utils.h
index eac5cad91f608..4e83a0e3bfec7 100644
--- a/flang/include/flang/Lower/Support/Utils.h
+++ b/flang/include/flang/Lower/Support/Utils.h
@@ -14,7 +14,6 @@
 #define FORTRAN_LOWER_SUPPORT_UTILS_H
 
 #include "flang/Common/indirection.h"
-#include "flang/Lower/IterationSpace.h"
 #include "flang/Parser/char-block.h"
 #include "flang/Semantics/tools.h"
 #include "mlir/Dialect/Arith/IR/Arith.h"
@@ -23,10 +22,25 @@
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringRef.h"
 
+namespace Fortran::evaluate {
+class Component;
+class ArrayRef;
+} // namespace Fortran::evaluate
+
 namespace Fortran::lower {
 using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>;
+using ExplicitSpaceArrayBases =
+    std::variant<const semantics::Symbol *, const evaluate::Component *,
+                 const evaluate::ArrayRef *>;
+// FIXME: needed for privatizeSymbol that does not belong to this header.
+class AbstractConverter;
+class SymMap;
 } // end namespace Fortran::lower
 
+namespace fir {
+class FirOpBuilder;
+}
+
 
//===----------------------------------------------------------------------===//
 // Small inline helper functions to deal with repetitive, clumsy conversions.
 
//===----------------------------------------------------------------------===//
@@ -89,12 +103,15 @@ A flatZip(const A &container1, const A &container2) {
 
 namespace Fortran::lower {
 unsigned getHashValue(const Fortran::lower::SomeExpr *x);
-unsigned getHashValue(const Fortran::lower::ExplicitIterSpace::ArrayBases &x);
+unsigned getHashValue(const Fortran::lower::ExplicitSpaceArrayBases &x);
+unsigned getHashValue(const Fortran::evaluate::Component *x);
 
 bool isEqual(const Fortran::lower::SomeExpr *x,
              const Fortran::lower::SomeExpr *y);
-bool isEqual(const Fortran::lower::ExplicitIterSpace::ArrayBases &x,
-             const Fortran::lower::ExplicitIterSpace::ArrayBases &y);
+bool isEqual(const Fortran::lower::ExplicitSpaceArrayBases &x,
+             const Fortran::lower::ExplicitSpaceArrayBases &y);
+bool isEqual(const Fortran::evaluate::Component *x,
+             const Fortran::evaluate::Component *y);
 
 template <typename OpType, typename OperandsStructType>
 void privatizeSymbol(
@@ -125,6 +142,24 @@ struct DenseMapInfo<const Fortran::lower::SomeExpr *> {
     return Fortran::lower::isEqual(lhs, rhs);
   }
 };
+
+// DenseMapInfo for pointers to Fortran::evaluate::Component.
+template <>
+struct DenseMapInfo<const Fortran::evaluate::Component *> {
+  static inline const Fortran::evaluate::Component *getEmptyKey() {
+    return reinterpret_cast<Fortran::evaluate::Component *>(~0);
+  }
+  static inline const Fortran::evaluate::Component *getTombstoneKey() {
+    return reinterpret_cast<Fortran::evaluate::Component *>(~0 - 1);
+  }
+  static unsigned getHashValue(const Fortran::evaluate::Component *v) {
+    return Fortran::lower::getHashValue(v);
+  }
+  static bool isEqual(const Fortran::evaluate::Component *lhs,
+                      const Fortran::evaluate::Component *rhs) {
+    return Fortran::lower::isEqual(lhs, rhs);
+  }
+};
 } // namespace llvm
 
 #endif // FORTRAN_LOWER_SUPPORT_UTILS_H
diff --git a/flang/include/flang/Lower/SymbolMap.h 
b/flang/include/flang/Lower/SymbolMap.h
index e57b6a42d3cc1..2b0c2ecbf1280 100644
--- a/flang/include/flang/Lower/SymbolMap.h
+++ b/flang/include/flang/Lower/SymbolMap.h
@@ -14,6 +14,7 @@
 #define FORTRAN_LOWER_SYMBOLMAP_H
 
 #include "flang/Common/reference.h"
+#include "flang/Lower/Support/Utils.h"
 #include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/Dialect/FortranVariableInterface.h"
@@ -134,6 +135,41 @@ struct SymbolBox : public fir::details::matcher<SymbolBox> 
{
   VT box;
 };
 
+/// Helper class to map `Fortran::evaluate::Component` references to IR values.
+/// This is used when the evaluation of a component reference must be
+/// overridden with a pre-computed address.
+class ComponentMap {
+public:
+  void insert(const Fortran::evaluate::Component &component,
+              fir::FortranVariableOpInterface definingOp) {
+    auto iter = componentMap.find(&component);
+    if (iter != componentMap.end()) {
+      iter->second = definingOp;
+      return;
+    }
+    componentStorage.push_back(
+        std::make_unique<Fortran::evaluate::Component>(component));
+    componentMap.insert({componentStorage.back().get(), definingOp});
+  }
+
+  std::optional<fir::FortranVariableOpInterface>
+  lookup(const Fortran::evaluate::Component *component) const {
+    auto iter = componentMap.find(component);
+    if (iter != componentMap.end())
+      return iter->second;
+    return std::nullopt;
+  }
+
+  LLVM_DUMP_METHOD void dump() const;
+
+private:
+  llvm::DenseMap<const Fortran::evaluate::Component *,
+                 fir::FortranVariableOpInterface>
+      componentMap;
+  llvm::SmallVector<std::unique_ptr<Fortran::evaluate::Component>>
+      componentStorage;
+};
+
 
//===----------------------------------------------------------------------===//
 // Map of symbol information
 
//===----------------------------------------------------------------------===//
@@ -156,12 +192,15 @@ class SymMap {
   void pushScope() {
     symbolMapStack.emplace_back();
     storageMapStack.emplace_back();
+    componentMapStack.emplace_back();
   }
   void popScope() {
     symbolMapStack.pop_back();
     assert(symbolMapStack.size() >= 1);
     storageMapStack.pop_back();
     assert(storageMapStack.size() >= 1);
+    componentMapStack.pop_back();
+    assert(componentMapStack.size() >= 1);
   }
 
   /// Add an extended value to the symbol table.
@@ -301,6 +340,8 @@ class SymMap {
     impliedDoStack.clear();
     storageMapStack.clear();
     storageMapStack.emplace_back();
+    componentMapStack.clear();
+    componentMapStack.emplace_back();
   }
 
   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
@@ -329,6 +370,33 @@ class SymMap {
     return std::nullopt;
   }
 
+  /// Register a mapping from a front-end component reference to the FIR
+  /// variable that should be used to implement it. This is used to override
+  /// the default lowering of component references in specific contexts.
+  void addComponentOverride(const Fortran::evaluate::Component &component,
+                            fir::FortranVariableOpInterface definingOp) {
+    assert(!componentMapStack.empty() && "component map stack is empty");
+    if (!componentMapStack.back())
+      componentMapStack.back() = std::make_unique<ComponentMap>();
+    componentMapStack.back().value()->insert(component, definingOp);
+  }
+
+  /// Lookup an overridden FIR variable definition for a given component
+  /// reference, if any.
+  std::optional<fir::FortranVariableOpInterface>
+  lookupComponentOverride(const Fortran::evaluate::Component &component) const 
{
+    for (auto jmap = componentMapStack.rbegin(),
+              jend = componentMapStack.rend();
+         jmap != jend; ++jmap) {
+      if (*jmap) {
+        auto iter = (**jmap)->lookup(&component);
+        if (iter != std::nullopt)
+          return iter;
+      }
+    }
+    return std::nullopt;
+  }
+
   /// Register the symbol's storage at the innermost level
   /// of the symbol table. If the storage is already registered,
   /// it will be replaced.
@@ -360,6 +428,12 @@ class SymMap {
   // A stack of maps between the symbols and their storage descriptors.
   llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, StorageDesc>>
       storageMapStack;
+
+  // A stack of maps from front-end component references to the FIR variables
+  // that should be used to implement them. This allows overriding component
+  // references in specific lowering contexts.
+  llvm::SmallVector<std::optional<std::unique_ptr<ComponentMap>>>
+      componentMapStack;
 };
 
 /// RAII wrapper for SymMap.
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp 
b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 1eda1f1b61355..b079c9e6fa29b 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -368,6 +368,8 @@ class HlfirDesignatorBuilder {
 
   fir::FortranVariableOpInterface
   gen(const Fortran::evaluate::Component &component) {
+    if (auto remapped = symMap.lookupComponentOverride(component))
+      return *remapped;
     if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol()))
       return genWholeAllocatableOrPointerComponent(component);
     PartInfo partInfo;
@@ -477,6 +479,8 @@ class HlfirDesignatorBuilder {
 
   fir::FortranVariableOpInterface genWholeAllocatableOrPointerComponent(
       const Fortran::evaluate::Component &component) {
+    if (auto remapped = symMap.lookupComponentOverride(component))
+      return *remapped;
     // Generate whole allocatable or pointer component reference. The
     // hlfir.designate result will be a pointer/allocatable.
     PartInfo partInfo;
@@ -539,7 +543,8 @@ class HlfirDesignatorBuilder {
       // components need special care to deal with the 
array%array_comp(indices)
       // case.
       if (Fortran::semantics::IsAllocatableOrObjectPointer(
-              &component->GetLastSymbol()))
+              &component->GetLastSymbol()) ||
+          symMap.lookupComponentOverride(*component))
         baseType = visit(*component, partInfo);
       else
         baseType = hlfir::getFortranElementOrSequenceType(
@@ -686,6 +691,15 @@ class HlfirDesignatorBuilder {
                                  partInfo.typeParams);
       return partInfo.base->getElementOrSequenceType();
     }
+    if (auto remapped = symMap.lookupComponentOverride(component)) {
+      // Do not generate field for the designate if the component
+      // is overridden, the override value is already addressing
+      // the component.
+      partInfo.base = *remapped;
+      hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base,
+                                 partInfo.typeParams);
+      return partInfo.base->getElementOrSequenceType();
+    }
     // This function must be called from contexts where the component is not 
the
     // base of an ArrayRef. In these cases, the component cannot be an array
     // if the base is an array. The code below determines the shape of the
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index b586ea3ac627b..ac6a845fa74ec 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -643,20 +643,123 @@ void genAtomicCapture(Fortran::lower::AbstractConverter 
&converter,
   firOpBuilder.setInsertionPointAfter(atomicCaptureOp);
 }
 
+/// Rebuild the array type from the acc.bounds operation with constant
+/// lowerbound/upperbound or extent.
+static mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds,
+                                    mlir::Type ty) {
+  auto seqTy =
+      mlir::dyn_cast_or_null<fir::SequenceType>(fir::unwrapRefType(ty));
+  if (!bounds.empty() && seqTy) {
+    llvm::SmallVector<int64_t> shape;
+    for (auto b : bounds) {
+      auto boundsOp =
+          mlir::dyn_cast<mlir::acc::DataBoundsOp>(b.getDefiningOp());
+      if (boundsOp.getLowerbound() &&
+          fir::getIntIfConstant(boundsOp.getLowerbound()) &&
+          boundsOp.getUpperbound() &&
+          fir::getIntIfConstant(boundsOp.getUpperbound())) {
+        int64_t ext = *fir::getIntIfConstant(boundsOp.getUpperbound()) -
+                      *fir::getIntIfConstant(boundsOp.getLowerbound()) + 1;
+        shape.push_back(ext);
+      } else if (boundsOp.getExtent() &&
+                 fir::getIntIfConstant(boundsOp.getExtent())) {
+        shape.push_back(*fir::getIntIfConstant(boundsOp.getExtent()));
+      } else {
+        return ty; // TODO: handle dynamic shaped array slice.
+      }
+    }
+    if (shape.empty() || shape.size() != bounds.size())
+      return ty;
+    auto newSeqTy = fir::SequenceType::get(shape, seqTy.getEleTy());
+    if (mlir::isa<fir::ReferenceType, fir::PointerType>(ty))
+      return fir::ReferenceType::get(newSeqTy);
+    return newSeqTy;
+  }
+  return ty;
+}
+
+static mlir::SymbolRefAttr
+createOrGetRecipe(fir::FirOpBuilder &builder, mlir::Location loc,
+                  mlir::acc::RecipeKind kind, mlir::Value addr,
+                  llvm::SmallVector<mlir::Value> &bounds) {
+  mlir::Type ty = getTypeFromBounds(bounds, addr.getType());
+  // Compute the canonical recipe name for the given kind, type, address and
+  // bounds so that recipes are shared wherever possible.
+  std::string recipeName = fir::acc::getRecipeName(kind, ty, addr, bounds);
+
+  switch (kind) {
+  case mlir::acc::RecipeKind::private_recipe: {
+    auto recipe =
+        Fortran::lower::createOrGetPrivateRecipe(builder, recipeName, loc, ty);
+    return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+  }
+  case mlir::acc::RecipeKind::firstprivate_recipe: {
+    auto recipe = Fortran::lower::createOrGetFirstprivateRecipe(
+        builder, recipeName, loc, ty, bounds);
+    return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
+  }
+  default:
+    llvm::report_fatal_error(
+        "createOrGetRecipe only supports private and firstprivate recipes");
+  }
+}
+
+namespace {
+// Helper class to keep track how the Designator that appear in the
+// data clauses of structured constructs so that they can be remapped
+// to the data operation result inside the scope of the construct.
+class AccDataMap {
+public:
+  struct DataComponent {
+    // Semantic representation of the component reference that appeared
+    // inside the data clause and that will need to be remapped to the
+    // data operation result.
+    Fortran::evaluate::Component component;
+    // Operation that produced the component when lowering the data clause.
+    mlir::Value designate;
+    // data operation result.
+    mlir::Value accValue;
+  };
+  void emplaceSymbol(mlir::Value accValue, Fortran::semantics::SymbolRef sym) {
+    symbols.emplace_back(mlir::Value(accValue),
+                         Fortran::semantics::SymbolRef(*sym));
+  }
+  void emplaceComponent(mlir::Value accValue,
+                        Fortran::evaluate::Component &&comp,
+                        mlir::Value designate) {
+    components.emplace_back(
+        DataComponent{std::move(comp), designate, accValue});
+  }
+  bool empty() const { return symbols.empty() && components.empty(); }
+
+  /// Remap symbols and components that appeared in OpenACC data clauses to use
+  /// the results of the corresponding data operations. This allows isolating
+  /// symbol accesses inside the OpenACC region from accesses in the host and
+  /// other regions while preserving Fortran information about the symbols for
+  /// optimizations.
+  void remapDataOperandSymbols(Fortran::lower::AbstractConverter &converter,
+                               fir::FirOpBuilder &builder,
+                               mlir::Region &region) const;
+
+  llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
+      symbols;
+  llvm::SmallVector<DataComponent> components;
+};
+} // namespace
+
 template <typename Op>
-static void genDataOperandOperations(
-    const Fortran::parser::AccObjectList &objectList,
-    Fortran::lower::AbstractConverter &converter,
-    Fortran::semantics::SemanticsContext &semanticsContext,
-    Fortran::lower::StatementContext &stmtCtx,
-    llvm::SmallVectorImpl<mlir::Value> &dataOperands,
-    mlir::acc::DataClause dataClause, bool structured, bool implicit,
-    llvm::ArrayRef<mlir::Value> async,
-    llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
-    llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
-    bool setDeclareAttr = false,
-    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
-        *symbolPairs = nullptr) {
+static void
+genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
+                         Fortran::lower::AbstractConverter &converter,
+                         Fortran::semantics::SemanticsContext 
&semanticsContext,
+                         Fortran::lower::StatementContext &stmtCtx,
+                         llvm::SmallVectorImpl<mlir::Value> &dataOperands,
+                         mlir::acc::DataClause dataClause, bool structured,
+                         bool implicit, llvm::ArrayRef<mlir::Value> async,
+                         llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
+                         llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
+                         bool setDeclareAttr = false,
+                         AccDataMap *dataMap = nullptr) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   Fortran::evaluate::ExpressionAnalyzer ea{semanticsContext};
   const bool unwrapBoxAddr = true;
@@ -664,9 +767,27 @@ static void genDataOperandOperations(
     llvm::SmallVector<mlir::Value> bounds;
     std::stringstream asFortran;
     mlir::Location operandLocation = genOperandLocation(converter, accObject);
+
     Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject);
+
+    std::optional<Fortran::evaluate::Component> componentRef;
     Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
         [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
+    if (std::optional<Fortran::evaluate::DataRef> dataRef =
+            Fortran::evaluate::ExtractDataRef(designator)) {
+      Fortran::common::visit(
+          Fortran::common::visitors{
+              [&](const Fortran::evaluate::Component &component) {
+                componentRef = component;
+              },
+              [&](const Fortran::evaluate::ArrayRef &arrayRef) {
+                if (auto *comp = arrayRef.base().UnwrapComponent())
+                  componentRef = *comp;
+              },
+              [](const auto &) {}},
+          dataRef->u);
+    }
+
     fir::factory::AddrAndBoundsInfo info =
         Fortran::lower::gatherDataOperandAddrAndBounds<
             mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>(
@@ -678,44 +799,61 @@ static void genDataOperandOperations(
             /*loadAllocatableAndPointerComponent=*/false);
     LLVM_DEBUG(llvm::dbgs() << __func__ << "\n"; info.dump(llvm::dbgs()));
 
-    bool isWholeSymbol =
-        !designator || 
Fortran::evaluate::UnwrapWholeSymbolDataRef(*designator);
-
     // If the input value is optional and is not a descriptor, we use the
     // rawInput directly.
-    mlir::Value baseAddr = ((fir::unwrapRefType(info.addr.getType()) !=
+    // For privatization, absent OPTIONAL are illegal as per OpenACC 3.3
+    // section 2.17.1 and the descriptor must be used to drive the creation of
+    // the temporary and the copy.
+    bool isPrivate = std::is_same_v<Op, mlir::acc::PrivateOp> ||
+                     std::is_same_v<Op, mlir::acc::FirstprivateOp>;
+    mlir::Value baseAddr = (!isPrivate &&
+                            (fir::unwrapRefType(info.addr.getType()) !=
                              fir::unwrapRefType(info.rawInput.getType())) &&
                             info.isPresent)
                                ? info.rawInput
                                : info.addr;
+
+    // TODO: update privatization of array section to return the base
+    // address and update the recipe generation to "offset back" the returned
+    // address. Then it will be possible to remap them like in other cases.
+    bool isPrivateArraySection = isPrivate && !bounds.empty();
+    mlir::Type resTy = isPrivateArraySection
+                           ? getTypeFromBounds(bounds, baseAddr.getType())
+                           : baseAddr.getType();
+
     Op op = createDataEntryOp<Op>(
         builder, operandLocation, baseAddr, asFortran, bounds, structured,
-        implicit, dataClause, baseAddr.getType(), async, asyncDeviceTypes,
+        implicit, dataClause, resTy, async, asyncDeviceTypes,
         asyncOnlyDeviceTypes, unwrapBoxAddr, info.isPresent);
     dataOperands.push_back(op.getAccVar());
 
-    // Track the symbol and its corresponding mlir::Value if requested
-    if (symbolPairs && isWholeSymbol)
-      symbolPairs->emplace_back(op.getAccVar(),
-                                Fortran::semantics::SymbolRef(symbol));
-
-    // For UseDeviceOp, if operand is one of a pair resulting from a
-    // declare operation, create a UseDeviceOp for the other operand as well.
-    if constexpr (std::is_same_v<Op, mlir::acc::UseDeviceOp>) {
-      if (auto declareOp =
-              mlir::dyn_cast<hlfir::DeclareOp>(baseAddr.getDefiningOp())) {
-        mlir::Value otherAddr = declareOp.getResult(1);
-        if (baseAddr != otherAddr) {
-          Op op = createDataEntryOp<Op>(builder, operandLocation, otherAddr,
-                                        asFortran, bounds, structured, 
implicit,
-                                        dataClause, otherAddr.getType(), async,
-                                        asyncDeviceTypes, asyncOnlyDeviceTypes,
-                                        unwrapBoxAddr, info.isPresent);
-          dataOperands.push_back(op.getAccVar());
-          // Not adding this to symbolPairs because it only make sense to
-          // map the symbol to a single value.
-        }
-      }
+    // Optionally tag the underlying variable with a declare attribute.
+    if (setDeclareAttr)
+      if (auto *defOp = op.getVar().getDefiningOp())
+        addDeclareAttr(builder, defOp, dataClause);
+
+    // Track the symbol and its corresponding mlir::Value if requested so that
+    // accesses inside regions can be remapped.
+    if (dataMap && !isPrivateArraySection) {
+      if (componentRef)
+        dataMap->emplaceComponent(op.getAccVar(), std::move(*componentRef),
+                                  baseAddr);
+      else
+        dataMap->emplaceSymbol(op.getAccVar(),
+                               Fortran::semantics::SymbolRef(symbol));
+    }
+
+    // For private/firstprivate, attach (and optionally record) the recipe.
+    if constexpr (std::is_same_v<Op, mlir::acc::PrivateOp>) {
+      mlir::SymbolRefAttr recipeAttr = createOrGetRecipe(
+          builder, operandLocation, mlir::acc::RecipeKind::private_recipe,
+          info.addr, bounds);
+      op.setRecipeAttr(recipeAttr);
+    } else if constexpr (std::is_same_v<Op, mlir::acc::FirstprivateOp>) {
+      mlir::SymbolRefAttr recipeAttr = createOrGetRecipe(
+          builder, operandLocation, mlir::acc::RecipeKind::firstprivate_recipe,
+          info.addr, bounds);
+      op.setRecipeAttr(recipeAttr);
     }
   }
 }
@@ -847,6 +985,15 @@ static void genDeclareDataOperandOperations(
     }
     Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
         [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
+
+    if (designator) {
+      Fortran::semantics::SomeExpr someExpr = *designator;
+      if (Fortran::lower::detail::getRef<Fortran::evaluate::Component>(
+              someExpr)) {
+        TODO(operandLocation,
+             "OpenACC declare with component reference not yet supported");
+      }
+    }
     fir::factory::AddrAndBoundsInfo info =
         Fortran::lower::gatherDataOperandAddrAndBounds<
             mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>(
@@ -1349,117 +1496,6 @@ mlir::acc::FirstprivateRecipeOp 
Fortran::lower::createOrGetFirstprivateRecipe(
   return recipe;
 }
 
-/// Rebuild the array type from the acc.bounds operation with constant
-/// lowerbound/upperbound or extent.
-mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds,
-                             mlir::Type ty) {
-  auto seqTy =
-      mlir::dyn_cast_or_null<fir::SequenceType>(fir::unwrapRefType(ty));
-  if (!bounds.empty() && seqTy) {
-    llvm::SmallVector<int64_t> shape;
-    for (auto b : bounds) {
-      auto boundsOp =
-          mlir::dyn_cast<mlir::acc::DataBoundsOp>(b.getDefiningOp());
-      if (boundsOp.getLowerbound() &&
-          fir::getIntIfConstant(boundsOp.getLowerbound()) &&
-          boundsOp.getUpperbound() &&
-          fir::getIntIfConstant(boundsOp.getUpperbound())) {
-        int64_t ext = *fir::getIntIfConstant(boundsOp.getUpperbound()) -
-                      *fir::getIntIfConstant(boundsOp.getLowerbound()) + 1;
-        shape.push_back(ext);
-      } else if (boundsOp.getExtent() &&
-                 fir::getIntIfConstant(boundsOp.getExtent())) {
-        shape.push_back(*fir::getIntIfConstant(boundsOp.getExtent()));
-      } else {
-        return ty; // TODO: handle dynamic shaped array slice.
-      }
-    }
-    if (shape.empty() || shape.size() != bounds.size())
-      return ty;
-    auto newSeqTy = fir::SequenceType::get(shape, seqTy.getEleTy());
-    if (mlir::isa<fir::ReferenceType, fir::PointerType>(ty))
-      return fir::ReferenceType::get(newSeqTy);
-    return newSeqTy;
-  }
-  return ty;
-}
-
-template <typename RecipeOp>
-static void genPrivatizationRecipes(
-    const Fortran::parser::AccObjectList &objectList,
-    Fortran::lower::AbstractConverter &converter,
-    Fortran::semantics::SemanticsContext &semanticsContext,
-    Fortran::lower::StatementContext &stmtCtx,
-    llvm::SmallVectorImpl<mlir::Value> &dataOperands,
-    llvm::ArrayRef<mlir::Value> async,
-    llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
-    llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
-    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
-        *symbolPairs = nullptr) {
-  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
-  Fortran::evaluate::ExpressionAnalyzer ea{semanticsContext};
-  for (const auto &accObject : objectList.v) {
-    llvm::SmallVector<mlir::Value> bounds;
-    std::stringstream asFortran;
-    mlir::Location operandLocation = genOperandLocation(converter, accObject);
-    Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject);
-    Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
-        [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
-    fir::factory::AddrAndBoundsInfo info =
-        Fortran::lower::gatherDataOperandAddrAndBounds<
-            mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>(
-            converter, builder, semanticsContext, stmtCtx, symbol, designator,
-            operandLocation, asFortran, bounds,
-            /*treatIndexAsSection=*/true, /*unwrapFirBox=*/false,
-            /*genDefaultBounds=*/generateDefaultBounds,
-            /*strideIncludeLowerExtent=*/strideIncludeLowerExtent,
-            /*loadAllocatableAndPointerComponent=*/false);
-    LLVM_DEBUG(llvm::dbgs() << __func__ << "\n"; info.dump(llvm::dbgs()));
-
-    bool isWholeSymbol =
-        !designator || 
Fortran::evaluate::UnwrapWholeSymbolDataRef(*designator);
-
-    RecipeOp recipe;
-    mlir::Type retTy = getTypeFromBounds(bounds, info.addr.getType());
-    if constexpr (std::is_same_v<RecipeOp, mlir::acc::PrivateRecipeOp>) {
-      std::string recipeName = fir::acc::getRecipeName(
-          mlir::acc::RecipeKind::private_recipe, retTy, info.addr, bounds);
-      recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName,
-                                                        operandLocation, 
retTy);
-      auto op = createDataEntryOp<mlir::acc::PrivateOp>(
-          builder, operandLocation, info.addr, asFortran, bounds, true,
-          /*implicit=*/false, mlir::acc::DataClause::acc_private, retTy, async,
-          asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
-      op.setRecipeAttr(
-          mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()));
-      dataOperands.push_back(op.getAccVar());
-
-      // Track the symbol and its corresponding mlir::Value if requested
-      if (symbolPairs && isWholeSymbol)
-        symbolPairs->emplace_back(op.getAccVar(),
-                                  Fortran::semantics::SymbolRef(symbol));
-    } else {
-      std::string recipeName = fir::acc::getRecipeName(
-          mlir::acc::RecipeKind::firstprivate_recipe, retTy, info.addr, 
bounds);
-      recipe = Fortran::lower::createOrGetFirstprivateRecipe(
-          builder, recipeName, operandLocation, retTy, bounds);
-      auto op = createDataEntryOp<mlir::acc::FirstprivateOp>(
-          builder, operandLocation, info.addr, asFortran, bounds, true,
-          /*implicit=*/false, mlir::acc::DataClause::acc_firstprivate, retTy,
-          async, asyncDeviceTypes, asyncOnlyDeviceTypes,
-          /*unwrapBoxAddr=*/true);
-      op.setRecipeAttr(
-          mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()));
-      dataOperands.push_back(op.getAccVar());
-
-      // Track the symbol and its corresponding mlir::Value if requested
-      if (symbolPairs && isWholeSymbol)
-        symbolPairs->emplace_back(op.getAccVar(),
-                                  Fortran::semantics::SymbolRef(symbol));
-    }
-  }
-}
-
 /// Return the corresponding enum value for the mlir::acc::ReductionOperator
 /// from the parser representation.
 static mlir::acc::ReductionOperator
@@ -1626,17 +1662,16 @@ static bool isSupportedReductionType(mlir::Type ty) {
   return fir::isa_trivial(ty);
 }
 
-static void genReductions(
-    const Fortran::parser::AccObjectListWithReduction &objectList,
-    Fortran::lower::AbstractConverter &converter,
-    Fortran::semantics::SemanticsContext &semanticsContext,
-    Fortran::lower::StatementContext &stmtCtx,
-    llvm::SmallVectorImpl<mlir::Value> &reductionOperands,
-    llvm::ArrayRef<mlir::Value> async,
-    llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
-    llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
-    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
-        *symbolPairs = nullptr) {
+static void
+genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
+              Fortran::lower::AbstractConverter &converter,
+              Fortran::semantics::SemanticsContext &semanticsContext,
+              Fortran::lower::StatementContext &stmtCtx,
+              llvm::SmallVectorImpl<mlir::Value> &reductionOperands,
+              llvm::ArrayRef<mlir::Value> async,
+              llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
+              llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
+              AccDataMap *dataMap = nullptr) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   const auto &objects = std::get<Fortran::parser::AccObjectList>(objectList.t);
   const auto &op = std::get<Fortran::parser::ReductionOperator>(objectList.t);
@@ -1669,6 +1704,15 @@ static void genReductions(
     if (!isSupportedReductionType(reductionTy))
       TODO(operandLocation, "reduction with unsupported type");
 
+    if (designator) {
+      Fortran::semantics::SomeExpr someExpr = *designator;
+      if (Fortran::lower::detail::getRef<Fortran::evaluate::Component>(
+              someExpr)) {
+        TODO(operandLocation,
+             "OpenACC reduction with component reference not yet supported");
+      }
+    }
+
     auto op = createDataEntryOp<mlir::acc::ReductionOp>(
         builder, operandLocation, info.addr, asFortran, bounds,
         /*structured=*/true, /*implicit=*/false,
@@ -1690,9 +1734,9 @@ static void genReductions(
     reductionOperands.push_back(op.getAccVar());
     // Track the symbol and its corresponding mlir::Value if requested so that
     // accesses inside the compute/loop regions use the acc.reduction variable.
-    if (symbolPairs && isWholeSymbol)
-      symbolPairs->emplace_back(op.getAccVar(),
-                                Fortran::semantics::SymbolRef(symbol));
+    if (dataMap && isWholeSymbol)
+      dataMap->emplaceSymbol(op.getAccVar(),
+                             Fortran::semantics::SymbolRef(symbol));
   }
 }
 
@@ -1902,7 +1946,7 @@ static void privatizeIv(
     llvm::SmallVector<mlir::Type> &ivTypes,
     llvm::SmallVector<mlir::Location> &ivLocs,
     llvm::SmallVector<mlir::Value> &privateOperands,
-    llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
+    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
         &ivPrivate,
     bool isDoConcurrent = false) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
@@ -1929,19 +1973,18 @@ static void privatizeIv(
   }
 
   if (privateOp == nullptr) {
-    std::string recipeName = fir::acc::getRecipeName(
-        mlir::acc::RecipeKind::private_recipe, ivValue.getType(), ivValue, {});
-    auto recipe = Fortran::lower::createOrGetPrivateRecipe(
-        builder, recipeName, loc, ivValue.getType());
+    llvm::SmallVector<mlir::Value> noBounds;
+    mlir::SymbolRefAttr recipe = createOrGetRecipe(
+        builder, loc, mlir::acc::RecipeKind::private_recipe, ivValue, 
noBounds);
 
     std::stringstream asFortran;
     asFortran << Fortran::lower::mangle::demangleName(toStringRef(sym.name()));
     auto op = createDataEntryOp<mlir::acc::PrivateOp>(
-        builder, loc, ivValue, asFortran, {}, true, /*implicit=*/true,
-        mlir::acc::DataClause::acc_private, ivValue.getType(),
+        builder, loc, ivValue, asFortran, {}, true,
+        /*implicit=*/true, mlir::acc::DataClause::acc_private,
+        ivValue.getType(),
         /*async=*/{}, /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{});
-    op.setRecipeAttr(
-        mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()));
+    op.setRecipeAttr(recipe);
     privateOp = op.getOperation();
 
     privateOperands.push_back(op.getAccVar());
@@ -2070,7 +2113,7 @@ static void processDoLoopBounds(
     llvm::SmallVector<mlir::Value> &upperbounds,
     llvm::SmallVector<mlir::Value> &steps,
     llvm::SmallVector<mlir::Value> &privateOperands,
-    llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
+    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
         &ivPrivate,
     llvm::SmallVector<mlir::Type> &ivTypes,
     llvm::SmallVector<mlir::Location> &ivLocs,
@@ -2160,18 +2203,10 @@ static void remapCommonBlockMember(
   seenSymbols.insert(&member);
 }
 
-/// Remap symbols that appeared in OpenACC data clauses to use the results of
-/// the corresponding data operations. This allows isolating symbol accesses
-/// inside the OpenACC region from accesses in the host and other regions while
-/// preserving Fortran information about the symbols for optimizations.
-template <typename RegionOp>
-static void remapDataOperandSymbols(
+void AccDataMap::remapDataOperandSymbols(
     Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder,
-    RegionOp &regionOp,
-    const llvm::SmallVector<
-        std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
-        &dataOperandSymbolPairs) {
-  if (!enableSymbolRemapping || dataOperandSymbolPairs.empty())
+    mlir::Region &region) const {
+  if (!enableSymbolRemapping || empty())
     return;
 
   // Map Symbols that appeared inside data clauses to a new hlfir.declare whose
@@ -2182,17 +2217,17 @@ static void remapDataOperandSymbols(
   // region.
   Fortran::lower::SymMap &symbolMap = converter.getSymbolMap();
   mlir::OpBuilder::InsertionGuard insertGuard(builder);
-  builder.setInsertionPointToStart(&regionOp.getRegion().front());
+  builder.setInsertionPointToStart(&region.front());
   llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 8> seenSymbols;
   mlir::IRMapping mapper;
-  mlir::Location loc = regionOp.getLoc();
-  for (auto [value, symbol] : dataOperandSymbolPairs) {
+  for (auto [value, symbol] : symbols) {
     // If a symbol appears on several data clause, just map it to the first
     // result (all data operations results for a symbol are pointing same
     // memory, so it does not matter which one is used).
     if (seenSymbols.contains(&symbol.get()))
       continue;
     seenSymbols.insert(&symbol.get());
+    mlir::Location loc = value.getLoc();
     // When a common block appears in a directive, remap its members.
     // Note: this will instantiate all common block members even if they are 
not
     // used inside the region. If hlfir.declare DCE is not made possible, this
@@ -2273,6 +2308,24 @@ static void remapDataOperandSymbols(
     symbolMap.addVariableDefinition(
         symbol, llvm::cast<fir::FortranVariableOpInterface>(computeDef));
   }
+
+  for (const auto &comp : components) {
+    mlir::Location loc = comp.accValue.getLoc();
+    hlfir::DesignateOp designate =
+        comp.designate.getDefiningOp<hlfir::DesignateOp>();
+    // If this is not a designate, it means the component was already remap in 
a
+    // parent construct, and the declare should be cloned instead.
+    if (!designate)
+      TODO(comp.designate.getLoc(),
+           "nested component reference in OpenACC clause");
+
+    auto declare = hlfir::DeclareOp::create(
+        builder, loc, comp.accValue, mlir::acc::getVariableName(comp.accValue),
+        designate.getShape(), designate.getTypeparams(), /*dummyScope=*/{},
+        /*storage=*/{},
+        /*storageOffset=*/0, designate.getFortranAttrsAttr());
+    symbolMap.addComponentOverride(comp.component, declare);
+  }
 }
 
 static void privatizeInductionVariables(
@@ -2281,7 +2334,7 @@ static void privatizeInductionVariables(
     const Fortran::parser::DoConstruct &outerDoConstruct,
     Fortran::lower::pft::Evaluation &eval,
     llvm::SmallVector<mlir::Value> &privateOperands,
-    llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
+    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
         &ivPrivate,
     llvm::SmallVector<mlir::Location> &locs, uint64_t loopsToProcess) {
   // ivTypes and locs will be ignored since no acc.loop control arguments will
@@ -2301,24 +2354,23 @@ static void privatizeInductionVariables(
                    });
 }
 
-static mlir::acc::LoopOp buildACCLoopOp(
-    Fortran::lower::AbstractConverter &converter,
-    mlir::Location currentLocation,
-    Fortran::semantics::SemanticsContext &semanticsContext,
-    Fortran::lower::StatementContext &stmtCtx,
-    const Fortran::parser::DoConstruct &outerDoConstruct,
-    Fortran::lower::pft::Evaluation &eval,
-    llvm::SmallVector<mlir::Value> &privateOperands,
-    llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
-        &dataOperandSymbolPairs,
-    llvm::SmallVector<mlir::Value> &gangOperands,
-    llvm::SmallVector<mlir::Value> &workerNumOperands,
-    llvm::SmallVector<mlir::Value> &vectorOperands,
-    llvm::SmallVector<mlir::Value> &tileOperands,
-    llvm::SmallVector<mlir::Value> &cacheOperands,
-    llvm::SmallVector<mlir::Value> &reductionOperands,
-    llvm::SmallVector<mlir::Type> &retTy, mlir::Value yieldValue,
-    uint64_t loopsToProcess) {
+static mlir::acc::LoopOp
+buildACCLoopOp(Fortran::lower::AbstractConverter &converter,
+               mlir::Location currentLocation,
+               Fortran::semantics::SemanticsContext &semanticsContext,
+               Fortran::lower::StatementContext &stmtCtx,
+               const Fortran::parser::DoConstruct &outerDoConstruct,
+               Fortran::lower::pft::Evaluation &eval,
+               llvm::SmallVector<mlir::Value> &privateOperands,
+               AccDataMap &dataMap,
+               llvm::SmallVector<mlir::Value> &gangOperands,
+               llvm::SmallVector<mlir::Value> &workerNumOperands,
+               llvm::SmallVector<mlir::Value> &vectorOperands,
+               llvm::SmallVector<mlir::Value> &tileOperands,
+               llvm::SmallVector<mlir::Value> &cacheOperands,
+               llvm::SmallVector<mlir::Value> &reductionOperands,
+               llvm::SmallVector<mlir::Type> &retTy, mlir::Value yieldValue,
+               uint64_t loopsToProcess) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
 
   llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
@@ -2369,9 +2421,9 @@ static mlir::acc::LoopOp buildACCLoopOp(
   // the loop even if it did not appear explicitly in a PRIVATE clause (if it
   // appeared explicitly in such clause, that is also fine because duplicates
   // in the list are ignored).
-  dataOperandSymbolPairs.append(ivPrivate.begin(), ivPrivate.end());
+  dataMap.symbols.append(ivPrivate.begin(), ivPrivate.end());
   // Remap symbols from data clauses to use data operation results
-  remapDataOperandSymbols(converter, builder, loopOp, dataOperandSymbolPairs);
+  dataMap.remapDataOperandSymbols(converter, builder, loopOp.getRegion());
 
   if (!eval.lowerAsUnstructured()) {
     for (auto [arg, iv] :
@@ -2420,9 +2472,7 @@ static mlir::acc::LoopOp createLoopOp(
   llvm::SmallVector<int32_t> tileOperandsSegments, gangOperandsSegments;
   llvm::SmallVector<int64_t> collapseValues;
 
-  // Vector to track mlir::Value results and their corresponding Fortran 
symbols
-  llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
-      dataOperandSymbolPairs;
+  AccDataMap dataMap;
 
   llvm::SmallVector<mlir::Attribute> gangArgTypes;
   llvm::SmallVector<mlir::Attribute> seqDeviceTypes, independentDeviceTypes,
@@ -2541,18 +2591,19 @@ static mlir::acc::LoopOp createLoopOp(
     } else if (const auto *privateClause =
                    std::get_if<Fortran::parser::AccClause::Private>(
                        &clause.u)) {
-      genPrivatizationRecipes<mlir::acc::PrivateRecipeOp>(
+      genDataOperandOperations<mlir::acc::PrivateOp>(
           privateClause->v, converter, semanticsContext, stmtCtx,
-          privateOperands, /*async=*/{},
-          /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{},
-          &dataOperandSymbolPairs);
+          privateOperands, mlir::acc::DataClause::acc_private,
+          /*structured=*/true, /*implicit=*/false,
+          /*async=*/{}, /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{},
+          /*setDeclareAttr=*/false, &dataMap);
     } else if (const auto *reductionClause =
                    std::get_if<Fortran::parser::AccClause::Reduction>(
                        &clause.u)) {
       genReductions(reductionClause->v, converter, semanticsContext, stmtCtx,
                     reductionOperands, /*async=*/{},
                     /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{},
-                    &dataOperandSymbolPairs);
+                    &dataMap);
     } else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
       for (auto crtDeviceTypeAttr : crtDeviceTypes)
         seqDeviceTypes.push_back(crtDeviceTypeAttr);
@@ -2601,9 +2652,9 @@ static mlir::acc::LoopOp createLoopOp(
       Fortran::lower::getLoopCountForCollapseAndTile(accClauseList);
   auto loopOp = buildACCLoopOp(
       converter, currentLocation, semanticsContext, stmtCtx, outerDoConstruct,
-      eval, privateOperands, dataOperandSymbolPairs, gangOperands,
-      workerNumOperands, vectorOperands, tileOperands, cacheOperands,
-      reductionOperands, retTy, yieldValue, loopsToProcess);
+      eval, privateOperands, dataMap, gangOperands, workerNumOperands,
+      vectorOperands, tileOperands, cacheOperands, reductionOperands, retTy,
+      yieldValue, loopsToProcess);
 
   if (!gangDeviceTypes.empty())
     loopOp.setGangAttr(builder.getArrayAttr(gangDeviceTypes));
@@ -2708,9 +2759,7 @@ static void genDataOperandOperationsWithModifier(
     llvm::ArrayRef<mlir::Value> async,
     llvm::ArrayRef<mlir::Attribute> asyncDeviceTypes,
     llvm::ArrayRef<mlir::Attribute> asyncOnlyDeviceTypes,
-    bool setDeclareAttr = false,
-    llvm::SmallVectorImpl<std::pair<mlir::Value, 
Fortran::semantics::SymbolRef>>
-        *symbolPairs = nullptr) {
+    bool setDeclareAttr = false, AccDataMap *dataMap = nullptr) {
   const Fortran::parser::AccObjectListWithModifier &listWithModifier = x->v;
   const auto &accObjectList =
       std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
@@ -2723,7 +2772,7 @@ static void genDataOperandOperationsWithModifier(
                                stmtCtx, dataClauseOperands, dataClause,
                                /*structured=*/true, /*implicit=*/false, async,
                                asyncDeviceTypes, asyncOnlyDeviceTypes,
-                               setDeclareAttr, symbolPairs);
+                               setDeclareAttr, dataMap);
 }
 
 template <typename Op>
@@ -2752,10 +2801,7 @@ static Op createComputeOp(
   llvm::SmallVector<mlir::Value> reductionOperands, privateOperands,
       firstprivateOperands;
 
-  // Vector to track mlir::Value results and their corresponding Fortran 
symbols
-  llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
-      dataOperandSymbolPairs;
-
+  AccDataMap dataMap;
   // Self clause has optional values but can be present with
   // no value as well. When there is no value, the op has an attribute to
   // represent the clause.
@@ -2876,8 +2922,7 @@ static Op createComputeOp(
           copyClause->v, converter, semanticsContext, stmtCtx,
           dataClauseOperands, mlir::acc::DataClause::acc_copy,
           /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       copyEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                dataClauseOperands.end());
     } else if (const auto *copyinClause =
@@ -2889,8 +2934,7 @@ static Op createComputeOp(
           Fortran::parser::AccDataModifier::Modifier::ReadOnly,
           dataClauseOperands, mlir::acc::DataClause::acc_copyin,
           mlir::acc::DataClause::acc_copyin_readonly, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       copyinEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                  dataClauseOperands.end());
     } else if (const auto *copyoutClause =
@@ -2903,8 +2947,7 @@ static Op createComputeOp(
           Fortran::parser::AccDataModifier::Modifier::Zero, dataClauseOperands,
           mlir::acc::DataClause::acc_copyout,
           mlir::acc::DataClause::acc_copyout_zero, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       copyoutEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                   dataClauseOperands.end());
     } else if (const auto *createClause =
@@ -2916,8 +2959,7 @@ static Op createComputeOp(
           Fortran::parser::AccDataModifier::Modifier::Zero, dataClauseOperands,
           mlir::acc::DataClause::acc_create,
           mlir::acc::DataClause::acc_create_zero, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       createEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                  dataClauseOperands.end());
     } else if (const auto *noCreateClause =
@@ -2928,8 +2970,7 @@ static Op createComputeOp(
           noCreateClause->v, converter, semanticsContext, stmtCtx,
           dataClauseOperands, mlir::acc::DataClause::acc_no_create,
           /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       nocreateEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                    dataClauseOperands.end());
     } else if (const auto *presentClause =
@@ -2940,16 +2981,13 @@ static Op createComputeOp(
           presentClause->v, converter, semanticsContext, stmtCtx,
           dataClauseOperands, mlir::acc::DataClause::acc_present,
           /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       presentEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                   dataClauseOperands.end());
     } else if (const auto *devicePtrClause =
                    std::get_if<Fortran::parser::AccClause::Deviceptr>(
                        &clause.u)) {
-      llvm::SmallVectorImpl<
-          std::pair<mlir::Value, Fortran::semantics::SymbolRef>> *symPairs =
-          enableDevicePtrRemap ? &dataOperandSymbolPairs : nullptr;
+      AccDataMap *symPairs = enableDevicePtrRemap ? &dataMap : nullptr;
       genDataOperandOperations<mlir::acc::DevicePtrOp>(
           devicePtrClause->v, converter, semanticsContext, stmtCtx,
           dataClauseOperands, mlir::acc::DataClause::acc_deviceptr,
@@ -2962,25 +3000,28 @@ static Op createComputeOp(
           attachClause->v, converter, semanticsContext, stmtCtx,
           dataClauseOperands, mlir::acc::DataClause::acc_attach,
           /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
-          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-          &dataOperandSymbolPairs);
+          asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
       attachEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                  dataClauseOperands.end());
     } else if (const auto *privateClause =
                    std::get_if<Fortran::parser::AccClause::Private>(
                        &clause.u)) {
       if (!combinedConstructs)
-        genPrivatizationRecipes<mlir::acc::PrivateRecipeOp>(
+        genDataOperandOperations<mlir::acc::PrivateOp>(
             privateClause->v, converter, semanticsContext, stmtCtx,
-            privateOperands, async, asyncDeviceTypes, asyncOnlyDeviceTypes,
-            &dataOperandSymbolPairs);
+            privateOperands, mlir::acc::DataClause::acc_private,
+            /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
+            asyncOnlyDeviceTypes,
+            /*setDeclareAttr=*/false, &dataMap);
     } else if (const auto *firstprivateClause =
                    std::get_if<Fortran::parser::AccClause::Firstprivate>(
                        &clause.u)) {
-      genPrivatizationRecipes<mlir::acc::FirstprivateRecipeOp>(
+      genDataOperandOperations<mlir::acc::FirstprivateOp>(
           firstprivateClause->v, converter, semanticsContext, stmtCtx,
-          firstprivateOperands, async, asyncDeviceTypes, asyncOnlyDeviceTypes,
-          &dataOperandSymbolPairs);
+          firstprivateOperands, mlir::acc::DataClause::acc_firstprivate,
+          /*structured=*/true, /*implicit=*/false, async, asyncDeviceTypes,
+          asyncOnlyDeviceTypes,
+          /*setDeclareAttr=*/false, &dataMap);
     } else if (const auto *reductionClause =
                    std::get_if<Fortran::parser::AccClause::Reduction>(
                        &clause.u)) {
@@ -2992,7 +3033,7 @@ static Op createComputeOp(
       if (!combinedConstructs) {
         genReductions(reductionClause->v, converter, semanticsContext, stmtCtx,
                       reductionOperands, async, asyncDeviceTypes,
-                      asyncOnlyDeviceTypes, &dataOperandSymbolPairs);
+                      asyncOnlyDeviceTypes, &dataMap);
       } else {
         auto crtDataStart = dataClauseOperands.size();
         genDataOperandOperations<mlir::acc::CopyinOp>(
@@ -3000,8 +3041,7 @@ static Op createComputeOp(
             converter, semanticsContext, stmtCtx, dataClauseOperands,
             mlir::acc::DataClause::acc_reduction,
             /*structured=*/true, /*implicit=*/true, async, asyncDeviceTypes,
-            asyncOnlyDeviceTypes, /*setDeclareAttr=*/false,
-            &dataOperandSymbolPairs);
+            asyncOnlyDeviceTypes, /*setDeclareAttr=*/false, &dataMap);
         copyEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
                                  dataClauseOperands.end());
       }
@@ -3088,8 +3128,7 @@ static Op createComputeOp(
   auto insPt = builder.saveInsertionPoint();
 
   // Remap symbols from data clauses to use data operation results
-  remapDataOperandSymbols(converter, builder, computeOp,
-                          dataOperandSymbolPairs);
+  dataMap.remapDataOperandSymbols(converter, builder, computeOp.getRegion());
 
   builder.setInsertionPointAfter(computeOp);
 
@@ -3341,6 +3380,7 @@ genACCHostDataOp(Fortran::lower::AbstractConverter 
&converter,
 
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
 
+  AccDataMap dataMap;
   for (const Fortran::parser::AccClause &clause : accClauseList.v) {
     mlir::Location clauseLocation = converter.genLocation(clause.source);
     if (const auto *ifClause =
@@ -3366,7 +3406,8 @@ genACCHostDataOp(Fortran::lower::AbstractConverter 
&converter,
           useDevice->v, converter, semanticsContext, stmtCtx, dataOperands,
           mlir::acc::DataClause::acc_use_device,
           /*structured=*/true, /*implicit=*/false, /*async=*/{},
-          /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{});
+          /*asyncDeviceTypes=*/{}, /*asyncOnlyDeviceTypes=*/{},
+          /*setDeclareAttr=*/false, &dataMap);
     } else if (std::get_if<Fortran::parser::AccClause::IfPresent>(&clause.u)) {
       addIfPresentAttr = true;
     }
@@ -3400,6 +3441,9 @@ genACCHostDataOp(Fortran::lower::AbstractConverter 
&converter,
 
   if (addIfPresentAttr)
     hostDataOp.setIfPresentAttr(builder.getUnitAttr());
+
+  // Remap symbols from use_device clauses to use the data operation results.
+  dataMap.remapDataOperandSymbols(converter, builder, hostDataOp.getRegion());
 }
 
 static void genACC(Fortran::lower::AbstractConverter &converter,
@@ -5063,8 +5107,7 @@ mlir::Operation 
*Fortran::lower::genOpenACCLoopFromDoConstruct(
       workerNumOperands, vectorOperands, tileOperands, cacheOperands,
       reductionOperands;
   llvm::SmallVector<mlir::Type> retTy;
-  llvm::SmallVector<std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
-      dataOperandSymbolPairs;
+  AccDataMap dataMap;
   mlir::Value yieldValue;
   uint64_t loopsToProcess = 1; // Single loop construct
 
@@ -5073,7 +5116,7 @@ mlir::Operation 
*Fortran::lower::genOpenACCLoopFromDoConstruct(
   Fortran::lower::StatementContext stmtCtx;
   auto loopOp = buildACCLoopOp(
       converter, converter.getCurrentLocation(), semanticsContext, stmtCtx,
-      doConstruct, eval, privateOperands, dataOperandSymbolPairs, gangOperands,
+      doConstruct, eval, privateOperands, dataMap, gangOperands,
       workerNumOperands, vectorOperands, tileOperands, cacheOperands,
       reductionOperands, retTy, yieldValue, loopsToProcess);
 
diff --git a/flang/lib/Lower/Support/Utils.cpp 
b/flang/lib/Lower/Support/Utils.cpp
index 4b95a3adf052a..159ce5211dacb 100644
--- a/flang/lib/Lower/Support/Utils.cpp
+++ b/flang/lib/Lower/Support/Utils.cpp
@@ -611,6 +611,10 @@ unsigned getHashValue(const 
Fortran::lower::ExplicitIterSpace::ArrayBases &x) {
       [&](const auto *p) { return HashEvaluateExpr::getHashValue(*p); }, x);
 }
 
+unsigned getHashValue(const Fortran::evaluate::Component *x) {
+  return HashEvaluateExpr::getHashValue(*x);
+}
+
 bool isEqual(const Fortran::lower::SomeExpr *x,
              const Fortran::lower::SomeExpr *y) {
   const auto *empty =
@@ -642,6 +646,17 @@ bool isEqual(const 
Fortran::lower::ExplicitIterSpace::ArrayBases &x,
       x, y);
 }
 
+bool isEqual(const Fortran::evaluate::Component *x,
+             const Fortran::evaluate::Component *y) {
+  const auto *empty =
+      llvm::DenseMapInfo<const Fortran::evaluate::Component *>::getEmptyKey();
+  const auto *tombstone = llvm::DenseMapInfo<
+      const Fortran::evaluate::Component *>::getTombstoneKey();
+  if (x == empty || y == empty || x == tombstone || y == tombstone)
+    return x == y;
+  return x == y || IsEqualEvaluateExpr::isEqual(*x, *y);
+}
+
 void copyFirstPrivateSymbol(lower::AbstractConverter &converter,
                             const semantics::Symbol *sym,
                             mlir::OpBuilder::InsertPoint *copyAssignIP) {
diff --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp
index 78529e0d539fb..40af6a1220e49 100644
--- a/flang/lib/Lower/SymbolMap.cpp
+++ b/flang/lib/Lower/SymbolMap.cpp
@@ -111,6 +111,16 @@ 
Fortran::lower::SymMap::lookupStorage(Fortran::semantics::SymbolRef symRef) {
 
 void Fortran::lower::SymbolBox::dump() const { llvm::errs() << *this << '\n'; }
 
+void Fortran::lower::ComponentMap::dump() const {
+  llvm::errs() << "ComponentMap:\n";
+  for (const auto &entry : componentMap) {
+    const auto *component = entry.first;
+    llvm::errs() << "  component @" << static_cast<const void *>(component)
+                 << " ->\n    ";
+    llvm::errs() << entry.second << '\n';
+  }
+}
+
 void Fortran::lower::SymMap::dump() const { llvm::errs() << *this << '\n'; }
 
 llvm::raw_ostream &
@@ -140,5 +150,17 @@ Fortran::lower::operator<<(llvm::raw_ostream &os,
     }
     os << " }>\n";
   }
+
+  os << "Component map:\n";
+  for (auto i : llvm::enumerate(symMap.componentMapStack)) {
+    if (!i.value()) {
+      os << " level " << i.index() << "<{}>\n";
+    } else {
+      os << " level " << i.index() << "<{\n";
+      (*i.value())->dump();
+      os << " }>\n";
+    }
+  }
+
   return os;
 }
diff --git a/flang/test/Lower/OpenACC/acc-host-data.f90 
b/flang/test/Lower/OpenACC/acc-host-data.f90
index 2cf8060bcf8d1..8d769d5c8babd 100644
--- a/flang/test/Lower/OpenACC/acc-host-data.f90
+++ b/flang/test/Lower/OpenACC/acc-host-data.f90
@@ -15,36 +15,33 @@ subroutine acc_host_data()
   !$acc end host_data
 
 ! CHECK: %[[DA0:.*]] = acc.use_device varPtr(%[[DECLA]]#0 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: %[[DA1:.*]] = acc.use_device varPtr(%[[DECLA]]#1 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: acc.host_data dataOperands(%[[DA0]], %[[DA1]] : 
!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
+! CHECK: acc.host_data dataOperands(%[[DA0]] : !fir.ref<!fir.array<10xf32>>)
 
   !$acc host_data use_device(a) if_present
   !$acc end host_data
 
 ! CHECK: %[[DA0:.*]] = acc.use_device varPtr(%[[DECLA]]#0 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: %[[DA1:.*]] = acc.use_device varPtr(%[[DECLA]]#1 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: acc.host_data dataOperands(%[[DA0]], %[[DA1]] : 
!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
+! CHECK: acc.host_data dataOperands(%[[DA0]] : !fir.ref<!fir.array<10xf32>>)
 ! CHECK: } attributes {ifPresent}
 
   !$acc host_data use_device(a) if_present
   !$acc end host_data
-! CHECK: acc.host_data dataOperands(%{{.*}}{{.*}} : 
!fir.ref<!fir.array<10xf32>>{{.*}}) {
+! CHECK: acc.host_data dataOperands(%{{.*}} : !fir.ref<!fir.array<10xf32>>) {
 ! CHECK: } attributes {ifPresent}
 
   !$acc host_data use_device(a) if(ifCondition)
   !$acc end host_data
 
 ! CHECK: %[[DA0:.*]] = acc.use_device varPtr(%[[DECLA]]#0 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: %[[DA1:.*]] = acc.use_device varPtr(%[[DECLA]]#1 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
 ! CHECK: %[[LOAD_IFCOND:.*]] = fir.load %[[DECLIFCOND]]#0 : 
!fir.ref<!fir.logical<4>>
 ! CHECK: %[[IFCOND_I1:.*]] = fir.convert %[[LOAD_IFCOND]] : (!fir.logical<4>) 
-> i1
-! CHECK: acc.host_data if(%[[IFCOND_I1]]) dataOperands(%[[DA0]]{{.*}} : 
!fir.ref<!fir.array<10xf32>>{{.*}})
+! CHECK: acc.host_data if(%[[IFCOND_I1]]) dataOperands(%[[DA0]] : 
!fir.ref<!fir.array<10xf32>>)
 
   !$acc host_data use_device(a) if(.true.)
   !$acc end host_data
 
 ! CHECK: %[[DA:.*]] = acc.use_device varPtr(%[[DECLA]]#0 : 
!fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "a"}
-! CHECK: acc.host_data dataOperands(%[[DA]]{{.*}} : 
!fir.ref<!fir.array<10xf32>>{{.*}})
+! CHECK: acc.host_data dataOperands(%[[DA]] : !fir.ref<!fir.array<10xf32>>)
 
   !$acc host_data use_device(a) if(.false.)
     a = 1.0
diff --git a/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 
b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90
new file mode 100644
index 0000000000000..0deaa0dffb351
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90
@@ -0,0 +1,156 @@
+! Test remapping of component references in data clauses.
+! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
+
+module mhdata_types
+  type t_scalar
+      integer :: x
+      real :: y
+  end type
+  type t_array
+      integer :: x
+      real :: y(10)
+  end type
+  type t_character
+      integer :: x
+      character(5) :: y
+  end type
+  type t_pointer
+      integer :: x
+      real, pointer :: y(:)
+  end type
+  type t_nested
+    type(t_array) :: comp(100)
+  end type
+end module
+
+subroutine test_scalar_comp(obj)
+  use mhdata_types, only : t_scalar
+  type(t_scalar) :: obj
+  !$acc host_data use_device(obj%y)
+  call foo_scalar(obj%y)
+  !$acc end host_data
+end subroutine
+
+subroutine test_array_comp(obj)
+  use mhdata_types, only : t_array
+  type(t_array) :: obj
+  !$acc host_data use_device(obj%y)
+  call foo_array(obj%y)
+  !$acc end host_data
+end subroutine
+
+subroutine test_character_comp(obj)
+  use mhdata_types, only : t_character
+  type(t_character) :: obj
+  !$acc host_data use_device(obj%y)
+  call foo_character(obj%y)
+  !$acc end host_data
+end subroutine
+
+subroutine test_pointer_comp(obj)
+  use mhdata_types, only : t_pointer
+  type(t_pointer) :: obj
+  interface
+    subroutine foo_pointer(x)
+      real, pointer :: x(:)
+    end subroutine
+  end interface
+  !$acc host_data use_device(obj%y)
+  call foo_pointer(obj%y)
+  !$acc end host_data
+end subroutine
+
+subroutine test_nested_comp(obj)
+  use mhdata_types, only : t_nested
+  type(t_nested) :: obj(:)
+  !$acc host_data use_device(obj(10)%comp(2)%y(4))
+  call foo_nested(obj(10)%comp(2)%y(4))
+  !$acc end host_data
+end subroutine
+
+! CHECK-LABEL:   func.func @_QPtest_scalar_comp(
+! CHECK-SAME:      %[[ARG0:.*]]: 
!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>> {fir.bindc_name = 
"obj"}) {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_scalar_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, !fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, 
!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>)
+! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  : (!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>) -> 
!fir.ref<f32>
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<f32>) -> !fir.ref<f32> {name = 
"obj%[[VAL_0:.*]]"}
+! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<f32>) {
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<f32>) -> (!fir.ref<f32>, 
!fir.ref<f32>)
+! CHECK:             fir.call @_QPfoo_scalar(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<f32>) -> ()
+! CHECK:             acc.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
+
+! CHECK-LABEL:   func.func @_QPtest_array_comp(
+! CHECK-SAME:      %[[ARG0:.*]]: 
!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>> 
{fir.bindc_name = "obj"}) {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_array_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, 
!fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, 
!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>)
+! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 10 : index
+! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> 
!fir.shape<1>
+! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  shape %[[SHAPE_0]] : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, 
!fir.shape<1>) -> !fir.ref<!fir.array<10xf32>>
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.array<10xf32>>) -> 
!fir.ref<!fir.array<10xf32>> {name = "obj%[[VAL_0:.*]]"}
+! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.array<10xf32>>) {
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_0]]) {uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, 
!fir.ref<!fir.array<10xf32>>)
+! CHECK:             fir.call @_QPfoo_array(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<!fir.array<10xf32>>) -> ()
+! CHECK:             acc.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
+
+! CHECK-LABEL:   func.func @_QPtest_character_comp(
+! CHECK-SAME:      %[[ARG0:.*]]: 
!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>> 
{fir.bindc_name = "obj"}) {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_character_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
!fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>)
+! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 5 : index
+! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  typeparams %[[CONSTANT_0]] : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
index) -> !fir.ref<!fir.char<1,5>>
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.char<1,5>>) -> !fir.ref<!fir.char<1,5>> 
{name = "obj%[[VAL_0:.*]]"}
+! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.char<1,5>>) {
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
typeparams %[[CONSTANT_0]] {uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, 
!fir.ref<!fir.char<1,5>>)
+! CHECK:             %[[EMBOXCHAR_0:.*]] = fir.emboxchar %[[DECLARE_1]]#0, 
%[[CONSTANT_0]] : (!fir.ref<!fir.char<1,5>>, index) -> !fir.boxchar<1>
+! CHECK:             fir.call @_QPfoo_character(%[[EMBOXCHAR_0]]) 
fastmath<contract> : (!fir.boxchar<1>) -> ()
+! CHECK:             acc.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
+
+! CHECK-LABEL:   func.func @_QPtest_pointer_comp(
+! CHECK-SAME:      %[[ARG0:.*]]: 
!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>
 {fir.bindc_name = "obj"}) {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_pointer_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>,
 !fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>,
 
!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
+! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  {fortran_attrs = #fir.var_attrs<pointer>} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
 -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {name = "obj%[[VAL_0:.*]]"}
+! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) {
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
+! CHECK:             fir.call @_QPfoo_pointer(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> ()
+! CHECK:             acc.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
+
+! CHECK-LABEL:   func.func @_QPtest_nested_comp(
+! CHECK-SAME:      %[[ARG0:.*]]: 
!fir.box<!fir.array<?x!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>>
 {fir.bindc_name = "obj"}) {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_nested_compEobj"} : 
(!fir.box<!fir.array<?x!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>>,
 !fir.dscope) -> 
(!fir.box<!fir.array<?x!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>>,
 
!fir.box<!fir.array<?x!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>>)
+! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 10 : index
+! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0 
(%[[CONSTANT_0]])  : 
(!fir.box<!fir.array<?x!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>>,
 index) -> 
!fir.ref<!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>
+! CHECK:           %[[CONSTANT_1:.*]] = arith.constant 100 : index
+! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_1]] : (index) -> 
!fir.shape<1>
+! CHECK:           %[[CONSTANT_2:.*]] = arith.constant 2 : index
+! CHECK:           %[[DESIGNATE_1:.*]] = hlfir.designate 
%[[DESIGNATE_0]]{"comp"} <%[[SHAPE_0]]> (%[[CONSTANT_2]])  : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_nested{comp:!fir.array<100x!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>}>>,
 !fir.shape<1>, index) -> 
!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>
+! CHECK:           %[[CONSTANT_3:.*]] = arith.constant 10 : index
+! CHECK:           %[[SHAPE_1:.*]] = fir.shape %[[CONSTANT_3]] : (index) -> 
!fir.shape<1>
+! CHECK:           %[[DESIGNATE_2:.*]] = hlfir.designate %[[DESIGNATE_1]]{"y"} 
  shape %[[SHAPE_1]] : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, 
!fir.shape<1>) -> !fir.ref<!fir.array<10xf32>>
+! CHECK:           %[[CONSTANT_4:.*]] = arith.constant 1 : index
+! CHECK:           %[[CONSTANT_5:.*]] = arith.constant 3 : index
+! CHECK:           %[[BOUNDS_0:.*]] = acc.bounds lowerbound(%[[CONSTANT_5]] : 
index) upperbound(%[[CONSTANT_5]] : index) extent(%[[CONSTANT_4]] : index) 
stride(%[[CONSTANT_4]] : index) startIdx(%[[CONSTANT_4]] : index)
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_2]] : !fir.ref<!fir.array<10xf32>>) bounds(%[[BOUNDS_0]]) 
-> !fir.ref<!fir.array<10xf32>> {name = 
"obj(10_8)%[[VAL_0:.*]](2_8)%[[VAL_1:.*]](4)"}
+! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.array<10xf32>>) {
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_1]]) {uniq_name = 
"obj(10_8)%[[VAL_0]](2_8)%[[VAL_1]](4)"} : (!fir.ref<!fir.array<10xf32>>, 
!fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
+! CHECK:             %[[CONSTANT_6:.*]] = arith.constant 4 : index
+! CHECK:             %[[DESIGNATE_3:.*]] = hlfir.designate %[[DECLARE_1]]#0 
(%[[CONSTANT_6]])  : (!fir.ref<!fir.array<10xf32>>, index) -> !fir.ref<f32>
+! CHECK:             fir.call @_QPfoo_nested(%[[DESIGNATE_3]]) 
fastmath<contract> : (!fir.ref<f32>) -> ()
+! CHECK:             acc.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
diff --git a/flang/test/Lower/OpenACC/acc-use-device.f90 
b/flang/test/Lower/OpenACC/acc-use-device.f90
index 4f9ed2d70b3ec..b1a78cf3589b6 100644
--- a/flang/test/Lower/OpenACC/acc-use-device.f90
+++ b/flang/test/Lower/OpenACC/acc-use-device.f90
@@ -18,9 +18,10 @@ subroutine test()
   call vadd(b)
   !$acc end host_data
 ! CHECK: %[[C:.*]] = acc.use_device var(%[[A]]#0 : 
!fir.box<!fir.array<?xf64>>) -> !fir.box<!fir.array<?xf64>> {name = "b"}
-! CHECK: %[[D:.*]] = acc.use_device varPtr(%[[A]]#1 : 
!fir.ref<!fir.array<?xf64>>) -> !fir.ref<!fir.array<?xf64>> {name = "b"}
-! CHECK: acc.host_data dataOperands(%[[C]], %[[D]] : 
!fir.box<!fir.array<?xf64>>, !fir.ref<!fir.array<?xf64>>) {
-! CHECK: fir.call @_QPvadd(%[[A]]#1) fastmath<contract> : 
(!fir.ref<!fir.array<?xf64>>) -> ()
+! CHECK: acc.host_data dataOperands(%[[C]] : !fir.box<!fir.array<?xf64>>) {
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[C]] 
+! CHECK: %[[REDCLARE:.*]]:2 = hlfir.declare %[[ADDR]]
+! CHECK: fir.call @_QPvadd(%[[REDCLARE]]#1) fastmath<contract> : 
(!fir.ref<!fir.array<?xf64>>) -> ()
   !$acc end data
 ! CHECK: acc.copyout accVar(%[[B]] : !fir.box<!fir.array<?xf64>>) to 
var(%[[A]]#0 : !fir.box<!fir.array<?xf64>>) {dataClause = #acc<data_clause 
acc_copy>, name = "b"}
 end
@@ -46,12 +47,9 @@ subroutine test2(a, b, c)
   !$acc end host_data
 
 ! CHECK: %[[H:.*]] = acc.use_device varPtr(%[[E]]#0 : 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>) -> 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>> {name = "a"}
-! CHECK: %[[I:.*]] = acc.use_device varPtr(%[[E]]#1 : 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>) -> 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>> {name = "a"}
 ! CHECK: %[[J:.*]] = acc.use_device var(%[[F]]#0 : 
!fir.box<!fir.array<?xf64>>) -> !fir.box<!fir.array<?xf64>> {name = "b"}
-! CHECK: %[[K:.*]] = acc.use_device var(%[[F]]#1 : 
!fir.box<!fir.array<?xf64>>) -> !fir.box<!fir.array<?xf64>> {name = "b"}
 ! CHECK: %[[L:.*]] = acc.use_device varPtr(%[[G]]#0 : 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>) -> 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>> {name = "c"}
-! CHECK: %[[M:.*]] = acc.use_device varPtr(%[[G]]#1 : 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>) -> 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>> {name = "c"}
-! CHECK: acc.host_data dataOperands(%[[H]], %[[I]], %[[J]], %[[K]], %[[L]], 
%[[M]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, !fir.box<!fir.array<?xf64>>, 
!fir.box<!fir.array<?xf64>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>, 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>) {
+! CHECK: acc.host_data dataOperands(%[[H]], %[[J]], %[[L]] : 
!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, !fir.box<!fir.array<?xf64>>, 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>) {
 
 
 
diff --git 
a/flang/test/Transforms/OpenACC/acc-implicit-data-derived-type-member.F90 
b/flang/test/Transforms/OpenACC/acc-implicit-data-derived-type-member.F90
index 71e7d79b7260f..f54a82bdc305e 100644
--- a/flang/test/Transforms/OpenACC/acc-implicit-data-derived-type-member.F90
+++ b/flang/test/Transforms/OpenACC/acc-implicit-data-derived-type-member.F90
@@ -22,7 +22,7 @@ program test
   d2%member0 = 123
   !$acc serial copyin(d2%member0) copyout(d4%member0)
   do i0 = 1, 1
-    d4%member0 = d2%member0
+    d4 = d2
   end do
   !$acc end serial
 end program

>From b3d6a0b4d50fde517ff80386d88a82a9d04f58ae Mon Sep 17 00:00:00 2001
From: Jean Perier <[email protected]>
Date: Wed, 10 Dec 2025 05:57:26 -0800
Subject: [PATCH 2/2] review comments

---
 flang/lib/Lower/OpenACC.cpp                   |  6 +++---
 .../OpenACC/acc-use-device-remapping.f90      | 21 ++++++++++---------
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index ac6a845fa74ec..9ff45aa53614f 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -705,9 +705,9 @@ createOrGetRecipe(fir::FirOpBuilder &builder, 
mlir::Location loc,
 }
 
 namespace {
-// Helper class to keep track how the Designator that appear in the
-// data clauses of structured constructs so that they can be remapped
-// to the data operation result inside the scope of the construct.
+// Helper class to keep track of designators that appear in data clauses of
+// structured constructs so that they can be remapped to the data operation
+// result inside the scope of the constructs.
 class AccDataMap {
 public:
   struct DataComponent {
diff --git a/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 
b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90
index 0deaa0dffb351..21d88ceab59d7 100644
--- a/flang/test/Lower/OpenACC/acc-use-device-remapping.f90
+++ b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90
@@ -73,9 +73,9 @@ subroutine test_nested_comp(obj)
 ! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_scalar_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, !fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, 
!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>)
 ! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  : (!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>) -> 
!fir.ref<f32>
-! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<f32>) -> !fir.ref<f32> {name = 
"obj%[[VAL_0:.*]]"}
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<f32>) -> !fir.ref<f32> {name = "obj%y"}
 ! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<f32>) {
-! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<f32>) -> (!fir.ref<f32>, 
!fir.ref<f32>)
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{uniq_name = "obj%y"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
 ! CHECK:             fir.call @_QPfoo_scalar(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<f32>) -> ()
 ! CHECK:             acc.terminator
 ! CHECK:           }
@@ -89,9 +89,9 @@ subroutine test_nested_comp(obj)
 ! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 10 : index
 ! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> 
!fir.shape<1>
 ! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  shape %[[SHAPE_0]] : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, 
!fir.shape<1>) -> !fir.ref<!fir.array<10xf32>>
-! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.array<10xf32>>) -> 
!fir.ref<!fir.array<10xf32>> {name = "obj%[[VAL_0:.*]]"}
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.array<10xf32>>) -> 
!fir.ref<!fir.array<10xf32>> {name = "obj%y"}
 ! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.array<10xf32>>) {
-! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_0]]) {uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, 
!fir.ref<!fir.array<10xf32>>)
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_0]]) {uniq_name = "obj%y"} : 
(!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, 
!fir.ref<!fir.array<10xf32>>)
 ! CHECK:             fir.call @_QPfoo_array(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<!fir.array<10xf32>>) -> ()
 ! CHECK:             acc.terminator
 ! CHECK:           }
@@ -104,9 +104,9 @@ subroutine test_nested_comp(obj)
 ! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_character_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
!fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>)
 ! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 5 : index
 ! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  typeparams %[[CONSTANT_0]] : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, 
index) -> !fir.ref<!fir.char<1,5>>
-! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.char<1,5>>) -> !fir.ref<!fir.char<1,5>> 
{name = "obj%[[VAL_0:.*]]"}
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.char<1,5>>) -> !fir.ref<!fir.char<1,5>> 
{name = "obj%y"}
 ! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.char<1,5>>) {
-! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
typeparams %[[CONSTANT_0]] {uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, 
!fir.ref<!fir.char<1,5>>)
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
typeparams %[[CONSTANT_0]] {uniq_name = "obj%y"} : (!fir.ref<!fir.char<1,5>>, 
index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
 ! CHECK:             %[[EMBOXCHAR_0:.*]] = fir.emboxchar %[[DECLARE_1]]#0, 
%[[CONSTANT_0]] : (!fir.ref<!fir.char<1,5>>, index) -> !fir.boxchar<1>
 ! CHECK:             fir.call @_QPfoo_character(%[[EMBOXCHAR_0]]) 
fastmath<contract> : (!fir.boxchar<1>) -> ()
 ! CHECK:             acc.terminator
@@ -119,9 +119,9 @@ subroutine test_nested_comp(obj)
 ! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope 
%[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_pointer_compEobj"} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>,
 !fir.dscope) -> 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>,
 
!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
 ! CHECK:           %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} 
  {fortran_attrs = #fir.var_attrs<pointer>} : 
(!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>)
 -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
-! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {name = "obj%[[VAL_0:.*]]"}
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {name = "obj%y"}
 ! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) {
-! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "obj%[[VAL_0]]"} : 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] 
{fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "obj%y"} : 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> 
(!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, 
!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
 ! CHECK:             fir.call @_QPfoo_pointer(%[[DECLARE_1]]#0) 
fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> ()
 ! CHECK:             acc.terminator
 ! CHECK:           }
@@ -144,9 +144,10 @@ subroutine test_nested_comp(obj)
 ! CHECK:           %[[CONSTANT_4:.*]] = arith.constant 1 : index
 ! CHECK:           %[[CONSTANT_5:.*]] = arith.constant 3 : index
 ! CHECK:           %[[BOUNDS_0:.*]] = acc.bounds lowerbound(%[[CONSTANT_5]] : 
index) upperbound(%[[CONSTANT_5]] : index) extent(%[[CONSTANT_4]] : index) 
stride(%[[CONSTANT_4]] : index) startIdx(%[[CONSTANT_4]] : index)
-! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_2]] : !fir.ref<!fir.array<10xf32>>) bounds(%[[BOUNDS_0]]) 
-> !fir.ref<!fir.array<10xf32>> {name = 
"obj(10_8)%[[VAL_0:.*]](2_8)%[[VAL_1:.*]](4)"}
+! CHECK:           %[[USE_DEVICE_0:.*]] = acc.use_device 
varPtr(%[[DESIGNATE_2]] : !fir.ref<!fir.array<10xf32>>)
+! bounds(%[[BOUNDS_0]]) -> !fir.ref<!fir.array<10xf32>> {name = 
"obj(10_8)%comp(2_8)%y(4)"}
 ! CHECK:           acc.host_data dataOperands(%[[USE_DEVICE_0]] : 
!fir.ref<!fir.array<10xf32>>) {
-! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_1]]) {uniq_name = 
"obj(10_8)%[[VAL_0]](2_8)%[[VAL_1]](4)"} : (!fir.ref<!fir.array<10xf32>>, 
!fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
+! CHECK:             %[[DECLARE_1:.*]]:2 = hlfir.declare 
%[[USE_DEVICE_0]](%[[SHAPE_1]]) {uniq_name = "obj(10_8)%comp(2_8)%y(4)"} : 
(!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, 
!fir.ref<!fir.array<10xf32>>)
 ! CHECK:             %[[CONSTANT_6:.*]] = arith.constant 4 : index
 ! CHECK:             %[[DESIGNATE_3:.*]] = hlfir.designate %[[DECLARE_1]]#0 
(%[[CONSTANT_6]])  : (!fir.ref<!fir.array<10xf32>>, index) -> !fir.ref<f32>
 ! CHECK:             fir.call @_QPfoo_nested(%[[DESIGNATE_3]]) 
fastmath<contract> : (!fir.ref<f32>) -> ()

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to