https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/171501
>From 9dd6758cb6322eb3224794657e5122c7d689c309 Mon Sep 17 00:00:00 2001 From: Jean Perier <[email protected]> Date: Mon, 8 Dec 2025 07:59:43 -0800 Subject: [PATCH 1/2] [flang][OpenACC] remap component references in structured constructs --- flang/include/flang/Lower/AbstractConverter.h | 1 + flang/include/flang/Lower/Support/Utils.h | 43 +- flang/include/flang/Lower/SymbolMap.h | 74 +++ flang/lib/Lower/ConvertExprToHLFIR.cpp | 16 +- flang/lib/Lower/OpenACC.cpp | 565 ++++++++++-------- flang/lib/Lower/Support/Utils.cpp | 15 + flang/lib/Lower/SymbolMap.cpp | 22 + flang/test/Lower/OpenACC/acc-host-data.f90 | 13 +- .../OpenACC/acc-use-device-remapping.f90 | 156 +++++ flang/test/Lower/OpenACC/acc-use-device.f90 | 12 +- .../acc-implicit-data-derived-type-member.F90 | 2 +- 11 files changed, 637 insertions(+), 282 deletions(-) create mode 100644 flang/test/Lower/OpenACC/acc-use-device-remapping.f90 diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index f93f7ad867b30..8109ebdc75688 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -16,6 +16,7 @@ #include "flang/Lower/LoweringOptions.h" #include "flang/Lower/PFTDefs.h" #include "flang/Lower/Support/Utils.h" +#include "flang/Lower/SymbolMap.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Semantics/symbol.h" diff --git a/flang/include/flang/Lower/Support/Utils.h b/flang/include/flang/Lower/Support/Utils.h index eac5cad91f608..4e83a0e3bfec7 100644 --- a/flang/include/flang/Lower/Support/Utils.h +++ b/flang/include/flang/Lower/Support/Utils.h @@ -14,7 +14,6 @@ #define FORTRAN_LOWER_SUPPORT_UTILS_H #include "flang/Common/indirection.h" -#include "flang/Lower/IterationSpace.h" #include "flang/Parser/char-block.h" #include "flang/Semantics/tools.h" #include "mlir/Dialect/Arith/IR/Arith.h" @@ -23,10 +22,25 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" +namespace Fortran::evaluate { +class Component; +class ArrayRef; +} // namespace Fortran::evaluate + namespace Fortran::lower { using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>; +using ExplicitSpaceArrayBases = + std::variant<const semantics::Symbol *, const evaluate::Component *, + const evaluate::ArrayRef *>; +// FIXME: needed for privatizeSymbol that does not belong to this header. +class AbstractConverter; +class SymMap; } // end namespace Fortran::lower +namespace fir { +class FirOpBuilder; +} + //===----------------------------------------------------------------------===// // Small inline helper functions to deal with repetitive, clumsy conversions. //===----------------------------------------------------------------------===// @@ -89,12 +103,15 @@ A flatZip(const A &container1, const A &container2) { namespace Fortran::lower { unsigned getHashValue(const Fortran::lower::SomeExpr *x); -unsigned getHashValue(const Fortran::lower::ExplicitIterSpace::ArrayBases &x); +unsigned getHashValue(const Fortran::lower::ExplicitSpaceArrayBases &x); +unsigned getHashValue(const Fortran::evaluate::Component *x); bool isEqual(const Fortran::lower::SomeExpr *x, const Fortran::lower::SomeExpr *y); -bool isEqual(const Fortran::lower::ExplicitIterSpace::ArrayBases &x, - const Fortran::lower::ExplicitIterSpace::ArrayBases &y); +bool isEqual(const Fortran::lower::ExplicitSpaceArrayBases &x, + const Fortran::lower::ExplicitSpaceArrayBases &y); +bool isEqual(const Fortran::evaluate::Component *x, + const Fortran::evaluate::Component *y); template <typename OpType, typename OperandsStructType> void privatizeSymbol( @@ -125,6 +142,24 @@ struct DenseMapInfo<const Fortran::lower::SomeExpr *> { return Fortran::lower::isEqual(lhs, rhs); } }; + +// DenseMapInfo for pointers to Fortran::evaluate::Component. +template <> +struct DenseMapInfo<const Fortran::evaluate::Component *> { + static inline const Fortran::evaluate::Component *getEmptyKey() { + return reinterpret_cast<Fortran::evaluate::Component *>(~0); + } + static inline const Fortran::evaluate::Component *getTombstoneKey() { + return reinterpret_cast<Fortran::evaluate::Component *>(~0 - 1); + } + static unsigned getHashValue(const Fortran::evaluate::Component *v) { + return Fortran::lower::getHashValue(v); + } + static bool isEqual(const Fortran::evaluate::Component *lhs, + const Fortran::evaluate::Component *rhs) { + return Fortran::lower::isEqual(lhs, rhs); + } +}; } // namespace llvm #endif // FORTRAN_LOWER_SUPPORT_UTILS_H diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h index e57b6a42d3cc1..2b0c2ecbf1280 100644 --- a/flang/include/flang/Lower/SymbolMap.h +++ b/flang/include/flang/Lower/SymbolMap.h @@ -14,6 +14,7 @@ #define FORTRAN_LOWER_SYMBOLMAP_H #include "flang/Common/reference.h" +#include "flang/Lower/Support/Utils.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/FortranVariableInterface.h" @@ -134,6 +135,41 @@ struct SymbolBox : public fir::details::matcher<SymbolBox> { VT box; }; +/// Helper class to map `Fortran::evaluate::Component` references to IR values. +/// This is used when the evaluation of a component reference must be +/// overridden with a pre-computed address. +class ComponentMap { +public: + void insert(const Fortran::evaluate::Component &component, + fir::FortranVariableOpInterface definingOp) { + auto iter = componentMap.find(&component); + if (iter != componentMap.end()) { + iter->second = definingOp; + return; + } + componentStorage.push_back( + std::make_unique<Fortran::evaluate::Component>(component)); + componentMap.insert({componentStorage.back().get(), definingOp}); + } + + std::optional<fir::FortranVariableOpInterface> + lookup(const Fortran::evaluate::Component *component) const { + auto iter = componentMap.find(component); + if (iter != componentMap.end()) + return iter->second; + return std::nullopt; + } + + LLVM_DUMP_METHOD void dump() const; + +private: + llvm::DenseMap<const Fortran::evaluate::Component *, + fir::FortranVariableOpInterface> + componentMap; + llvm::SmallVector<std::unique_ptr<Fortran::evaluate::Component>> + componentStorage; +}; + //===----------------------------------------------------------------------===// // Map of symbol information //===----------------------------------------------------------------------===// @@ -156,12 +192,15 @@ class SymMap { void pushScope() { symbolMapStack.emplace_back(); storageMapStack.emplace_back(); + componentMapStack.emplace_back(); } void popScope() { symbolMapStack.pop_back(); assert(symbolMapStack.size() >= 1); storageMapStack.pop_back(); assert(storageMapStack.size() >= 1); + componentMapStack.pop_back(); + assert(componentMapStack.size() >= 1); } /// Add an extended value to the symbol table. @@ -301,6 +340,8 @@ class SymMap { impliedDoStack.clear(); storageMapStack.clear(); storageMapStack.emplace_back(); + componentMapStack.clear(); + componentMapStack.emplace_back(); } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, @@ -329,6 +370,33 @@ class SymMap { return std::nullopt; } + /// Register a mapping from a front-end component reference to the FIR + /// variable that should be used to implement it. This is used to override + /// the default lowering of component references in specific contexts. + void addComponentOverride(const Fortran::evaluate::Component &component, + fir::FortranVariableOpInterface definingOp) { + assert(!componentMapStack.empty() && "component map stack is empty"); + if (!componentMapStack.back()) + componentMapStack.back() = std::make_unique<ComponentMap>(); + componentMapStack.back().value()->insert(component, definingOp); + } + + /// Lookup an overridden FIR variable definition for a given component + /// reference, if any. + std::optional<fir::FortranVariableOpInterface> + lookupComponentOverride(const Fortran::evaluate::Component &component) const { + for (auto jmap = componentMapStack.rbegin(), + jend = componentMapStack.rend(); + jmap != jend; ++jmap) { + if (*jmap) { + auto iter = (**jmap)->lookup(&component); + if (iter != std::nullopt) + return iter; + } + } + return std::nullopt; + } + /// Register the symbol's storage at the innermost level /// of the symbol table. If the storage is already registered, /// it will be replaced. @@ -360,6 +428,12 @@ class SymMap { // A stack of maps between the symbols and their storage descriptors. llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, StorageDesc>> storageMapStack; + + // A stack of maps from front-end component references to the FIR variables + // that should be used to implement them. This allows overriding component + // references in specific lowering contexts. + llvm::SmallVector<std::optional<std::unique_ptr<ComponentMap>>> + componentMapStack; }; /// RAII wrapper for SymMap. diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index 1eda1f1b61355..b079c9e6fa29b 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -368,6 +368,8 @@ class HlfirDesignatorBuilder { fir::FortranVariableOpInterface gen(const Fortran::evaluate::Component &component) { + if (auto remapped = symMap.lookupComponentOverride(component)) + return *remapped; if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol())) return genWholeAllocatableOrPointerComponent(component); PartInfo partInfo; @@ -477,6 +479,8 @@ class HlfirDesignatorBuilder { fir::FortranVariableOpInterface genWholeAllocatableOrPointerComponent( const Fortran::evaluate::Component &component) { + if (auto remapped = symMap.lookupComponentOverride(component)) + return *remapped; // Generate whole allocatable or pointer component reference. The // hlfir.designate result will be a pointer/allocatable. PartInfo partInfo; @@ -539,7 +543,8 @@ class HlfirDesignatorBuilder { // components need special care to deal with the array%array_comp(indices) // case. if (Fortran::semantics::IsAllocatableOrObjectPointer( - &component->GetLastSymbol())) + &component->GetLastSymbol()) || + symMap.lookupComponentOverride(*component)) baseType = visit(*component, partInfo); else baseType = hlfir::getFortranElementOrSequenceType( @@ -686,6 +691,15 @@ class HlfirDesignatorBuilder { partInfo.typeParams); return partInfo.base->getElementOrSequenceType(); } + if (auto remapped = symMap.lookupComponentOverride(component)) { + // Do not generate field for the designate if the component + // is overridden, the override value is already addressing + // the component. + partInfo.base = *remapped; + hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base, + partInfo.typeParams); + return partInfo.base->getElementOrSequenceType(); + } // This function must be called from contexts where the component is not the // base of an ArrayRef. In these cases, the component cannot be an array // if the base is an array. The code below determines the shape of the diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index b586ea3ac627b..ac6a845fa74ec 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -643,20 +643,123 @@ void genAtomicCapture(Fortran::lower::AbstractConverter &converter, firOpBuilder.setInsertionPointAfter(atomicCaptureOp); } +/// Rebuild the array type from the acc.bounds operation with constant +/// lowerbound/upperbound or extent. +static mlir::Type getTypeFromBounds(llvm::SmallVector<mlir::Value> &bounds, + mlir::Type ty) { + auto seqTy = + mlir::dyn_cast_or_null<fir::SequenceType>(fir::unwrapRefType(ty)); + if (!bounds.empty() && seqTy) { + llvm::SmallVector<int64_t> shape; + for (auto b : bounds) { + auto boundsOp = + mlir::dyn_cast<mlir::acc::DataBoundsOp>(b.getDefiningOp()); + if (boundsOp.getLowerbound() && + fir::getIntIfConstant(boundsOp.getLowerbound()) && + boundsOp.getUpperbound() && + fir::getIntIfConstant(boundsOp.getUpperbound())) { + int64_t ext = *fir::getIntIfConstant(boundsOp.getUpperbound()) - + *fir::getIntIfConstant(boundsOp.getLowerbound()) + 1; + shape.push_back(ext); + } else if (boundsOp.getExtent() && + fir::getIntIfConstant(boundsOp.getExtent())) { + shape.push_back(*fir::getIntIfConstant(boundsOp.getExtent())); + } else { + return ty; // TODO: handle dynamic shaped array slice. + } + } + if (shape.empty() || shape.size() != bounds.size()) + return ty; + auto newSeqTy = fir::SequenceType::get(shape, seqTy.getEleTy()); + if (mlir::isa<fir::ReferenceType, fir::PointerType>(ty)) + return fir::ReferenceType::get(newSeqTy); + return newSeqTy; + } + return ty; +} + +static mlir::SymbolRefAttr +createOrGetRecipe(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::acc::RecipeKind kind, mlir::Value addr, + llvm::SmallVector<mlir::Value> &bounds) { + mlir::Type ty = getTypeFromBounds(bounds, addr.getType()); + // Compute the canonical recipe name for the given kind, type, address and + // bounds so that recipes are shared wherever possible. + std::string recipeName = fir::acc::getRecipeName(kind, ty, addr, bounds); + + switch (kind) { + case mlir::acc::RecipeKind::private_recipe: { + auto recipe = + Fortran::lower::createOrGetPrivateRecipe(builder, recipeName, loc, ty); + return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); + } + case mlir::acc::RecipeKind::firstprivate_recipe: { + auto recipe = Fortran::lower::createOrGetFirstprivateRecipe( + builder, recipeName, loc, ty, bounds); + return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName()); + } + default: + llvm::report_fatal_error( + "createOrGetRecipe only supports private and firstprivate recipes"); + } +} + +namespace { +// Helper class to keep track how the Designator that appear in the +// data clauses of structured constructs so that they can be remapped +// to the data operation result inside the scope of the construct. +class AccDataMap { +public: + struct DataComponent { + // Semantic representation of the component reference that appeared + // inside the data clause and that will need to be remapped to the + // data operation result. + Fortran::evaluate::Component component; + // Operation that produced the component when lowering the data clause. + mlir::Value designate; + // data operation result. + mlir::Value accValue; + }; + void emplaceSymbol(mlir::Value accValue, Fortran::semantics::SymbolRef sym) { + symbols.emplace_back(mlir::Value(accValue), + Fortran::semantics::SymbolRef(*sym)); + } + void emplaceComponent(mlir::Value accValue, + Fortran::evaluate::Component &&comp, + mlir::Value designate) { + components.emplace_back( + DataComponent{std::move(comp), designate, accValue}); + } + bool empty() const { return symbols.empty() && components.empty(); } + + /// Remap symbols and components that appeared in OpenACC data clauses to use + /// the results of the corresponding data operations. This allows isolating + /// symbol accesses inside the OpenACC region from accesses in the host and + /// other regions while preserving Fortran information about the symbols for + /// optimizations. + void remapDataOperandSymbols(Fortran::lower::AbstractConverter &converter, + fir::FirOpBuilder &builder, + mlir::Region ®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 b3d6a0b4d50fde517ff80386d88a82a9d04f58ae Mon Sep 17 00:00:00 2001 From: Jean Perier <[email protected]> Date: Wed, 10 Dec 2025 05:57:26 -0800 Subject: [PATCH 2/2] review comments --- flang/lib/Lower/OpenACC.cpp | 6 +++--- .../OpenACC/acc-use-device-remapping.f90 | 21 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index ac6a845fa74ec..9ff45aa53614f 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -705,9 +705,9 @@ createOrGetRecipe(fir::FirOpBuilder &builder, mlir::Location loc, } namespace { -// Helper class to keep track how the Designator that appear in the -// data clauses of structured constructs so that they can be remapped -// to the data operation result inside the scope of the construct. +// Helper class to keep track of designators that appear in data clauses of +// structured constructs so that they can be remapped to the data operation +// result inside the scope of the constructs. class AccDataMap { public: struct DataComponent { diff --git a/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 index 0deaa0dffb351..21d88ceab59d7 100644 --- a/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 +++ b/flang/test/Lower/OpenACC/acc-use-device-remapping.f90 @@ -73,9 +73,9 @@ subroutine test_nested_comp(obj) ! CHECK: %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope ! CHECK: %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_scalar_compEobj"} : (!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>, !fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>) ! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} : (!fir.ref<!fir.type<_QMmhdata_typesTt_scalar{x:i32,y:f32}>>) -> !fir.ref<f32> -! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<f32>) -> !fir.ref<f32> {name = "obj%[[VAL_0:.*]]"} +! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<f32>) -> !fir.ref<f32> {name = "obj%y"} ! CHECK: acc.host_data dataOperands(%[[USE_DEVICE_0]] : !fir.ref<f32>) { -! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] {uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>) +! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] {uniq_name = "obj%y"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>) ! CHECK: fir.call @_QPfoo_scalar(%[[DECLARE_1]]#0) fastmath<contract> : (!fir.ref<f32>) -> () ! CHECK: acc.terminator ! CHECK: } @@ -89,9 +89,9 @@ subroutine test_nested_comp(obj) ! CHECK: %[[CONSTANT_0:.*]] = arith.constant 10 : index ! CHECK: %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1> ! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} shape %[[SHAPE_0]] : (!fir.ref<!fir.type<_QMmhdata_typesTt_array{x:i32,y:!fir.array<10xf32>}>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xf32>> -! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "obj%[[VAL_0:.*]]"} +! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.array<10xf32>>) -> !fir.ref<!fir.array<10xf32>> {name = "obj%y"} ! CHECK: acc.host_data dataOperands(%[[USE_DEVICE_0]] : !fir.ref<!fir.array<10xf32>>) { -! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]](%[[SHAPE_0]]) {uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) +! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]](%[[SHAPE_0]]) {uniq_name = "obj%y"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) ! CHECK: fir.call @_QPfoo_array(%[[DECLARE_1]]#0) fastmath<contract> : (!fir.ref<!fir.array<10xf32>>) -> () ! CHECK: acc.terminator ! CHECK: } @@ -104,9 +104,9 @@ subroutine test_nested_comp(obj) ! CHECK: %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_character_compEobj"} : (!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, !fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>) ! CHECK: %[[CONSTANT_0:.*]] = arith.constant 5 : index ! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} typeparams %[[CONSTANT_0]] : (!fir.ref<!fir.type<_QMmhdata_typesTt_character{x:i32,y:!fir.char<1,5>}>>, index) -> !fir.ref<!fir.char<1,5>> -! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.char<1,5>>) -> !fir.ref<!fir.char<1,5>> {name = "obj%[[VAL_0:.*]]"} +! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.char<1,5>>) -> !fir.ref<!fir.char<1,5>> {name = "obj%y"} ! CHECK: acc.host_data dataOperands(%[[USE_DEVICE_0]] : !fir.ref<!fir.char<1,5>>) { -! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] typeparams %[[CONSTANT_0]] {uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>) +! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] typeparams %[[CONSTANT_0]] {uniq_name = "obj%y"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>) ! CHECK: %[[EMBOXCHAR_0:.*]] = fir.emboxchar %[[DECLARE_1]]#0, %[[CONSTANT_0]] : (!fir.ref<!fir.char<1,5>>, index) -> !fir.boxchar<1> ! CHECK: fir.call @_QPfoo_character(%[[EMBOXCHAR_0]]) fastmath<contract> : (!fir.boxchar<1>) -> () ! CHECK: acc.terminator @@ -119,9 +119,9 @@ subroutine test_nested_comp(obj) ! CHECK: %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope ! CHECK: %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[DUMMY_SCOPE_0]] arg 1 {uniq_name = "_QFtest_pointer_compEobj"} : (!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.dscope) -> (!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>, !fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) ! CHECK: %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_0]]#0{"y"} {fortran_attrs = #fir.var_attrs<pointer>} : (!fir.ref<!fir.type<_QMmhdata_typesTt_pointer{x:i32,y:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> -! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {name = "obj%[[VAL_0:.*]]"} +! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> {name = "obj%y"} ! CHECK: acc.host_data dataOperands(%[[USE_DEVICE_0]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) { -! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "obj%[[VAL_0]]"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) +! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "obj%y"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) ! CHECK: fir.call @_QPfoo_pointer(%[[DECLARE_1]]#0) fastmath<contract> : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> () ! CHECK: acc.terminator ! CHECK: } @@ -144,9 +144,10 @@ subroutine test_nested_comp(obj) ! CHECK: %[[CONSTANT_4:.*]] = arith.constant 1 : index ! CHECK: %[[CONSTANT_5:.*]] = arith.constant 3 : index ! CHECK: %[[BOUNDS_0:.*]] = acc.bounds lowerbound(%[[CONSTANT_5]] : index) upperbound(%[[CONSTANT_5]] : index) extent(%[[CONSTANT_4]] : index) stride(%[[CONSTANT_4]] : index) startIdx(%[[CONSTANT_4]] : index) -! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_2]] : !fir.ref<!fir.array<10xf32>>) bounds(%[[BOUNDS_0]]) -> !fir.ref<!fir.array<10xf32>> {name = "obj(10_8)%[[VAL_0:.*]](2_8)%[[VAL_1:.*]](4)"} +! CHECK: %[[USE_DEVICE_0:.*]] = acc.use_device varPtr(%[[DESIGNATE_2]] : !fir.ref<!fir.array<10xf32>>) +! bounds(%[[BOUNDS_0]]) -> !fir.ref<!fir.array<10xf32>> {name = "obj(10_8)%comp(2_8)%y(4)"} ! CHECK: acc.host_data dataOperands(%[[USE_DEVICE_0]] : !fir.ref<!fir.array<10xf32>>) { -! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]](%[[SHAPE_1]]) {uniq_name = "obj(10_8)%[[VAL_0]](2_8)%[[VAL_1]](4)"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) +! CHECK: %[[DECLARE_1:.*]]:2 = hlfir.declare %[[USE_DEVICE_0]](%[[SHAPE_1]]) {uniq_name = "obj(10_8)%comp(2_8)%y(4)"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) ! CHECK: %[[CONSTANT_6:.*]] = arith.constant 4 : index ! CHECK: %[[DESIGNATE_3:.*]] = hlfir.designate %[[DECLARE_1]]#0 (%[[CONSTANT_6]]) : (!fir.ref<!fir.array<10xf32>>, index) -> !fir.ref<f32> ! CHECK: fir.call @_QPfoo_nested(%[[DESIGNATE_3]]) fastmath<contract> : (!fir.ref<f32>) -> () _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
