mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 01:07:04 +08:00
[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`.
This commit is contained in:
committed by
GitHub
parent
b3a6d434a7
commit
4d9479fa8f
@@ -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.
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@@ -127,6 +128,9 @@ private:
|
||||
// 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 @@ public:
|
||||
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 @@ private:
|
||||
// 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};
|
||||
|
||||
@@ -398,37 +398,39 @@ public:
|
||||
// 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 @@ public:
|
||||
[&](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 @@ public:
|
||||
// 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 @@ public:
|
||||
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 @@ private:
|
||||
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
/// 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 @@ private:
|
||||
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 @@ private:
|
||||
|
||||
/// 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 @@ private:
|
||||
/// 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 @@ private:
|
||||
/// 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)) {
|
||||
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)
|
||||
// Only define the variables owned by this module.
|
||||
const Fortran::semantics::Scope *owningScope = var.getOwningScope();
|
||||
if (owningScope && mod.getScope() != *owningScope)
|
||||
continue;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
Fortran::lower::defineModuleVariable(*this, var);
|
||||
}
|
||||
for (auto &eval : mod.evaluationList)
|
||||
genFIR(eval);
|
||||
});
|
||||
}
|
||||
|
||||
/// Lower functions contained in a module.
|
||||
@@ -6372,13 +6373,6 @@ private:
|
||||
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 @@ private:
|
||||
/// 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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
return builder.getArrayAttr(attributes);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 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<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));
|
||||
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));
|
||||
|
||||
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())));
|
||||
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());
|
||||
}
|
||||
accRoutineInfos.clear();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
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)) {
|
||||
if (const auto v{EvaluateInt64(context_, dim->v)}) {
|
||||
if (info.deviceTypeInfos().empty()) {
|
||||
info.set_gangDim(*v);
|
||||
} else {
|
||||
info.deviceTypeInfos().back().set_gangDim(*v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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();
|
||||
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 (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 (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) {
|
||||
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)}) {
|
||||
for (auto &device : currentDevices) {
|
||||
device->set_gangDim(*v);
|
||||
}
|
||||
}
|
||||
}
|
||||
numArgs++;
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
17
flang/test/Lower/OpenACC/acc-module-definition.f90
Normal file
17
flang/test/Lower/OpenACC/acc-module-definition.f90
Normal file
@@ -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
|
||||
@@ -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 @@ contains
|
||||
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
|
||||
|
||||
23
flang/test/Lower/OpenACC/acc-routine-use-module.f90
Normal file
23
flang/test/Lower/OpenACC/acc-routine-use-module.f90
Normal file
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user