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

OpenACC data clauses of structured constructs may contain component references 
(`obj%comp`, or `obj%array(i:j:k)`, ...).

This changes allows using the ACC dialect data operation result for such 
clauses every time the component is referred to inside the scope of the 
construct.

The bulk of the change is to add the ability to map `evaluate::Component` to 
mlir values in the symbol map used in lowering.
This is done by adding the `ComponentMap` helper class to the lowering symbol 
map, and using it to override `evaluate::Component` reference lowering in 
expression lowering (ConvertExprToHLFIR.cpp).

Some changes are made in Lower/Support/Utils.h in order to set-up/expose the 
hashing/equality helpers needed to use `evaluate::Component` in llvm::DenseMap.

In OpenACC.cpp, `genPrivatizationRecipes` and `genDataOperandOperations` are 
merged to unify the processing of Designator in data clauses.

New code is added to unwrap the rightmost `evaluate::Component`, if any, and 
remap it.

Note that when the right most part is an array reference on a component 
(`obj%array(i:j:k)`), the whole component `obj%array(` is remapped, and the 
array reference is dealt with a bound operand like for whole object array.

After this patch, all designators in data clauses on structured constructs will 
be remapped, except for array reference in private/first private/reduction (the 
result type of the related operation needs to be changed and the recipe adapted 
to "offset back"),  component reference in reduction (this patch is adding a 
TODO for it), and device_ptr (previously bypassed remapping because of issues 
with descriptors, should be OK to lift it in a further patch).

Note that this patch assumes that it is illegal to have code with intermediate 
variable indexing in the component reference (e.g. `array(i)%comp`) where the 
value of the index would be changed inside the region (e.g., `i` is assigned a 
new value), or where the component would be used with different indices meant 
to have the same value as the one used in the clause (e.g. `array(i)%comp` 
where `j` is meant to be the same as `i`). I will try to add a warning in 
semantics for such questionable/risky usages.

>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] [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

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

Reply via email to