[flang-commits] [flang] [flang][OpenACC] remap component references in structured constructs (PR #171501)
via flang-commits
flang-commits at lists.llvm.org
Fri Dec 12 01:20:46 PST 2025
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/171501
>From feace08b671aef6d89ebec2dfac5299225b30fcd Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 8 Dec 2025 07:59:43 -0800
Subject: [PATCH 1/3] [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 ®ion) 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 ®ionOp,
- const llvm::SmallVector<
- std::pair<mlir::Value, Fortran::semantics::SymbolRef>>
- &dataOperandSymbolPairs) {
- if (!enableSymbolRemapping || dataOperandSymbolPairs.empty())
+ mlir::Region ®ion) 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(®ionOp.getRegion().front());
+ builder.setInsertionPointToStart(®ion.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 c47d65c648c6794be8ee2ec30aaf3152c3550ee7 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Wed, 10 Dec 2025 05:57:26 -0800
Subject: [PATCH 2/3] 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>) -> ()
>From b0d982bec1f4202c2e19e65891bac108ad5cea71 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Fri, 12 Dec 2025 00:38:42 -0800
Subject: [PATCH 3/3] limit no_create remapping until other issue is fixed
---
flang/lib/Lower/OpenACC.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 9ff45aa53614f..52fee7baf9de1 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -832,9 +832,16 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
if (auto *defOp = op.getVar().getDefiningOp())
addDeclareAttr(builder, defOp, dataClause);
+ // TODO: no_create remapping could currently cause segfaults because of the
+ // fir.box_addr that may be inserted in the remapping in the region.
+ // This is an issue if the variable is not mapped (which is OK if its
+ // accesses are not reached inside the construct).
+ bool isNoCreateWithBounds =
+ std::is_same_v<Op, mlir::acc::NoCreateOp> && !bounds.empty();
+
// Track the symbol and its corresponding mlir::Value if requested so that
// accesses inside regions can be remapped.
- if (dataMap && !isPrivateArraySection) {
+ if (dataMap && !isPrivateArraySection && !isNoCreateWithBounds) {
if (componentRef)
dataMap->emplaceComponent(op.getAccVar(), std::move(*componentRef),
baseAddr);
More information about the flang-commits
mailing list