[flang][OpenMP] Store DECLARE_TARGET information in WithOmpDeclarative (#201103)
This will be used to emit DECLARE_TARGET directives into module files. When a symbol apperars in DECLARE_TARGET, the OmpDeclareTarget flag will be set on it (this includes procedures containing a DECLARE_TARGET without arguments or clauses). The set of accompanying clauses will be stored in the associated details, in the WithOmpDeclarative mixin. The mixin was added to ObjectEntityDetails, ProcEntityDetails, and CommonBlockDetails. The design goal was to be able to reconstruct the appropriate DECLARE_ TARGET directive for individual symbols for the purpose of emitting it in a module file. Simply storing and then unparsing the AST node may include symbols that should not be emitted. Additionally, refactor the WithOmpDeclarative printing code for reuse in symbol dumping for debugging, and for printing clause sets.
This commit is contained in:
parent
3a9c6cdb5d
commit
270a6a8f67
14 changed files with 280 additions and 67 deletions
|
|
@ -137,8 +137,7 @@ void OpenMPCounterVisitor::Post(
|
|||
}
|
||||
void OpenMPCounterVisitor::Post(
|
||||
const OmpDeviceTypeClause::DeviceTypeDescription &c) {
|
||||
clauseDetails +=
|
||||
"type=" + std::string{OmpDeviceTypeClause::EnumToString(c)} + ";";
|
||||
clauseDetails += "type=" + std::string{common::EnumToString(c)} + ";";
|
||||
}
|
||||
void OpenMPCounterVisitor::Post(
|
||||
const OmpDefaultmapClause::ImplicitBehavior &c) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public:
|
|||
NODE_ENUM(common, CUDASubprogramAttrs)
|
||||
NODE_ENUM(common, ImportKind)
|
||||
NODE_ENUM(common, OmpDependenceKind)
|
||||
NODE_ENUM(common, OmpDeviceType)
|
||||
NODE_ENUM(common, OmpMemoryOrderType)
|
||||
NODE_ENUM(common, OpenACCDeviceType)
|
||||
NODE(format, ControlEditDesc)
|
||||
|
|
@ -605,7 +606,6 @@ public:
|
|||
NODE_ENUM(OmpDeviceModifier, Value)
|
||||
NODE(parser, OmpDeviceSafesyncClause)
|
||||
NODE(parser, OmpDeviceTypeClause)
|
||||
NODE_ENUM(OmpDeviceTypeClause, DeviceTypeDescription)
|
||||
NODE(parser, OmpDimsModifier)
|
||||
NODE(parser, OmpDirectiveName)
|
||||
NODE(parser, OmpDirectiveSpecification)
|
||||
|
|
|
|||
|
|
@ -4591,7 +4591,7 @@ struct OmpDeviceSafesyncClause {
|
|||
// device-type-clause ->
|
||||
// DEVICE_TYPE(ANY | HOST | NOHOST) // since 5.0
|
||||
struct OmpDeviceTypeClause {
|
||||
ENUM_CLASS(DeviceTypeDescription, Any, Host, Nohost)
|
||||
using DeviceTypeDescription = common::OmpDeviceType;
|
||||
WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, DeviceTypeDescription);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,18 @@ public:
|
|||
ompAtomicDefaultMemOrder_ = flags;
|
||||
}
|
||||
|
||||
const OmpClauseSet &ompDeclTarget() const { return ompDeclTarget_; }
|
||||
void set_ompDeclTarget(OmpClauseSet clauses) { ompDeclTarget_ = clauses; }
|
||||
|
||||
const std::optional<common::OmpDeviceType> &ompDeviceType() const {
|
||||
return ompDeviceType_;
|
||||
}
|
||||
void set_ompDeclTarget(common::OmpDeviceType device) {
|
||||
ompDeviceType_ = device;
|
||||
}
|
||||
|
||||
void printClauseSet(llvm::raw_ostream &os, const OmpClauseSet &clauses,
|
||||
parser::CharBlock name = parser::CharBlock{}) const;
|
||||
friend llvm::raw_ostream &operator<<(
|
||||
llvm::raw_ostream &, const WithOmpDeclarative &);
|
||||
|
||||
|
|
@ -81,6 +93,12 @@ private:
|
|||
// The argument to ATOMIC_DEFAULT_MEM_ORDER. Only needed when the ADMO
|
||||
// clause is present in the ompRequires_ set.
|
||||
std::optional<common::OmpMemoryOrderType> ompAtomicDefaultMemOrder_;
|
||||
// The set of clauses on DECLARE_TARGET directive that apply to this
|
||||
// symbol.
|
||||
OmpClauseSet ompDeclTarget_;
|
||||
// The argument to DEVICE_TYPE clause. Only needed when the clause is
|
||||
// present in the ompDeclTarget_ set.
|
||||
std::optional<common::OmpDeviceType> ompDeviceType_;
|
||||
};
|
||||
|
||||
// A module or submodule.
|
||||
|
|
@ -379,7 +397,7 @@ private:
|
|||
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
|
||||
|
||||
// An entity known to be an object.
|
||||
class ObjectEntityDetails : public EntityDetails {
|
||||
class ObjectEntityDetails : public EntityDetails, public WithOmpDeclarative {
|
||||
public:
|
||||
explicit ObjectEntityDetails(EntityDetails &&);
|
||||
ObjectEntityDetails(const ObjectEntityDetails &) = default;
|
||||
|
|
@ -450,7 +468,9 @@ private:
|
|||
// A procedure pointer (other than one defined with POINTER and an
|
||||
// INTERFACE block), a dummy procedure (without an INTERFACE but with
|
||||
// EXTERNAL or use in a procedure reference), or external procedure.
|
||||
class ProcEntityDetails : public EntityDetails, public WithPassArg {
|
||||
class ProcEntityDetails : public EntityDetails,
|
||||
public WithPassArg,
|
||||
public WithOmpDeclarative {
|
||||
public:
|
||||
ProcEntityDetails() = default;
|
||||
explicit ProcEntityDetails(EntityDetails &&);
|
||||
|
|
@ -587,7 +607,7 @@ private:
|
|||
SymbolVector objects_;
|
||||
};
|
||||
|
||||
class CommonBlockDetails : public WithBindName {
|
||||
class CommonBlockDetails : public WithBindName, public WithOmpDeclarative {
|
||||
public:
|
||||
explicit CommonBlockDetails(SourceName location)
|
||||
: sourceLocation_{location} {}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ ENUM_CLASS(OmpDependenceKind, In, Out, Inout, Inoutset, Mutexinoutset, Depobj)
|
|||
// OpenMP memory-order types
|
||||
ENUM_CLASS(OmpMemoryOrderType, Acq_Rel, Acquire, Relaxed, Release, Seq_Cst)
|
||||
|
||||
// OpenMP device-type
|
||||
ENUM_CLASS(OmpDeviceType, Any, Host, Nohost)
|
||||
|
||||
// Fortran names may have up to 63 characters (See Fortran 2018 C601).
|
||||
static constexpr int maxNameLen{63};
|
||||
|
||||
|
|
|
|||
|
|
@ -2846,6 +2846,7 @@ public:
|
|||
WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA
|
||||
WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA
|
||||
WALK_NESTED_ENUM(common, OmpDependenceKind)
|
||||
WALK_NESTED_ENUM(common, OmpDeviceType)
|
||||
WALK_NESTED_ENUM(common, OmpMemoryOrderType)
|
||||
WALK_NESTED_ENUM(IntentSpec, Intent) // R826
|
||||
WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
|
||||
|
|
@ -2873,8 +2874,6 @@ public:
|
|||
WALK_NESTED_ENUM(OmpThreadsetClause, ThreadsetPolicy) // OMP threadset
|
||||
WALK_NESTED_ENUM(OmpAccessGroup, Value)
|
||||
WALK_NESTED_ENUM(OmpDeviceModifier, Value) // OMP device modifier
|
||||
WALK_NESTED_ENUM(
|
||||
OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
|
||||
WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
|
||||
WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
|
||||
WALK_NESTED_ENUM(OmpFallbackModifier, Value) // OMP fallback-modifier
|
||||
|
|
|
|||
|
|
@ -364,39 +364,51 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
|
|||
}
|
||||
}
|
||||
|
||||
static const WithOmpDeclarative *GetOmpDeclarative(const Symbol &symbol) {
|
||||
return common::visit(
|
||||
[&](auto &&details) -> const WithOmpDeclarative * {
|
||||
using TypeD = llvm::remove_cvref_t<decltype(details)>;
|
||||
if constexpr (std::is_base_of_v<WithOmpDeclarative, TypeD>) {
|
||||
return &static_cast<const WithOmpDeclarative &>(details);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
},
|
||||
symbol.details());
|
||||
}
|
||||
|
||||
static void PutOpenMPRequirements(
|
||||
llvm::raw_ostream &os, const Symbol &symbol, SemanticsContext &semaCtx) {
|
||||
using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
|
||||
using OmpMemoryOrderType = common::OmpMemoryOrderType;
|
||||
unsigned version{semaCtx.langOptions().OpenMPVersion};
|
||||
|
||||
const auto [reqs, order]{common::visit(
|
||||
[&](auto &&details)
|
||||
-> std::pair<const OmpClauseSet *, const OmpMemoryOrderType *> {
|
||||
if constexpr (std::is_convertible_v<decltype(details),
|
||||
const WithOmpDeclarative &>) {
|
||||
if (const auto &memOrder{details.ompAtomicDefaultMemOrder()}) {
|
||||
return {&details.ompRequires(), &*memOrder};
|
||||
}
|
||||
return {&details.ompRequires(), nullptr};
|
||||
} else {
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
},
|
||||
symbol.details())};
|
||||
if (const auto *decls{GetOmpDeclarative(symbol)}) {
|
||||
if (const OmpClauseSet &reqs{decls->ompRequires()}; reqs.count()) {
|
||||
os << "!$omp "
|
||||
<< parser::ToLowerCaseLetters(llvm::omp::getOpenMPDirectiveName(
|
||||
llvm::omp::Directive::OMPD_requires, version));
|
||||
decls->printClauseSet(os, reqs);
|
||||
os << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reqs->count()) {
|
||||
os << "!$omp requires";
|
||||
reqs->IterateOverMembers([&, order = order](llvm::omp::Clause f) {
|
||||
os << ' '
|
||||
<< parser::ToLowerCaseLetters(
|
||||
llvm::omp::getOpenMPClauseName(f, version));
|
||||
if (f == llvm::omp::Clause::OMPC_atomic_default_mem_order) {
|
||||
os << '(' << parser::ToLowerCaseLetters(EnumToString(DEREF(order)))
|
||||
<< ')';
|
||||
static void PutOpenMPDeclarativeDirectives(llvm::raw_ostream &os,
|
||||
const SymbolVector &symbols, SemanticsContext &semaCtx) {
|
||||
using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
|
||||
unsigned version{semaCtx.langOptions().OpenMPVersion};
|
||||
|
||||
for (const Symbol &symbol : symbols) {
|
||||
if (const auto *decls{GetOmpDeclarative(symbol)}) {
|
||||
if (const OmpClauseSet &dtgt{decls->ompDeclTarget()}; dtgt.count()) {
|
||||
os << "!$omp "
|
||||
<< parser::ToLowerCaseLetters(llvm::omp::getOpenMPDirectiveName(
|
||||
llvm::omp::Directive::OMPD_declare_target, version))
|
||||
<< " ";
|
||||
decls->printClauseSet(os, dtgt, symbol.name());
|
||||
os << "\n";
|
||||
}
|
||||
});
|
||||
os << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -438,6 +450,8 @@ void ModFileWriter::PutSymbols(
|
|||
PutUse(symbol);
|
||||
}
|
||||
PutOpenMPRequirements(decls_, DEREF(scope.symbol()), context_);
|
||||
PutOpenMPDeclarativeDirectives(decls_, sorted, context_);
|
||||
|
||||
for (const auto &set : scope.equivalenceSets()) {
|
||||
if (!set.empty() &&
|
||||
!set.front().symbol.test(Symbol::Flag::CompilerCreated)) {
|
||||
|
|
|
|||
|
|
@ -2191,9 +2191,30 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) {
|
|||
bool OmpAttributeVisitor::Pre(const parser::OmpDeclareTargetDirective &x) {
|
||||
PushContext(x.source, llvm::omp::Directive::OMPD_declare_target);
|
||||
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
|
||||
std::map<const Symbol *, WithOmpDeclarative> details;
|
||||
std::optional<common::OmpDeviceType> device;
|
||||
|
||||
if (auto *devClause{
|
||||
parser::omp::FindClause(x.v, llvm::omp::Clause::OMPC_device_type)}) {
|
||||
device = parser::UnwrapRef<common::OmpDeviceType>(*devClause);
|
||||
}
|
||||
|
||||
auto addClause{[&](const parser::OmpObject &object,
|
||||
llvm::omp::Clause clauseId) {
|
||||
if (const Symbol *sym{omp::GetObjectSymbol(object)}) {
|
||||
auto &clauseSet{const_cast<OmpClauseSet &>(details[sym].ompDeclTarget())};
|
||||
clauseSet.set(clauseId);
|
||||
}
|
||||
}};
|
||||
|
||||
for (const parser::OmpArgument &arg : x.v.Arguments().v) {
|
||||
if (auto *object{parser::omp::GetArgumentObject(arg)}) {
|
||||
ResolveOmpObject(*object, Symbol::Flag::OmpDeclareTarget);
|
||||
// Always record this as "enter", even with older OpenMP versions
|
||||
// (as opposed to "to").
|
||||
addClause(*object, llvm::omp::Clause::OMPC_enter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2201,9 +2222,53 @@ bool OmpAttributeVisitor::Pre(const parser::OmpDeclareTargetDirective &x) {
|
|||
if (auto *objects{parser::omp::GetOmpObjectList(clause)}) {
|
||||
for (const parser::OmpObject &object : objects->v) {
|
||||
ResolveOmpObject(object, Symbol::Flag::OmpDeclareTarget);
|
||||
addClause(object, clause.Id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x.v.Arguments().v.empty() && x.v.Clauses().v.empty()) {
|
||||
// "!$omp declare_target" alone applies to the associated procedure.
|
||||
const Scope &scope{omp::GetScopingUnit(context_.FindScope(x.source))};
|
||||
if (auto *proc{const_cast<Symbol *>(scope.symbol())}) {
|
||||
proc->flags().set(Symbol::Flag::OmpDeclareTarget);
|
||||
auto &clauseSet{
|
||||
const_cast<OmpClauseSet &>(details[proc].ompDeclTarget())};
|
||||
clauseSet.set(llvm::omp::Clause::OMPC_enter);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair : details) {
|
||||
const Symbol *sym{&pair.first->GetUltimate()};
|
||||
const WithOmpDeclarative &decl{pair.second};
|
||||
common::visit(
|
||||
[&](auto &d) {
|
||||
using TypeD = llvm::remove_cvref_t<decltype(d)>;
|
||||
if constexpr (std::is_base_of_v<WithOmpDeclarative, TypeD>) {
|
||||
d.set_version(version);
|
||||
auto &clauseSet{const_cast<OmpClauseSet &>(d.ompDeclTarget())};
|
||||
clauseSet |= decl.ompDeclTarget();
|
||||
if (device) {
|
||||
clauseSet.set(llvm::omp::Clause::OMPC_device_type);
|
||||
auto &deviceType{
|
||||
const_cast<decltype(device) &>(d.ompDeviceType())};
|
||||
deviceType = device;
|
||||
}
|
||||
} else if constexpr (std::is_same_v<GenericDetails, TypeD> ||
|
||||
std::is_same_v<TypeParamDetails, TypeD> ||
|
||||
std::is_same_v<MiscDetails, TypeD>) { // e.g. KindParamInquiry
|
||||
// These cannot be specified on DECLARE_TARGET. The symbol will
|
||||
// receive the OmpDeclareTarget flag (for a diagnostic message),
|
||||
// but no details will be modified.
|
||||
} else {
|
||||
// Catch any unexpected cases.
|
||||
assert((std::is_base_of_v<WithOmpDeclarative, TypeD>) &&
|
||||
"Unexpected details type");
|
||||
}
|
||||
},
|
||||
const_cast<Symbol *>(sym)->details());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,33 +70,50 @@ static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
|
|||
}
|
||||
}
|
||||
|
||||
void WithOmpDeclarative::printClauseSet(llvm::raw_ostream &os,
|
||||
const OmpClauseSet &clauses, parser::CharBlock name) const {
|
||||
auto toLower = parser::ToLowerCaseLetters;
|
||||
|
||||
size_t idx{0}, size{clauses.count()};
|
||||
clauses.IterateOverMembers([&](llvm::omp::Clause c) {
|
||||
os << toLower(llvm::omp::getOpenMPClauseName(c, version_));
|
||||
switch (c) {
|
||||
case llvm::omp::Clause::OMPC_atomic_default_mem_order:
|
||||
os << '(' << toLower(EnumToString(*ompAtomicDefaultMemOrder())) << ')';
|
||||
break;
|
||||
case llvm::omp::Clause::OMPC_device_type:
|
||||
os << "(" << toLower(EnumToString(*ompDeviceType())) << ')';
|
||||
break;
|
||||
case llvm::omp::Clause::OMPC_enter:
|
||||
case llvm::omp::Clause::OMPC_link:
|
||||
if (!name.empty()) {
|
||||
os << '(' << name.ToString() << ')';
|
||||
}
|
||||
break;
|
||||
case llvm::omp::Clause::OMPC_indirect:
|
||||
os << "(true)";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (++idx < size) {
|
||||
os << ' ';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
llvm::raw_ostream &operator<<(
|
||||
llvm::raw_ostream &os, const WithOmpDeclarative &x) {
|
||||
using OmpClauseSet = WithOmpDeclarative::OmpClauseSet;
|
||||
|
||||
auto toLower = parser::ToLowerCaseLetters;
|
||||
|
||||
auto printClauses = [&](const OmpClauseSet &cs) {
|
||||
size_t idx{0}, size{cs.count()};
|
||||
cs.IterateOverMembers([&](llvm::omp::Clause c) {
|
||||
os << toLower(llvm::omp::getOpenMPClauseName(c, x.version_));
|
||||
switch (c) {
|
||||
case llvm::omp::Clause::OMPC_atomic_default_mem_order:
|
||||
os << '(' << toLower(EnumToString(*x.ompAtomicDefaultMemOrder()))
|
||||
<< ')';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (++idx < size) {
|
||||
os << ',';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (const OmpClauseSet &reqs{x.ompRequires()}; reqs.count()) {
|
||||
os << " OmpRequirements:(";
|
||||
printClauses(reqs);
|
||||
x.printClauseSet(os, reqs);
|
||||
os << ')';
|
||||
}
|
||||
if (const OmpClauseSet &dtgt{x.ompDeclTarget()}; dtgt.count()) {
|
||||
os << " OmpDeclareTargetFlags:(";
|
||||
x.printClauseSet(os, dtgt);
|
||||
os << ')';
|
||||
}
|
||||
return os;
|
||||
|
|
@ -541,6 +558,7 @@ llvm::raw_ostream &operator<<(
|
|||
if (x.cudaDataAttr()) {
|
||||
os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
|
||||
}
|
||||
os << static_cast<const WithOmpDeclarative &>(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
@ -580,6 +598,7 @@ llvm::raw_ostream &operator<<(
|
|||
if (x.isCUDAKernel()) {
|
||||
os << " isCUDAKernel";
|
||||
}
|
||||
os << static_cast<const WithOmpDeclarative &>(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
@ -675,6 +694,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
|
|||
for (const auto &object : x.objects()) {
|
||||
os << ' ' << object->name();
|
||||
}
|
||||
os << static_cast<const WithOmpDeclarative &>(x);
|
||||
},
|
||||
[&](const TypeParamDetails &x) {
|
||||
DumpOptional(os, "type", x.type());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | Flags = {}
|
||||
|
|
@ -17,7 +17,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | Flags = {}
|
||||
|
|
@ -27,7 +27,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | Flags = {}
|
||||
|
|
@ -37,7 +37,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | | bool = 'true'
|
||||
|
|
@ -48,7 +48,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | | bool = 'true'
|
||||
|
|
@ -59,7 +59,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | | bool = 'true'
|
||||
|
|
@ -70,7 +70,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Host
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Host
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
|
|
@ -83,7 +83,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
|
|
@ -96,7 +96,7 @@ subroutine openmp_declare_target
|
|||
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareTargetDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare target
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Any
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Any
|
||||
!PARSE-TREE: | OmpClause -> Enter -> OmpEnterClause
|
||||
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
|
||||
!PARSE-TREE: | OmpClause -> To -> OmpToClause
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ end module
|
|||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = groupprivate
|
||||
!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'x'
|
||||
!PARSE-TREE: | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'y'
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> DeviceTypeDescription = Nohost
|
||||
!PARSE-TREE: | OmpClauseList -> OmpClause -> DeviceType -> OmpDeviceTypeClause -> OmpDeviceType = Nohost
|
||||
!PARSE-TREE: | Flags = {}
|
||||
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpGroupprivateDirective -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = groupprivate
|
||||
|
|
|
|||
43
flang/test/Semantics/OpenMP/declare-target-flags.f90
Normal file
43
flang/test/Semantics/OpenMP/declare-target-flags.f90
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
!RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=60 %s | FileCheck %s
|
||||
|
||||
module m
|
||||
integer :: x
|
||||
!$omp declare_target link(x) device_type(nohost)
|
||||
real :: w(10), u(10)
|
||||
common /named_block/ w, u
|
||||
!$omp declare_target link(/named_block/)
|
||||
|
||||
interface
|
||||
real function g(v)
|
||||
real :: v(10)
|
||||
!$omp declare_target
|
||||
end
|
||||
end interface
|
||||
|
||||
contains
|
||||
subroutine f
|
||||
!$omp declare_target(f)
|
||||
end
|
||||
subroutine h
|
||||
integer, save :: a(10)
|
||||
!$omp declare_target enter(h, a)
|
||||
continue
|
||||
end
|
||||
end module
|
||||
|
||||
!CHECK: Module scope: m size=4 alignment=4 sourceRange=383 bytes
|
||||
!CHECK: f, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
|
||||
!CHECK: g, EXTERNAL, PUBLIC (Function, OmpDeclareTarget): Subprogram isInterface result:REAL(4) g (REAL(4) v) OmpDeclareTargetFlags:(enter)
|
||||
!CHECK: h, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
|
||||
!CHECK: u, PUBLIC (InCommonBlock, OmpDeclareTarget) size=40 offset=40: ObjectEntity type: REAL(4) shape: 1_8:10_8
|
||||
!CHECK: w, PUBLIC (InCommonBlock, OmpDeclareTarget) size=40 offset=0: ObjectEntity type: REAL(4) shape: 1_8:10_8
|
||||
!CHECK: x, PUBLIC (OmpDeclareTarget) size=4 offset=0: ObjectEntity type: INTEGER(4) OmpDeclareTargetFlags:(device_type(nohost) link)
|
||||
!CHECK: named_block size=80 offset=0: CommonBlockDetails alignment=4: w u OmpDeclareTargetFlags:(link)
|
||||
!CHECK: Subprogram scope: g size=44 alignment=4 sourceRange=57 bytes
|
||||
!CHECK: g size=4 offset=0: ObjectEntity funcResult type: REAL(4)
|
||||
!CHECK: v size=40 offset=4: ObjectEntity dummy type: REAL(4) shape: 1_8:10_8
|
||||
!CHECK: Subprogram scope: f size=0 alignment=1 sourceRange=40 bytes
|
||||
!CHECK: f (Subroutine, OmpDeclareTarget): HostAssoc => f, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
|
||||
!CHECK: Subprogram scope: h size=40 alignment=4 sourceRange=81 bytes
|
||||
!CHECK: a, SAVE (OmpDeclareTarget) size=40 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:10_8 OmpDeclareTargetFlags:(enter)
|
||||
!CHECK: h (Subroutine, OmpDeclareTarget): HostAssoc => h, PUBLIC (Subroutine): Subprogram () OmpDeclareTargetFlags:(enter)
|
||||
50
flang/test/Semantics/OpenMP/declare-target-modfile.f90
Normal file
50
flang/test/Semantics/OpenMP/declare-target-modfile.f90
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
!RUN: %python %S/../test_modfile.py %s %flang_fc1 -fopenmp -fopenmp-version=60
|
||||
|
||||
module m
|
||||
integer :: x
|
||||
!$omp declare_target link(x) device_type(nohost)
|
||||
real :: w(10), u(10)
|
||||
common /named_block/ w, u
|
||||
!$omp declare_target link(/named_block/)
|
||||
|
||||
interface
|
||||
real function g(v)
|
||||
real :: v(10)
|
||||
!$omp declare_target
|
||||
end
|
||||
end interface
|
||||
|
||||
contains
|
||||
subroutine f
|
||||
!$omp declare_target(f)
|
||||
end
|
||||
subroutine h
|
||||
integer, save :: a(10)
|
||||
!$omp declare_target enter(h, a)
|
||||
continue
|
||||
end
|
||||
end module
|
||||
|
||||
!Expect: m.mod
|
||||
!module m
|
||||
!integer(4)::x
|
||||
!real(4)::w(1_8:10_8)
|
||||
!real(4)::u(1_8:10_8)
|
||||
!interface
|
||||
!function g(v)
|
||||
!real(4)::v(1_8:10_8)
|
||||
!real(4)::g
|
||||
!end
|
||||
!end interface
|
||||
!common/named_block/w,u
|
||||
!!$omp declare_target device_type(nohost) link(x)
|
||||
!!$omp declare_target enter(g)
|
||||
!!$omp declare_target enter(f)
|
||||
!!$omp declare_target enter(h)
|
||||
!!$omp declare_target link(named_block)
|
||||
!contains
|
||||
!subroutine f()
|
||||
!end
|
||||
!subroutine h()
|
||||
!end
|
||||
!end
|
||||
|
|
@ -11,4 +11,4 @@ subroutine f01
|
|||
end
|
||||
end module
|
||||
|
||||
!CHECK: fred: Module OmpRequirements:(atomic_default_mem_order(relaxed),unified_address,unified_shared_memory)
|
||||
!CHECK: fred: Module OmpRequirements:(atomic_default_mem_order(relaxed) unified_address unified_shared_memory)
|
||||
|
|
|
|||
Loading…
Reference in a new issue