[flang-commits] [flang] 4d9479f - [flang][openacc] Allow open acc routines from other modules. (#136012)
via flang-commits
flang-commits at lists.llvm.org
Fri May 9 11:12:27 PDT 2025
Author: Andre Kuhlenschmidt
Date: 2025-05-09T11:12:24-07:00
New Revision: 4d9479fa8f4e949bc4c5768477cd36687c1c6b29
URL: https://github.com/llvm/llvm-project/commit/4d9479fa8f4e949bc4c5768477cd36687c1c6b29
DIFF: https://github.com/llvm/llvm-project/commit/4d9479fa8f4e949bc4c5768477cd36687c1c6b29.diff
LOG: [flang][openacc] Allow open acc routines from other modules. (#136012)
OpenACC routines annotations in separate compilation units currently get
ignored, which leads to errors in compilation. There are two reason for
currently ignoring open acc routine information and this PR is
addressing both.
- The module file reader doesn't read back in openacc directives from
module files.
- Simple fix in `flang/lib/Semantics/mod-file.cpp`
- The lowering to HLFIR doesn't generate routine directives for symbols
imported from other modules that are openacc routines.
- This is the majority of this diff, and is address by the changes that
start in `flang/lib/Lower/CallInterface.cpp`.
Added:
flang/test/Lower/OpenACC/acc-module-definition.f90
flang/test/Lower/OpenACC/acc-routine-use-module.f90
Modified:
flang/include/flang/Lower/OpenACC.h
flang/include/flang/Semantics/symbol.h
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/CallInterface.cpp
flang/lib/Lower/OpenACC.cpp
flang/lib/Semantics/mod-file.cpp
flang/lib/Semantics/resolve-directives.cpp
flang/lib/Semantics/symbol.cpp
flang/test/Lower/OpenACC/acc-routine-named.f90
flang/test/Lower/OpenACC/acc-routine.f90
Removed:
################################################################################
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<std::pair<std::string, mlir::SymbolRefAttr>>;
-
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<Fortran::semantics::OpenACCRoutineInfo> &);
/// 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 1d997abef6dee..97c1e30631840 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -22,6 +22,7 @@
#include <list>
#include <optional>
#include <set>
+#include <variant>
#include <vector>
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<std::string, SymbolRef> *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<std::variant<std::string, SymbolRef>> &
+ 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<std::string> bindName_;
+ // bind("name") -> std::string
+ // bind(sym) -> SymbolRef (requires namemangling in lowering)
+ std::optional<std::variant<std::string, SymbolRef>> 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<OpenACCRoutineDeviceTypeInfo> &deviceTypeInfos() {
+ const std::list<OpenACCRoutineDeviceTypeInfo> &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<OpenACCRoutineDeviceTypeInfo> deviceTypeInfos_;
bool isNohost_{false};
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 0a61f61ab8f75..43375e84f21fa 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -398,37 +398,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<Fortran::lower::pft::FunctionLikeUnit>(
- &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<Fortran::lower::pft::FunctionLikeUnit>(
+ &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.
@@ -439,14 +441,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);
}
@@ -454,24 +449,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) {
@@ -1036,7 +1031,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(); }
@@ -3063,8 +3061,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);
}
@@ -5661,6 +5658,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 =
@@ -5930,8 +5931,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<void()> &createGlobals) {
// FIXME: get rid of the bogus function context and instantiate the
// globals directly into the module.
@@ -5943,6 +5945,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());
@@ -5958,7 +5961,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<Fortran::semantics::ObjectEntityDetails>()) {
@@ -5972,7 +5975,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); });
}
@@ -6042,36 +6045,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.
@@ -6372,13 +6373,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(
@@ -6470,9 +6464,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 73e0984f01635..676c26dbcdbec 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<T>::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<Fortran::semantics::SubprogramDetails>()}) {
+ 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 82daa05c165cb..2f70041a04dde 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"
@@ -4493,125 +4495,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<Fortran::parser::Name> name =
- std::get<std::optional<Fortran::parser::Name>>(routineConstruct.t);
- const auto &clauses =
- std::get<Fortran::parser::AccClauseList>(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<mlir::Attribute> &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<Fortran::semantics::SubprogramDetails>()
- : 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<mlir::Attribute> seqDeviceTypes, vectorDeviceTypes,
- workerDeviceTypes, bindNameDeviceTypes, bindNames, gangDeviceTypes,
- gangDimDeviceTypes, gangDimValues;
-
- // device_type attribute is set to `none` until a device_type clause is
- // encountered.
- llvm::SmallVector<mlir::Attribute> 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<Fortran::parser::AccClause::Seq>(&clause.u)) {
- for (auto crtDeviceTypeAttr : crtDeviceTypes)
- seqDeviceTypes.push_back(crtDeviceTypeAttr);
- } else if (const auto *gangClause =
- std::get_if<Fortran::parser::AccClause::Gang>(&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<Fortran::parser::AccGangArg::Dim>(&gangArg.u)) {
- const std::optional<int64_t> 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<Fortran::parser::AccClause::Vector>(&clause.u)) {
- for (auto crtDeviceTypeAttr : crtDeviceTypes)
- vectorDeviceTypes.push_back(crtDeviceTypeAttr);
- } else if (std::get_if<Fortran::parser::AccClause::Worker>(&clause.u)) {
- for (auto crtDeviceTypeAttr : crtDeviceTypes)
- workerDeviceTypes.push_back(crtDeviceTypeAttr);
- } else if (std::get_if<Fortran::parser::AccClause::Nohost>(&clause.u)) {
- hasNohost = true;
- } else if (const auto *bindClause =
- std::get_if<Fortran::parser::AccClause::Bind>(&clause.u)) {
- if (const auto *name =
- std::get_if<Fortran::parser::Name>(&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<Fortran::parser::ScalarDefaultCharExpr>(
- &bindClause->v.u)) {
- const std::optional<std::string> name =
- Fortran::semantics::GetConstExpr<std::string>(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<Fortran::parser::AccClause::DeviceType>(
- &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<mlir::Attribute> &bindNames,
+ llvm::SmallVector<mlir::Attribute> &bindNameDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &gangDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &gangDimValues,
+ llvm::SmallVector<mlir::Attribute> &gangDimDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &seqDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &workerDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &vectorDeviceTypes) {
for (auto routineOp : mod.getOps<mlir::acc::RoutineOp>()) {
if (routineOp.getFuncName().str().compare(funcName) == 0) {
@@ -4626,47 +4530,117 @@ void Fortran::lower::genOpenACCRoutineConstruct(
mlir::emitError(loc, "Routine already specified with
diff erent 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<mlir::acc::RoutineOp>(
- 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<mlir::func::FuncOp>(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<mlir::Attribute> &seqDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &vectorDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &workerDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &bindNameDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &bindNames,
+ llvm::SmallVector<mlir::Attribute> &gangDeviceTypes,
+ llvm::SmallVector<mlir::Attribute> &gangDimValues,
+ llvm::SmallVector<mlir::Attribute> &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<std::string>(&bindName)}) {
+ bindNameAttr = builder.getStringAttr(*bindStr);
+ } else if (const auto &bindSym{
+ std::get_if<Fortran::semantics::SymbolRef>(&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<Fortran::semantics::OpenACCRoutineInfo> &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<mlir::Attribute> 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
@@ -4774,8 +4748,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{
@@ -4784,14 +4757,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 12fc553518cfd..3ea37ceddd056 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -24,6 +24,7 @@
#include <fstream>
#include <set>
#include <string_view>
+#include <variant>
#include <vector>
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<std::string, SymbolRef> *bindName{info.bindName()}) {
+ os << " bind(";
+ if (std::holds_alternative<std::string>(*bindName)) {
+ os << "\"" << std::get<std::string>(*bindName) << "\"";
+ } else {
+ os << std::get<SymbolRef>(*bindName)->name();
+ }
+ os << ")";
}
}
@@ -1388,6 +1395,9 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> 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 60531538e6d59..138749a97eb72 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1047,88 +1047,78 @@ void AccAttributeVisitor::AddRoutineInfoToSymbol(
Symbol &symbol, const parser::OpenACCRoutineConstruct &x) {
if (symbol.has<SubprogramDetails>()) {
Fortran::semantics::OpenACCRoutineInfo info;
- const auto &clauses = std::get<Fortran::parser::AccClauseList>(x.t);
+ std::vector<OpenACCRoutineDeviceTypeInfo *> currentDevices;
+ currentDevices.push_back(&info);
+ const auto &clauses{std::get<Fortran::parser::AccClauseList>(x.t)};
for (const Fortran::parser::AccClause &clause : clauses.v) {
- if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
- if (info.deviceTypeInfos().empty()) {
- info.set_isSeq();
- } else {
- info.deviceTypeInfos().back().set_isSeq();
+ if (const auto *dTypeClause{
+ std::get_if<Fortran::parser::AccClause::DeviceType>(&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<Fortran::parser::AccClause::Gang>(&clause.u)) {
- if (info.deviceTypeInfos().empty()) {
- info.set_isGang();
- } else {
- info.deviceTypeInfos().back().set_isGang();
+ } else if (std::get_if<Fortran::parser::AccClause::Nohost>(&clause.u)) {
+ info.set_isNohost();
+ } else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
+ for (auto &device : currentDevices) {
+ device->set_isSeq();
+ }
+ } else if (std::get_if<Fortran::parser::AccClause::Vector>(&clause.u)) {
+ for (auto &device : currentDevices) {
+ device->set_isVector();
+ }
+ } else if (std::get_if<Fortran::parser::AccClause::Worker>(&clause.u)) {
+ for (auto &device : currentDevices) {
+ device->set_isWorker();
+ }
+ } else if (const auto *gangClause{
+ std::get_if<Fortran::parser::AccClause::Gang>(
+ &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<Fortran::parser::AccGangArg::Dim>(&gangArg.u)) {
+ CHECK(numArgs <= 1 && "expecting 0 or 1 gang dim args");
+ if (const auto *dim{std::get_if<Fortran::parser::AccGangArg::Dim>(
+ &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<Fortran::parser::AccClause::Vector>(&clause.u)) {
- if (info.deviceTypeInfos().empty()) {
- info.set_isVector();
- } else {
- info.deviceTypeInfos().back().set_isVector();
- }
- } else if (std::get_if<Fortran::parser::AccClause::Worker>(&clause.u)) {
- if (info.deviceTypeInfos().empty()) {
- info.set_isWorker();
- } else {
- info.deviceTypeInfos().back().set_isWorker();
- }
- } else if (std::get_if<Fortran::parser::AccClause::Nohost>(&clause.u)) {
- info.set_isNohost();
- } else if (const auto *bindClause =
- std::get_if<Fortran::parser::AccClause::Bind>(&clause.u)) {
- if (const auto *name =
- std::get_if<Fortran::parser::Name>(&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<Fortran::parser::AccClause::Bind>(
+ &clause.u)}) {
+ if (const auto *name{
+ std::get_if<Fortran::parser::Name>(&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<Fortran::parser::ScalarDefaultCharExpr>(
- &bindClause->v.u)) {
- auto *charConst =
+ &bindClause->v.u)}) {
+ auto *charConst{
Fortran::parser::Unwrap<Fortran::parser::CharLiteralConstant>(
- *charExpr);
+ *charExpr)};
std::string str{std::get<std::string>(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<Fortran::parser::AccClause::DeviceType>(
- &clause.u)) {
- const parser::AccDeviceTypeExprList &deviceTypeExprList = dType->v;
- OpenACCRoutineDeviceTypeInfo dtypeInfo;
- dtypeInfo.set_dType(deviceTypeExprList.v.front().v);
- info.add_deviceTypeInfo(dtypeInfo);
}
}
symbol.get<SubprogramDetails>().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<std::string>(bindName)}) {
+ os << " bindName(\"" << *symbol << "\")";
+ } else {
+ const SymbolRef s{std::get<SymbolRef>(*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<const OpenACCRoutineDeviceTypeInfo &>(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<i32>) 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<host>], "_QPacc_routine17" [#acc.device_type<default>], "_QPacc_routine16" [#acc.device_type<multicore>])
-! CHECK: acc.routine @acc_routine_16 func(@_QPacc_routine18) bind("_QPacc_routine17" [#acc.device_type<host>], "_QPacc_routine16" [#acc.device_type<multicore>])
-! CHECK: acc.routine @acc_routine_15 func(@_QPacc_routine17) worker ([#acc.device_type<host>]) vector ([#acc.device_type<multicore>])
-! CHECK: acc.routine @acc_routine_14 func(@_QPacc_routine16) gang([#acc.device_type<nvidia>]) seq ([#acc.device_type<host>])
-! 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<host>], "_QPacc_routine17" [#acc.device_type<default>], "_QPacc_routine16" [#acc.device_type<multicore>])
+! CHECK: acc.routine @[[r13:.*]] func(@_QPacc_routine18) bind("_QPacc_routine17" [#acc.device_type<host>], "_QPacc_routine16" [#acc.device_type<multicore>])
+! CHECK: acc.routine @[[r12:.*]] func(@_QPacc_routine17) worker ([#acc.device_type<host>]) vector ([#acc.device_type<multicore>])
+! CHECK: acc.routine @[[r11:.*]] func(@_QPacc_routine16) gang([#acc.device_type<nvidia>]) seq ([#acc.device_type<host>])
+! 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<f32> {fir.bindc_name = "a"}) attributes {acc.routine_info = #acc.routine_info<[@acc_routine_10]>}
+! CHECK-LABEL: func.func @_QPacc_routine11(%arg0: !fir.ref<f32> {fir.bindc_name = "a"})
+! CHECK-SAME: attributes {acc.routine_info = #acc.routine_info<[@[[r10]]]>}
subroutine acc_routine12()
More information about the flang-commits
mailing list