diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h index 0d7038a7fd856..bbe3b01fdb29d 100644 --- a/flang/include/flang/Lower/OpenACC.h +++ b/flang/include/flang/Lower/OpenACC.h @@ -22,6 +22,9 @@ class StringRef; } // namespace llvm namespace mlir { +namespace func { +class FuncOp; +} // namespace func class Location; class Type; class ModuleOp; @@ -31,9 +34,13 @@ class Value; namespace fir { class FirOpBuilder; -} +} // namespace fir namespace Fortran { +namespace evaluate { +struct ProcedureDesignator; +} // namespace evaluate + namespace parser { struct AccClauseList; struct OpenACCConstruct; @@ -42,6 +49,7 @@ struct OpenACCRoutineConstruct; } // namespace parser namespace semantics { +class OpenACCRoutineInfo; class SemanticsContext; class Symbol; } // namespace semantics @@ -55,9 +63,6 @@ namespace pft { struct Evaluation; } // namespace pft -using AccRoutineInfoMappingList = - llvm::SmallVector>; - static constexpr llvm::StringRef declarePostAllocSuffix = "_acc_declare_update_desc_post_alloc"; static constexpr llvm::StringRef declarePreDeallocSuffix = @@ -71,19 +76,12 @@ mlir::Value genOpenACCConstruct(AbstractConverter &, Fortran::semantics::SemanticsContext &, pft::Evaluation &, const parser::OpenACCConstruct &); -void genOpenACCDeclarativeConstruct(AbstractConverter &, - Fortran::semantics::SemanticsContext &, - StatementContext &, - const parser::OpenACCDeclarativeConstruct &, - AccRoutineInfoMappingList &); -void genOpenACCRoutineConstruct(AbstractConverter &, - Fortran::semantics::SemanticsContext &, - mlir::ModuleOp, - const parser::OpenACCRoutineConstruct &, - AccRoutineInfoMappingList &); - -void finalizeOpenACCRoutineAttachment(mlir::ModuleOp, - AccRoutineInfoMappingList &); +void genOpenACCDeclarativeConstruct( + AbstractConverter &, Fortran::semantics::SemanticsContext &, + StatementContext &, const parser::OpenACCDeclarativeConstruct &); +void genOpenACCRoutineConstruct( + AbstractConverter &, mlir::ModuleOp, mlir::func::FuncOp, + const std::vector &); /// Get a acc.private.recipe op for the given type or create it if it does not /// exist yet. diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index 715811885c219..f122b599bde84 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace llvm { @@ -127,6 +128,9 @@ class WithBindName { // Device type specific OpenACC routine information class OpenACCRoutineDeviceTypeInfo { public: + explicit OpenACCRoutineDeviceTypeInfo( + Fortran::common::OpenACCDeviceType dType) + : deviceType_{dType} {} bool isSeq() const { return isSeq_; } void set_isSeq(bool value = true) { isSeq_ = value; } bool isVector() const { return isVector_; } @@ -137,22 +141,30 @@ class OpenACCRoutineDeviceTypeInfo { void set_isGang(bool value = true) { isGang_ = value; } unsigned gangDim() const { return gangDim_; } void set_gangDim(unsigned value) { gangDim_ = value; } - const std::string *bindName() const { - return bindName_ ? &*bindName_ : nullptr; + const std::variant *bindName() const { + return bindName_.has_value() ? &*bindName_ : nullptr; } - void set_bindName(std::string &&name) { bindName_ = std::move(name); } - void set_dType(Fortran::common::OpenACCDeviceType dType) { - deviceType_ = dType; + const std::optional> & + bindNameOpt() const { + return bindName_; } + void set_bindName(std::string &&name) { bindName_.emplace(std::move(name)); } + void set_bindName(SymbolRef symbol) { bindName_.emplace(symbol); } + Fortran::common::OpenACCDeviceType dType() const { return deviceType_; } + friend llvm::raw_ostream &operator<<( + llvm::raw_ostream &, const OpenACCRoutineDeviceTypeInfo &); + private: bool isSeq_{false}; bool isVector_{false}; bool isWorker_{false}; bool isGang_{false}; unsigned gangDim_{0}; - std::optional bindName_; + // bind("name") -> std::string + // bind(sym) -> SymbolRef (requires namemangling in lowering) + std::optional> bindName_; Fortran::common::OpenACCDeviceType deviceType_{ Fortran::common::OpenACCDeviceType::None}; }; @@ -162,15 +174,29 @@ class OpenACCRoutineDeviceTypeInfo { // in as objects in the OpenACCRoutineDeviceTypeInfo list. class OpenACCRoutineInfo : public OpenACCRoutineDeviceTypeInfo { public: + OpenACCRoutineInfo() + : OpenACCRoutineDeviceTypeInfo(Fortran::common::OpenACCDeviceType::None) { + } bool isNohost() const { return isNohost_; } void set_isNohost(bool value = true) { isNohost_ = value; } - std::list &deviceTypeInfos() { + const std::list &deviceTypeInfos() const { return deviceTypeInfos_; } - void add_deviceTypeInfo(OpenACCRoutineDeviceTypeInfo &info) { - deviceTypeInfos_.push_back(info); + + OpenACCRoutineDeviceTypeInfo &add_deviceTypeInfo( + Fortran::common::OpenACCDeviceType type) { + return add_deviceTypeInfo(OpenACCRoutineDeviceTypeInfo(type)); + } + + OpenACCRoutineDeviceTypeInfo &add_deviceTypeInfo( + OpenACCRoutineDeviceTypeInfo &&info) { + deviceTypeInfos_.push_back(std::move(info)); + return deviceTypeInfos_.back(); } + friend llvm::raw_ostream &operator<<( + llvm::raw_ostream &, const OpenACCRoutineInfo &); + private: std::list deviceTypeInfos_; bool isNohost_{false}; diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index b4d1197822a43..81127ab55a937 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -397,37 +397,39 @@ class FirConverter : public Fortran::lower::AbstractConverter { // they are available before lowering any function that may use them. bool hasMainProgram = false; const Fortran::semantics::Symbol *globalOmpRequiresSymbol = nullptr; - for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) { - Fortran::common::visit( - Fortran::common::visitors{ - [&](Fortran::lower::pft::FunctionLikeUnit &f) { - if (f.isMainProgram()) - hasMainProgram = true; - declareFunction(f); - if (!globalOmpRequiresSymbol) - globalOmpRequiresSymbol = f.getScope().symbol(); - }, - [&](Fortran::lower::pft::ModuleLikeUnit &m) { - lowerModuleDeclScope(m); - for (Fortran::lower::pft::ContainedUnit &unit : - m.containedUnitList) - if (auto *f = - std::get_if( - &unit)) - declareFunction(*f); - }, - [&](Fortran::lower::pft::BlockDataUnit &b) { - if (!globalOmpRequiresSymbol) - globalOmpRequiresSymbol = b.symTab.symbol(); - }, - [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, - [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {}, - }, - u); - } + createBuilderOutsideOfFuncOpAndDo([&]() { + for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) { + Fortran::common::visit( + Fortran::common::visitors{ + [&](Fortran::lower::pft::FunctionLikeUnit &f) { + if (f.isMainProgram()) + hasMainProgram = true; + declareFunction(f); + if (!globalOmpRequiresSymbol) + globalOmpRequiresSymbol = f.getScope().symbol(); + }, + [&](Fortran::lower::pft::ModuleLikeUnit &m) { + lowerModuleDeclScope(m); + for (Fortran::lower::pft::ContainedUnit &unit : + m.containedUnitList) + if (auto *f = + std::get_if( + &unit)) + declareFunction(*f); + }, + [&](Fortran::lower::pft::BlockDataUnit &b) { + if (!globalOmpRequiresSymbol) + globalOmpRequiresSymbol = b.symTab.symbol(); + }, + [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, + [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {}, + }, + u); + } + }); // Create definitions of intrinsic module constants. - createGlobalOutsideOfFunctionLowering( + createBuilderOutsideOfFuncOpAndDo( [&]() { createIntrinsicModuleDefinitions(pft); }); // Primary translation pass. @@ -438,14 +440,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { [&](Fortran::lower::pft::ModuleLikeUnit &m) { lowerMod(m); }, [&](Fortran::lower::pft::BlockDataUnit &b) {}, [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, - [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) { - builder = new fir::FirOpBuilder( - bridge.getModule(), bridge.getKindMap(), &mlirSymbolTable); - Fortran::lower::genOpenACCRoutineConstruct( - *this, bridge.getSemanticsContext(), bridge.getModule(), - d.routine, accRoutineInfos); - builder = nullptr; - }, + [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {}, }, u); } @@ -453,24 +448,24 @@ class FirConverter : public Fortran::lower::AbstractConverter { // Once all the code has been translated, create global runtime type info // data structures for the derived types that have been processed, as well // as fir.type_info operations for the dispatch tables. - createGlobalOutsideOfFunctionLowering( + createBuilderOutsideOfFuncOpAndDo( [&]() { typeInfoConverter.createTypeInfo(*this); }); // Generate the `main` entry point if necessary if (hasMainProgram) - createGlobalOutsideOfFunctionLowering([&]() { + createBuilderOutsideOfFuncOpAndDo([&]() { fir::runtime::genMain(*builder, toLocation(), bridge.getEnvironmentDefaults(), getFoldingContext().languageFeatures().IsEnabled( Fortran::common::LanguageFeature::CUDA)); }); - finalizeOpenACCLowering(); finalizeOpenMPLowering(globalOmpRequiresSymbol); } /// Declare a function. void declareFunction(Fortran::lower::pft::FunctionLikeUnit &funit) { + CHECK(builder && "declareFunction called with uninitialized builder"); setCurrentPosition(funit.getStartingSourceLoc()); for (int entryIndex = 0, last = funit.entryPointList.size(); entryIndex < last; ++entryIndex) { @@ -1035,7 +1030,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { return bridge.getSemanticsContext().FindScope(currentPosition); } - fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; } + fir::FirOpBuilder &getFirOpBuilder() override final { + CHECK(builder && "builder is not set before calling getFirOpBuilder"); + return *builder; + } mlir::ModuleOp getModuleOp() override final { return bridge.getModule(); } @@ -3018,8 +3016,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { void genFIR(const Fortran::parser::OpenACCDeclarativeConstruct &accDecl) { genOpenACCDeclarativeConstruct(*this, bridge.getSemanticsContext(), - bridge.openAccCtx(), accDecl, - accRoutineInfos); + bridge.openAccCtx(), accDecl); for (Fortran::lower::pft::Evaluation &e : getEval().getNestedEvaluations()) genFIR(e); } @@ -5612,6 +5609,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { LLVM_DEBUG(llvm::dbgs() << "\n[bridge - startNewFunction]"; if (auto *sym = scope.symbol()) llvm::dbgs() << " " << *sym; llvm::dbgs() << "\n"); + // Setting the builder is not necessary here, because callee + // always looks up the FuncOp from the module. If there was a function that + // was not declared yet, this call to callee will cause an assertion + // failure. Fortran::lower::CalleeInterface callee(funit, *this); mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments(); builder = @@ -5881,8 +5882,9 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Helper to generate GlobalOps when the builder is not positioned in any /// region block. This is required because the FirOpBuilder assumes it is /// always positioned inside a region block when creating globals, the easiest - /// way comply is to create a dummy function and to throw it afterwards. - void createGlobalOutsideOfFunctionLowering( + /// way to comply is to create a dummy function and to throw it away + /// afterwards. + void createBuilderOutsideOfFuncOpAndDo( const std::function &createGlobals) { // FIXME: get rid of the bogus function context and instantiate the // globals directly into the module. @@ -5894,6 +5896,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { mlir::FunctionType::get(context, std::nullopt, std::nullopt), symbolTable); func.addEntryBlock(); + CHECK(!builder && "Expected builder to be uninitialized"); builder = new fir::FirOpBuilder(func, bridge.getKindMap(), symbolTable); assert(builder && "FirOpBuilder did not instantiate"); builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions()); @@ -5909,7 +5912,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Instantiate the data from a BLOCK DATA unit. void lowerBlockData(Fortran::lower::pft::BlockDataUnit &bdunit) { - createGlobalOutsideOfFunctionLowering([&]() { + createBuilderOutsideOfFuncOpAndDo([&]() { Fortran::lower::AggregateStoreMap fakeMap; for (const auto &[_, sym] : bdunit.symTab) { if (sym->has()) { @@ -5923,7 +5926,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// Create fir::Global for all the common blocks that appear in the program. void lowerCommonBlocks(const Fortran::semantics::CommonBlockList &commonBlocks) { - createGlobalOutsideOfFunctionLowering( + createBuilderOutsideOfFuncOpAndDo( [&]() { Fortran::lower::defineCommonBlocks(*this, commonBlocks); }); } @@ -5993,36 +5996,34 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// declarative construct. void lowerModuleDeclScope(Fortran::lower::pft::ModuleLikeUnit &mod) { setCurrentPosition(mod.getStartingSourceLoc()); - createGlobalOutsideOfFunctionLowering([&]() { - auto &scopeVariableListMap = - Fortran::lower::pft::getScopeVariableListMap(mod); - for (const auto &var : Fortran::lower::pft::getScopeVariableList( - mod.getScope(), scopeVariableListMap)) { - - // Only define the variables owned by this module. - const Fortran::semantics::Scope *owningScope = var.getOwningScope(); - if (owningScope && mod.getScope() != *owningScope) - continue; + auto &scopeVariableListMap = + Fortran::lower::pft::getScopeVariableListMap(mod); + for (const auto &var : Fortran::lower::pft::getScopeVariableList( + mod.getScope(), scopeVariableListMap)) { - // Very special case: The value of numeric_storage_size depends on - // compilation options and therefore its value is not yet known when - // building the builtins runtime. Instead, the parameter is folding a - // __numeric_storage_size() expression which is loaded into the user - // program. For the iso_fortran_env object file, omit the symbol as it - // is never used. - if (var.hasSymbol()) { - const Fortran::semantics::Symbol &sym = var.getSymbol(); - const Fortran::semantics::Scope &owner = sym.owner(); - if (sym.name() == "numeric_storage_size" && owner.IsModule() && - DEREF(owner.symbol()).name() == "iso_fortran_env") - continue; - } + // Only define the variables owned by this module. + const Fortran::semantics::Scope *owningScope = var.getOwningScope(); + if (owningScope && mod.getScope() != *owningScope) + continue; - Fortran::lower::defineModuleVariable(*this, var); + // Very special case: The value of numeric_storage_size depends on + // compilation options and therefore its value is not yet known when + // building the builtins runtime. Instead, the parameter is folding a + // __numeric_storage_size() expression which is loaded into the user + // program. For the iso_fortran_env object file, omit the symbol as it + // is never used. + if (var.hasSymbol()) { + const Fortran::semantics::Symbol &sym = var.getSymbol(); + const Fortran::semantics::Scope &owner = sym.owner(); + if (sym.name() == "numeric_storage_size" && owner.IsModule() && + DEREF(owner.symbol()).name() == "iso_fortran_env") + continue; } + + Fortran::lower::defineModuleVariable(*this, var); + } for (auto &eval : mod.evaluationList) genFIR(eval); - }); } /// Lower functions contained in a module. @@ -6323,13 +6324,6 @@ class FirConverter : public Fortran::lower::AbstractConverter { expr.u); } - /// Performing OpenACC lowering action that were deferred to the end of - /// lowering. - void finalizeOpenACCLowering() { - Fortran::lower::finalizeOpenACCRoutineAttachment(getModuleOp(), - accRoutineInfos); - } - /// Performing OpenMP lowering actions that were deferred to the end of /// lowering. void finalizeOpenMPLowering( @@ -6421,9 +6415,6 @@ class FirConverter : public Fortran::lower::AbstractConverter { /// A counter for uniquing names in `literalNamesMap`. std::uint64_t uniqueLitId = 0; - /// Deferred OpenACC routine attachment. - Fortran::lower::AccRoutineInfoMappingList accRoutineInfos; - /// Whether an OpenMP target region or declare target function/subroutine /// intended for device offloading has been detected bool ompDeviceCodeFound = false; diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index 226ba1e52c968..8affa1e1965e8 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -10,6 +10,7 @@ #include "flang/Evaluate/fold.h" #include "flang/Lower/Bridge.h" #include "flang/Lower/Mangler.h" +#include "flang/Lower/OpenACC.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/StatementContext.h" #include "flang/Lower/Support/Utils.h" @@ -715,6 +716,17 @@ void Fortran::lower::CallInterface::declare() { func.setArgAttrs(placeHolder.index(), placeHolder.value().attributes); setCUDAAttributes(func, side().getProcedureSymbol(), characteristic); + + if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol()) { + if (const auto &info{ + sym->GetUltimate() + .detailsIf()}) { + if (!info->openACCRoutineInfos().empty()) { + genOpenACCRoutineConstruct(converter, module, func, + info->openACCRoutineInfos()); + } + } + } } } } diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 3dd35ed9ae481..1a031dce7a487 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -33,11 +33,13 @@ #include "flang/Semantics/scope.h" #include "flang/Semantics/tools.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" +#include "mlir/IR/MLIRContext.h" #include "mlir/Support/LLVM.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenACC/ACC.h.inc" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #define DEBUG_TYPE "flang-lower-openacc" @@ -4139,125 +4141,27 @@ static void attachRoutineInfo(mlir::func::FuncOp func, mlir::acc::RoutineInfoAttr::get(func.getContext(), routines)); } -void Fortran::lower::genOpenACCRoutineConstruct( - Fortran::lower::AbstractConverter &converter, - Fortran::semantics::SemanticsContext &semanticsContext, mlir::ModuleOp mod, - const Fortran::parser::OpenACCRoutineConstruct &routineConstruct, - Fortran::lower::AccRoutineInfoMappingList &accRoutineInfos) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - mlir::Location loc = converter.genLocation(routineConstruct.source); - std::optional name = - std::get>(routineConstruct.t); - const auto &clauses = - std::get(routineConstruct.t); - mlir::func::FuncOp funcOp; - std::string funcName; - if (name) { - funcName = converter.mangleName(*name->symbol); - funcOp = - builder.getNamedFunction(mod, builder.getMLIRSymbolTable(), funcName); +static mlir::ArrayAttr +getArrayAttrOrNull(fir::FirOpBuilder &builder, + llvm::SmallVector &attributes) { + if (attributes.empty()) { + return nullptr; } else { - Fortran::semantics::Scope &scope = - semanticsContext.FindScope(routineConstruct.source); - const Fortran::semantics::Scope &progUnit{GetProgramUnitContaining(scope)}; - const auto *subpDetails{ - progUnit.symbol() - ? progUnit.symbol() - ->detailsIf() - : nullptr}; - if (subpDetails && subpDetails->isInterface()) { - funcName = converter.mangleName(*progUnit.symbol()); - funcOp = - builder.getNamedFunction(mod, builder.getMLIRSymbolTable(), funcName); - } else { - funcOp = builder.getFunction(); - funcName = funcOp.getName(); - } - } - bool hasNohost = false; - - llvm::SmallVector seqDeviceTypes, vectorDeviceTypes, - workerDeviceTypes, bindNameDeviceTypes, bindNames, gangDeviceTypes, - gangDimDeviceTypes, gangDimValues; - - // device_type attribute is set to `none` until a device_type clause is - // encountered. - llvm::SmallVector crtDeviceTypes; - crtDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get( - builder.getContext(), mlir::acc::DeviceType::None)); - - for (const Fortran::parser::AccClause &clause : clauses.v) { - if (std::get_if(&clause.u)) { - for (auto crtDeviceTypeAttr : crtDeviceTypes) - seqDeviceTypes.push_back(crtDeviceTypeAttr); - } else if (const auto *gangClause = - std::get_if(&clause.u)) { - if (gangClause->v) { - const Fortran::parser::AccGangArgList &x = *gangClause->v; - for (const Fortran::parser::AccGangArg &gangArg : x.v) { - if (const auto *dim = - std::get_if(&gangArg.u)) { - const std::optional dimValue = Fortran::evaluate::ToInt64( - *Fortran::semantics::GetExpr(dim->v)); - if (!dimValue) - mlir::emitError(loc, - "dim value must be a constant positive integer"); - mlir::Attribute gangDimAttr = - builder.getIntegerAttr(builder.getI64Type(), *dimValue); - for (auto crtDeviceTypeAttr : crtDeviceTypes) { - gangDimValues.push_back(gangDimAttr); - gangDimDeviceTypes.push_back(crtDeviceTypeAttr); - } - } - } - } else { - for (auto crtDeviceTypeAttr : crtDeviceTypes) - gangDeviceTypes.push_back(crtDeviceTypeAttr); - } - } else if (std::get_if(&clause.u)) { - for (auto crtDeviceTypeAttr : crtDeviceTypes) - vectorDeviceTypes.push_back(crtDeviceTypeAttr); - } else if (std::get_if(&clause.u)) { - for (auto crtDeviceTypeAttr : crtDeviceTypes) - workerDeviceTypes.push_back(crtDeviceTypeAttr); - } else if (std::get_if(&clause.u)) { - hasNohost = true; - } else if (const auto *bindClause = - std::get_if(&clause.u)) { - if (const auto *name = - std::get_if(&bindClause->v.u)) { - mlir::Attribute bindNameAttr = - builder.getStringAttr(converter.mangleName(*name->symbol)); - for (auto crtDeviceTypeAttr : crtDeviceTypes) { - bindNames.push_back(bindNameAttr); - bindNameDeviceTypes.push_back(crtDeviceTypeAttr); - } - } else if (const auto charExpr = - std::get_if( - &bindClause->v.u)) { - const std::optional name = - Fortran::semantics::GetConstExpr(semanticsContext, - *charExpr); - if (!name) - mlir::emitError(loc, "Could not retrieve the bind name"); - - mlir::Attribute bindNameAttr = builder.getStringAttr(*name); - for (auto crtDeviceTypeAttr : crtDeviceTypes) { - bindNames.push_back(bindNameAttr); - bindNameDeviceTypes.push_back(crtDeviceTypeAttr); - } - } - } else if (const auto *deviceTypeClause = - std::get_if( - &clause.u)) { - crtDeviceTypes.clear(); - gatherDeviceTypeAttrs(builder, deviceTypeClause, crtDeviceTypes); - } + return builder.getArrayAttr(attributes); } +} - mlir::OpBuilder modBuilder(mod.getBodyRegion()); - std::stringstream routineOpName; - routineOpName << accRoutinePrefix.str() << routineCounter++; +void createOpenACCRoutineConstruct( + Fortran::lower::AbstractConverter &converter, mlir::Location loc, + mlir::ModuleOp mod, mlir::func::FuncOp funcOp, std::string funcName, + bool hasNohost, llvm::SmallVector &bindNames, + llvm::SmallVector &bindNameDeviceTypes, + llvm::SmallVector &gangDeviceTypes, + llvm::SmallVector &gangDimValues, + llvm::SmallVector &gangDimDeviceTypes, + llvm::SmallVector &seqDeviceTypes, + llvm::SmallVector &workerDeviceTypes, + llvm::SmallVector &vectorDeviceTypes) { for (auto routineOp : mod.getOps()) { if (routineOp.getFuncName().str().compare(funcName) == 0) { @@ -4272,47 +4176,117 @@ void Fortran::lower::genOpenACCRoutineConstruct( mlir::emitError(loc, "Routine already specified with different clauses"); } } - + std::stringstream routineOpName; + routineOpName << accRoutinePrefix.str() << routineCounter++; + std::string routineOpStr = routineOpName.str(); + mlir::OpBuilder modBuilder(mod.getBodyRegion()); + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); modBuilder.create( - loc, routineOpName.str(), funcName, - bindNames.empty() ? nullptr : builder.getArrayAttr(bindNames), - bindNameDeviceTypes.empty() ? nullptr - : builder.getArrayAttr(bindNameDeviceTypes), - workerDeviceTypes.empty() ? nullptr - : builder.getArrayAttr(workerDeviceTypes), - vectorDeviceTypes.empty() ? nullptr - : builder.getArrayAttr(vectorDeviceTypes), - seqDeviceTypes.empty() ? nullptr : builder.getArrayAttr(seqDeviceTypes), - hasNohost, /*implicit=*/false, - gangDeviceTypes.empty() ? nullptr : builder.getArrayAttr(gangDeviceTypes), - gangDimValues.empty() ? nullptr : builder.getArrayAttr(gangDimValues), - gangDimDeviceTypes.empty() ? nullptr - : builder.getArrayAttr(gangDimDeviceTypes)); - - if (funcOp) - attachRoutineInfo(funcOp, builder.getSymbolRefAttr(routineOpName.str())); - else - // FuncOp is not lowered yet. Keep the information so the routine info - // can be attached later to the funcOp. - accRoutineInfos.push_back(std::make_pair( - funcName, builder.getSymbolRefAttr(routineOpName.str()))); + loc, routineOpStr, funcName, getArrayAttrOrNull(builder, bindNames), + getArrayAttrOrNull(builder, bindNameDeviceTypes), + getArrayAttrOrNull(builder, workerDeviceTypes), + getArrayAttrOrNull(builder, vectorDeviceTypes), + getArrayAttrOrNull(builder, seqDeviceTypes), hasNohost, + /*implicit=*/false, getArrayAttrOrNull(builder, gangDeviceTypes), + getArrayAttrOrNull(builder, gangDimValues), + getArrayAttrOrNull(builder, gangDimDeviceTypes)); + + attachRoutineInfo(funcOp, builder.getSymbolRefAttr(routineOpStr)); } -void Fortran::lower::finalizeOpenACCRoutineAttachment( - mlir::ModuleOp mod, - Fortran::lower::AccRoutineInfoMappingList &accRoutineInfos) { - for (auto &mapping : accRoutineInfos) { - mlir::func::FuncOp funcOp = - mod.lookupSymbol(mapping.first); - if (!funcOp) - mlir::emitWarning(mod.getLoc(), - llvm::Twine("function '") + llvm::Twine(mapping.first) + - llvm::Twine("' in acc routine directive is not " - "found in this translation unit.")); - else - attachRoutineInfo(funcOp, mapping.second); +static void interpretRoutineDeviceInfo( + Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::OpenACCRoutineDeviceTypeInfo &dinfo, + llvm::SmallVector &seqDeviceTypes, + llvm::SmallVector &vectorDeviceTypes, + llvm::SmallVector &workerDeviceTypes, + llvm::SmallVector &bindNameDeviceTypes, + llvm::SmallVector &bindNames, + llvm::SmallVector &gangDeviceTypes, + llvm::SmallVector &gangDimValues, + llvm::SmallVector &gangDimDeviceTypes) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + auto getDeviceTypeAttr = [&]() -> mlir::Attribute { + auto context = builder.getContext(); + auto value = getDeviceType(dinfo.dType()); + return mlir::acc::DeviceTypeAttr::get(context, value); + }; + if (dinfo.isSeq()) { + seqDeviceTypes.push_back(getDeviceTypeAttr()); + } + if (dinfo.isVector()) { + vectorDeviceTypes.push_back(getDeviceTypeAttr()); + } + if (dinfo.isWorker()) { + workerDeviceTypes.push_back(getDeviceTypeAttr()); + } + if (dinfo.isGang()) { + unsigned gangDim = dinfo.gangDim(); + auto deviceType = getDeviceTypeAttr(); + if (!gangDim) { + gangDeviceTypes.push_back(deviceType); + } else { + gangDimValues.push_back( + builder.getIntegerAttr(builder.getI64Type(), gangDim)); + gangDimDeviceTypes.push_back(deviceType); + } + } + if (dinfo.bindNameOpt().has_value()) { + const auto &bindName = dinfo.bindNameOpt().value(); + mlir::Attribute bindNameAttr; + if (const auto &bindStr{std::get_if(&bindName)}) { + bindNameAttr = builder.getStringAttr(*bindStr); + } else if (const auto &bindSym{ + std::get_if(&bindName)}) { + bindNameAttr = builder.getStringAttr(converter.mangleName(*bindSym)); + } else { + llvm_unreachable("Unsupported bind name type"); + } + bindNames.push_back(bindNameAttr); + bindNameDeviceTypes.push_back(getDeviceTypeAttr()); } - accRoutineInfos.clear(); +} + +void Fortran::lower::genOpenACCRoutineConstruct( + Fortran::lower::AbstractConverter &converter, mlir::ModuleOp mod, + mlir::func::FuncOp funcOp, + const std::vector &routineInfos) { + CHECK(funcOp && "Expected a valid function operation"); + mlir::Location loc{funcOp.getLoc()}; + std::string funcName{funcOp.getName()}; + + // Collect the routine clauses + bool hasNohost{false}; + + llvm::SmallVector seqDeviceTypes, vectorDeviceTypes, + workerDeviceTypes, bindNameDeviceTypes, bindNames, gangDeviceTypes, + gangDimDeviceTypes, gangDimValues; + + for (const Fortran::semantics::OpenACCRoutineInfo &info : routineInfos) { + // Device Independent Attributes + if (info.isNohost()) { + hasNohost = true; + } + // Note: Device Independent Attributes are set to the + // none device type in `info`. + interpretRoutineDeviceInfo(converter, info, seqDeviceTypes, + vectorDeviceTypes, workerDeviceTypes, + bindNameDeviceTypes, bindNames, gangDeviceTypes, + gangDimValues, gangDimDeviceTypes); + + // Device Dependent Attributes + for (const Fortran::semantics::OpenACCRoutineDeviceTypeInfo &dinfo : + info.deviceTypeInfos()) { + interpretRoutineDeviceInfo( + converter, dinfo, seqDeviceTypes, vectorDeviceTypes, + workerDeviceTypes, bindNameDeviceTypes, bindNames, gangDeviceTypes, + gangDimValues, gangDimDeviceTypes); + } + } + createOpenACCRoutineConstruct( + converter, loc, mod, funcOp, funcName, hasNohost, bindNames, + bindNameDeviceTypes, gangDeviceTypes, gangDimValues, gangDimDeviceTypes, + seqDeviceTypes, workerDeviceTypes, vectorDeviceTypes); } static void @@ -4428,8 +4402,7 @@ void Fortran::lower::genOpenACCDeclarativeConstruct( Fortran::lower::AbstractConverter &converter, Fortran::semantics::SemanticsContext &semanticsContext, Fortran::lower::StatementContext &openAccCtx, - const Fortran::parser::OpenACCDeclarativeConstruct &accDeclConstruct, - Fortran::lower::AccRoutineInfoMappingList &accRoutineInfos) { + const Fortran::parser::OpenACCDeclarativeConstruct &accDeclConstruct) { Fortran::common::visit( common::visitors{ @@ -4438,14 +4411,7 @@ void Fortran::lower::genOpenACCDeclarativeConstruct( genACC(converter, semanticsContext, openAccCtx, standaloneDeclarativeConstruct); }, - [&](const Fortran::parser::OpenACCRoutineConstruct - &routineConstruct) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - mlir::ModuleOp mod = builder.getModule(); - Fortran::lower::genOpenACCRoutineConstruct( - converter, semanticsContext, mod, routineConstruct, - accRoutineInfos); - }, + [&](const Fortran::parser::OpenACCRoutineConstruct &x) {}, }, accDeclConstruct.u); } diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index ee356e56e4458..60b97b401affb 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace Fortran::semantics { @@ -638,8 +639,14 @@ static void PutOpenACCDeviceTypeRoutineInfo( if (info.isWorker()) { os << " worker"; } - if (info.bindName()) { - os << " bind(" << *info.bindName() << ")"; + if (const std::variant *bindName{info.bindName()}) { + os << " bind("; + if (std::holds_alternative(*bindName)) { + os << "\"" << std::get(*bindName) << "\""; + } else { + os << std::get(*bindName)->name(); + } + os << ")"; } } @@ -1387,6 +1394,9 @@ Scope *ModFileReader::Read(SourceName name, std::optional isIntrinsic, parser::Options options; options.isModuleFile = true; options.features.Enable(common::LanguageFeature::BackslashEscapes); + if (context_.languageFeatures().IsEnabled(common::LanguageFeature::OpenACC)) { + options.features.Enable(common::LanguageFeature::OpenACC); + } options.features.Enable(common::LanguageFeature::OpenMP); options.features.Enable(common::LanguageFeature::CUDA); if (!isIntrinsic.value_or(false) && !notAModule) { diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index d75b4ea13d35f..66116637dc812 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -1034,88 +1034,78 @@ void AccAttributeVisitor::AddRoutineInfoToSymbol( Symbol &symbol, const parser::OpenACCRoutineConstruct &x) { if (symbol.has()) { Fortran::semantics::OpenACCRoutineInfo info; - const auto &clauses = std::get(x.t); + std::vector currentDevices; + currentDevices.push_back(&info); + const auto &clauses{std::get(x.t)}; for (const Fortran::parser::AccClause &clause : clauses.v) { - if (std::get_if(&clause.u)) { - if (info.deviceTypeInfos().empty()) { - info.set_isSeq(); - } else { - info.deviceTypeInfos().back().set_isSeq(); + if (const auto *dTypeClause{ + std::get_if(&clause.u)}) { + currentDevices.clear(); + for (const auto &deviceTypeExpr : dTypeClause->v.v) { + currentDevices.push_back(&info.add_deviceTypeInfo(deviceTypeExpr.v)); } - } else if (const auto *gangClause = - std::get_if(&clause.u)) { - if (info.deviceTypeInfos().empty()) { - info.set_isGang(); - } else { - info.deviceTypeInfos().back().set_isGang(); + } else if (std::get_if(&clause.u)) { + info.set_isNohost(); + } else if (std::get_if(&clause.u)) { + for (auto &device : currentDevices) { + device->set_isSeq(); + } + } else if (std::get_if(&clause.u)) { + for (auto &device : currentDevices) { + device->set_isVector(); + } + } else if (std::get_if(&clause.u)) { + for (auto &device : currentDevices) { + device->set_isWorker(); + } + } else if (const auto *gangClause{ + std::get_if( + &clause.u)}) { + for (auto &device : currentDevices) { + device->set_isGang(); } if (gangClause->v) { const Fortran::parser::AccGangArgList &x = *gangClause->v; + int numArgs{0}; for (const Fortran::parser::AccGangArg &gangArg : x.v) { - if (const auto *dim = - std::get_if(&gangArg.u)) { + CHECK(numArgs <= 1 && "expecting 0 or 1 gang dim args"); + if (const auto *dim{std::get_if( + &gangArg.u)}) { if (const auto v{EvaluateInt64(context_, dim->v)}) { - if (info.deviceTypeInfos().empty()) { - info.set_gangDim(*v); - } else { - info.deviceTypeInfos().back().set_gangDim(*v); + for (auto &device : currentDevices) { + device->set_gangDim(*v); } } } + numArgs++; } } - } else if (std::get_if(&clause.u)) { - if (info.deviceTypeInfos().empty()) { - info.set_isVector(); - } else { - info.deviceTypeInfos().back().set_isVector(); - } - } else if (std::get_if(&clause.u)) { - if (info.deviceTypeInfos().empty()) { - info.set_isWorker(); - } else { - info.deviceTypeInfos().back().set_isWorker(); - } - } else if (std::get_if(&clause.u)) { - info.set_isNohost(); - } else if (const auto *bindClause = - std::get_if(&clause.u)) { - if (const auto *name = - std::get_if(&bindClause->v.u)) { - if (Symbol *sym = ResolveFctName(*name)) { - if (info.deviceTypeInfos().empty()) { - info.set_bindName(sym->name().ToString()); - } else { - info.deviceTypeInfos().back().set_bindName( - sym->name().ToString()); + } else if (const auto *bindClause{ + std::get_if( + &clause.u)}) { + if (const auto *name{ + std::get_if(&bindClause->v.u)}) { + if (Symbol * sym{ResolveFctName(*name)}) { + Symbol &ultimate{sym->GetUltimate()}; + for (auto &device : currentDevices) { + device->set_bindName(SymbolRef{ultimate}); } } else { context_.Say((*name).source, "No function or subroutine declared for '%s'"_err_en_US, (*name).source); } - } else if (const auto charExpr = + } else if (const auto charExpr{ std::get_if( - &bindClause->v.u)) { - auto *charConst = + &bindClause->v.u)}) { + auto *charConst{ Fortran::parser::Unwrap( - *charExpr); + *charExpr)}; std::string str{std::get(charConst->t)}; - std::stringstream bindName; - bindName << "\"" << str << "\""; - if (info.deviceTypeInfos().empty()) { - info.set_bindName(bindName.str()); - } else { - info.deviceTypeInfos().back().set_bindName(bindName.str()); + for (auto &device : currentDevices) { + device->set_bindName(std::string(str)); } } - } else if (const auto *dType = - std::get_if( - &clause.u)) { - const parser::AccDeviceTypeExprList &deviceTypeExprList = dType->v; - OpenACCRoutineDeviceTypeInfo dtypeInfo; - dtypeInfo.set_dType(deviceTypeExprList.v.front().v); - info.add_deviceTypeInfo(dtypeInfo); } } symbol.get().add_openACCRoutineInfo(info); diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp index 32eb6c2c5a188..2118970a7bf25 100644 --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -144,6 +144,52 @@ llvm::raw_ostream &operator<<( os << ' ' << x; } } + if (!x.openACCRoutineInfos_.empty()) { + os << " openACCRoutineInfos:"; + for (const auto &x : x.openACCRoutineInfos_) { + os << x; + } + } + return os; +} + +llvm::raw_ostream &operator<<( + llvm::raw_ostream &os, const OpenACCRoutineDeviceTypeInfo &x) { + if (x.dType() != common::OpenACCDeviceType::None) { + os << " deviceType(" << common::EnumToString(x.dType()) << ')'; + } + if (x.isSeq()) { + os << " seq"; + } + if (x.isVector()) { + os << " vector"; + } + if (x.isWorker()) { + os << " worker"; + } + if (x.isGang()) { + os << " gang(" << x.gangDim() << ')'; + } + if (const auto *bindName{x.bindName()}) { + if (const auto &symbol{std::get_if(bindName)}) { + os << " bindName(\"" << *symbol << "\")"; + } else { + const SymbolRef s{std::get(*bindName)}; + os << " bindName(" << s->name() << ")"; + } + } + return os; +} + +llvm::raw_ostream &operator<<( + llvm::raw_ostream &os, const OpenACCRoutineInfo &x) { + if (x.isNohost()) { + os << " nohost"; + } + os << static_cast(x); + for (const auto &d : x.deviceTypeInfos_) { + os << d; + } return os; } diff --git a/flang/test/Lower/OpenACC/acc-module-definition.f90 b/flang/test/Lower/OpenACC/acc-module-definition.f90 new file mode 100644 index 0000000000000..36e41fc631c77 --- /dev/null +++ b/flang/test/Lower/OpenACC/acc-module-definition.f90 @@ -0,0 +1,17 @@ +! RUN: rm -fr %t && mkdir -p %t && cd %t +! RUN: bbc -fopenacc -emit-fir %s +! RUN: cat mod1.mod | FileCheck %s + +!CHECK-LABEL: module mod1 +module mod1 + contains + !CHECK subroutine callee(aa) + subroutine callee(aa) + !CHECK: !$acc routine seq + !$acc routine seq + integer :: aa + aa = 1 + end subroutine + !CHECK: end + !CHECK: end +end module \ No newline at end of file diff --git a/flang/test/Lower/OpenACC/acc-routine-named.f90 b/flang/test/Lower/OpenACC/acc-routine-named.f90 index 2cf6bf8b2bc06..de9784a1146cc 100644 --- a/flang/test/Lower/OpenACC/acc-routine-named.f90 +++ b/flang/test/Lower/OpenACC/acc-routine-named.f90 @@ -4,8 +4,8 @@ module acc_routines -! CHECK: acc.routine @acc_routine_1 func(@_QMacc_routinesPacc2) -! CHECK: acc.routine @acc_routine_0 func(@_QMacc_routinesPacc1) seq +! CHECK: acc.routine @[[r0:.*]] func(@_QMacc_routinesPacc2) +! CHECK: acc.routine @[[r1:.*]] func(@_QMacc_routinesPacc1) seq !$acc routine(acc1) seq @@ -14,12 +14,14 @@ module acc_routines subroutine acc1() end subroutine -! CHECK-LABEL: func.func @_QMacc_routinesPacc1() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_0]>} +! CHECK-LABEL: func.func @_QMacc_routinesPacc1() +! CHECK-SAME:attributes {acc.routine_info = #acc.routine_info<[@[[r1]]]>} subroutine acc2() !$acc routine(acc2) end subroutine -! CHECK-LABEL: func.func @_QMacc_routinesPacc2() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_1]>} +! CHECK-LABEL: func.func @_QMacc_routinesPacc2() +! CHECK-SAME:attributes {acc.routine_info = #acc.routine_info<[@[[r0]]]>} end module diff --git a/flang/test/Lower/OpenACC/acc-routine-use-module.f90 b/flang/test/Lower/OpenACC/acc-routine-use-module.f90 new file mode 100644 index 0000000000000..059324230a746 --- /dev/null +++ b/flang/test/Lower/OpenACC/acc-routine-use-module.f90 @@ -0,0 +1,23 @@ +! RUN: rm -fr %t && mkdir -p %t && cd %t +! RUN: bbc -fopenacc -emit-fir %S/acc-module-definition.f90 +! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s + +! This test module is based off of flang/test/Lower/use_module.f90 +! The first runs ensures the module file is generated. + +module use_mod1 + use mod1 + contains + !CHECK: acc.routine @acc_routine_0 func(@_QMmod1Pcallee) seq + !CHECK: func.func @_QMuse_mod1Pcaller + !CHECK-SAME { + subroutine caller(aa) + integer :: aa + !$acc serial + !CHECK: fir.call @_QMmod1Pcallee + call callee(aa) + !$acc end serial + end subroutine + !CHECK: } + !CHECK: func.func private @_QMmod1Pcallee(!fir.ref) attributes {acc.routine_info = #acc.routine_info<[@acc_routine_0]>} +end module \ No newline at end of file diff --git a/flang/test/Lower/OpenACC/acc-routine.f90 b/flang/test/Lower/OpenACC/acc-routine.f90 index 1170af18bc334..789f3a57e1f79 100644 --- a/flang/test/Lower/OpenACC/acc-routine.f90 +++ b/flang/test/Lower/OpenACC/acc-routine.f90 @@ -2,69 +2,77 @@ ! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s -! CHECK: acc.routine @acc_routine_17 func(@_QPacc_routine19) bind("_QPacc_routine17" [#acc.device_type], "_QPacc_routine17" [#acc.device_type], "_QPacc_routine16" [#acc.device_type]) -! CHECK: acc.routine @acc_routine_16 func(@_QPacc_routine18) bind("_QPacc_routine17" [#acc.device_type], "_QPacc_routine16" [#acc.device_type]) -! CHECK: acc.routine @acc_routine_15 func(@_QPacc_routine17) worker ([#acc.device_type]) vector ([#acc.device_type]) -! CHECK: acc.routine @acc_routine_14 func(@_QPacc_routine16) gang([#acc.device_type]) seq ([#acc.device_type]) -! CHECK: acc.routine @acc_routine_10 func(@_QPacc_routine11) seq -! CHECK: acc.routine @acc_routine_9 func(@_QPacc_routine10) seq -! CHECK: acc.routine @acc_routine_8 func(@_QPacc_routine9) bind("_QPacc_routine9a") -! CHECK: acc.routine @acc_routine_7 func(@_QPacc_routine8) bind("routine8_") -! CHECK: acc.routine @acc_routine_6 func(@_QPacc_routine7) gang(dim: 1 : i64) -! CHECK: acc.routine @acc_routine_5 func(@_QPacc_routine6) nohost -! CHECK: acc.routine @acc_routine_4 func(@_QPacc_routine5) worker -! CHECK: acc.routine @acc_routine_3 func(@_QPacc_routine4) vector -! CHECK: acc.routine @acc_routine_2 func(@_QPacc_routine3) gang -! CHECK: acc.routine @acc_routine_1 func(@_QPacc_routine2) seq -! CHECK: acc.routine @acc_routine_0 func(@_QPacc_routine1) +! CHECK: acc.routine @[[r14:.*]] func(@_QPacc_routine19) bind("_QPacc_routine17" [#acc.device_type], "_QPacc_routine17" [#acc.device_type], "_QPacc_routine16" [#acc.device_type]) +! CHECK: acc.routine @[[r13:.*]] func(@_QPacc_routine18) bind("_QPacc_routine17" [#acc.device_type], "_QPacc_routine16" [#acc.device_type]) +! CHECK: acc.routine @[[r12:.*]] func(@_QPacc_routine17) worker ([#acc.device_type]) vector ([#acc.device_type]) +! CHECK: acc.routine @[[r11:.*]] func(@_QPacc_routine16) gang([#acc.device_type]) seq ([#acc.device_type]) +! CHECK: acc.routine @[[r10:.*]] func(@_QPacc_routine11) seq +! CHECK: acc.routine @[[r09:.*]] func(@_QPacc_routine10) seq +! CHECK: acc.routine @[[r08:.*]] func(@_QPacc_routine9) bind("_QPacc_routine9a") +! CHECK: acc.routine @[[r07:.*]] func(@_QPacc_routine8) bind("routine8_") +! CHECK: acc.routine @[[r06:.*]] func(@_QPacc_routine7) gang(dim: 1 : i64) +! CHECK: acc.routine @[[r05:.*]] func(@_QPacc_routine6) nohost +! CHECK: acc.routine @[[r04:.*]] func(@_QPacc_routine5) worker +! CHECK: acc.routine @[[r03:.*]] func(@_QPacc_routine4) vector +! CHECK: acc.routine @[[r02:.*]] func(@_QPacc_routine3) gang +! CHECK: acc.routine @[[r01:.*]] func(@_QPacc_routine2) seq +! CHECK: acc.routine @[[r00:.*]] func(@_QPacc_routine1) subroutine acc_routine1() !$acc routine end subroutine -! CHECK-LABEL: func.func @_QPacc_routine1() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_0]>} +! CHECK-LABEL: func.func @_QPacc_routine1() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r00]]]>} subroutine acc_routine2() !$acc routine seq end subroutine -! CHECK-LABEL: func.func @_QPacc_routine2() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_1]>} +! CHECK-LABEL: func.func @_QPacc_routine2() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r01]]]>} subroutine acc_routine3() !$acc routine gang end subroutine -! CHECK-LABEL: func.func @_QPacc_routine3() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_2]>} +! CHECK-LABEL: func.func @_QPacc_routine3() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r02]]]>} subroutine acc_routine4() !$acc routine vector end subroutine -! CHECK-LABEL: func.func @_QPacc_routine4() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_3]>} +! CHECK-LABEL: func.func @_QPacc_routine4() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r03]]]>} subroutine acc_routine5() !$acc routine worker end subroutine -! CHECK-LABEL: func.func @_QPacc_routine5() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_4]>} +! CHECK-LABEL: func.func @_QPacc_routine5() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r04]]]>} subroutine acc_routine6() !$acc routine nohost end subroutine -! CHECK-LABEL: func.func @_QPacc_routine6() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_5]>} +! CHECK-LABEL: func.func @_QPacc_routine6() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r05]]]>} subroutine acc_routine7() !$acc routine gang(dim:1) end subroutine -! CHECK-LABEL: func.func @_QPacc_routine7() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_6]>} +! CHECK-LABEL: func.func @_QPacc_routine7() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r06]]]>} subroutine acc_routine8() !$acc routine bind("routine8_") end subroutine -! CHECK-LABEL: func.func @_QPacc_routine8() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_7]>} +! CHECK-LABEL: func.func @_QPacc_routine8() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r07]]]>} subroutine acc_routine9a() end subroutine @@ -73,20 +81,23 @@ subroutine acc_routine9() !$acc routine bind(acc_routine9a) end subroutine -! CHECK-LABEL: func.func @_QPacc_routine9() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_8]>} +! CHECK-LABEL: func.func @_QPacc_routine9() +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r08]]]>} function acc_routine10() !$acc routine(acc_routine10) seq end function -! CHECK-LABEL: func.func @_QPacc_routine10() -> f32 attributes {acc.routine_info = #acc.routine_info<[@acc_routine_9]>} +! CHECK-LABEL: func.func @_QPacc_routine10() -> f32 +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r09]]]>} subroutine acc_routine11(a) real :: a !$acc routine(acc_routine11) seq end subroutine -! CHECK-LABEL: func.func @_QPacc_routine11(%arg0: !fir.ref {fir.bindc_name = "a"}) attributes {acc.routine_info = #acc.routine_info<[@acc_routine_10]>} +! CHECK-LABEL: func.func @_QPacc_routine11(%arg0: !fir.ref {fir.bindc_name = "a"}) +! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r10]]]>} subroutine acc_routine12()