[flang][OpenMP] Frontend support for BEGIN/END METADIRECTIVE (#194402)
This implements parsing of BEGIN/END METADIRECTIVE, plus a minimal semantic check for the association of a directive in a WHEN/OTHERWISE clauses. The same semantic checks for the context selectors apply here as in the case of a standalone METADIRECTIVE.
This commit is contained in:
committed by
GitHub
parent
b7d6438450
commit
2fce8c9d9e
@@ -586,6 +586,7 @@ public:
|
||||
NODE_ENUM(OmpDefaultmapClause, ImplicitBehavior)
|
||||
NODE(parser, OmpDeleteModifier)
|
||||
NODE_ENUM(OmpDeleteModifier, Value)
|
||||
NODE(parser, OmpDelimitedMetadirectiveDirective)
|
||||
NODE(parser, OmpDependClause)
|
||||
NODE(OmpDependClause, TaskDep)
|
||||
NODE(OmpDependClause::TaskDep, Modifier)
|
||||
|
||||
@@ -5082,7 +5082,7 @@ struct OmpClauseList {
|
||||
// --- Directives and constructs
|
||||
|
||||
struct OmpDirectiveSpecification {
|
||||
ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo)
|
||||
ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo, ExplicitBegin)
|
||||
using Flags = common::EnumSet<Flag, Flag_enumSize>;
|
||||
|
||||
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
|
||||
@@ -5133,6 +5133,11 @@ struct OmpMetadirectiveDirective {
|
||||
OmpMetadirectiveDirective, OmpDirectiveSpecification);
|
||||
};
|
||||
|
||||
struct OmpDelimitedMetadirectiveDirective : public OmpBlockConstruct {
|
||||
INHERITED_TUPLE_CLASS_BOILERPLATE(
|
||||
OmpDelimitedMetadirectiveDirective, OmpBlockConstruct);
|
||||
};
|
||||
|
||||
// Ref: [5.1:89-90], [5.2:216]
|
||||
//
|
||||
// nothing-directive ->
|
||||
@@ -5468,7 +5473,7 @@ struct OpenMPConstruct {
|
||||
OpenMPSectionConstruct, OpenMPLoopConstruct, OmpBlockConstruct,
|
||||
OpenMPAtomicConstruct, OmpAllocateDirective, OpenMPDispatchConstruct,
|
||||
OpenMPUtilityConstruct, OpenMPAllocatorsConstruct, OpenMPAssumeConstruct,
|
||||
OpenMPCriticalConstruct>
|
||||
OpenMPCriticalConstruct, OmpDelimitedMetadirectiveDirective>
|
||||
u;
|
||||
};
|
||||
|
||||
|
||||
@@ -4544,6 +4544,14 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
|
||||
lowerAtomic(converter, symTable, semaCtx, eval, construct);
|
||||
}
|
||||
|
||||
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
|
||||
semantics::SemanticsContext &semaCtx,
|
||||
lower::pft::Evaluation &eval,
|
||||
const parser::OmpDelimitedMetadirectiveDirective &meta) {
|
||||
TODO(converter.getCurrentLocation(),
|
||||
"OpenMP BEGIN/END METADIRECTIVE lowering");
|
||||
}
|
||||
|
||||
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
|
||||
semantics::SemanticsContext &semaCtx,
|
||||
lower::pft::Evaluation &eval,
|
||||
|
||||
@@ -1924,16 +1924,15 @@ TYPE_PARSER(construct<OmpMetadirectiveDirective>(
|
||||
IsDirective(llvm::omp::Directive::OMPD_metadirective)) >=
|
||||
OmpDirectiveSpecificationParser{}))
|
||||
|
||||
struct OmpBeginDirectiveParser {
|
||||
struct OmpDirectiveParser {
|
||||
using resultType = OmpDirectiveSpecification;
|
||||
|
||||
constexpr OmpBeginDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
|
||||
constexpr OmpBeginDirectiveParser(llvm::omp::Directive dir) {
|
||||
dirs_.set(llvm::to_underlying(dir));
|
||||
}
|
||||
constexpr OmpDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
|
||||
constexpr OmpDirectiveParser(llvm::omp::Directive dir)
|
||||
: dirs_({static_cast<unsigned>(llvm::to_underlying(dir))}) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
auto &&p{predicated(Parser<OmpDirectiveName>{}, IsMemberOf(dirs_)) >=
|
||||
auto p{predicated(Parser<OmpDirectiveName>{}, IsMemberOf(dirs_)) >=
|
||||
OmpDirectiveSpecificationParser{}};
|
||||
return p.Parse(state);
|
||||
}
|
||||
@@ -1942,18 +1941,61 @@ private:
|
||||
DirectiveSet dirs_;
|
||||
};
|
||||
|
||||
// Parse the directive that begins a construct. In some cases the directive
|
||||
// has to be preceded with an explicit "BEGIN", in other cases the begin is
|
||||
// assumed to be implicit. This parser is invoked after the OpenMP sentinel
|
||||
// has been consumed.
|
||||
// Note: Even if OMPD_begin_somename exists, the directive(s) to parse should
|
||||
// use the non-begin id, i.e. OMPD_somename.
|
||||
struct OmpBeginDirectiveParser {
|
||||
using resultType = OmpDirectiveSpecification;
|
||||
|
||||
constexpr OmpBeginDirectiveParser(DirectiveSet dirs, bool implicit = true)
|
||||
: dparser_(dirs), implicit_(implicit) {}
|
||||
constexpr OmpBeginDirectiveParser(
|
||||
llvm::omp::Directive dir, bool implicit = true)
|
||||
: dparser_(dir), implicit_(implicit) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
if (implicit_) {
|
||||
return dparser_.Parse(state);
|
||||
}
|
||||
|
||||
if (auto &&beginToken{verbatim("BEGIN"_sptok).Parse(state)}) {
|
||||
if (auto &&dirSpec{dparser_.Parse(state)}) {
|
||||
// Extend the "source" on both the OmpDirectiveName and the
|
||||
// OmpDirectiveNameSpecification.
|
||||
CharBlock &nameSource{std::get<OmpDirectiveName>(dirSpec->t).source};
|
||||
nameSource.ExtendToCover(beginToken->source);
|
||||
dirSpec->source.ExtendToCover(beginToken->source);
|
||||
std::get<OmpDirectiveSpecification::Flags>(dirSpec->t)
|
||||
.set(OmpDirectiveSpecification::Flag::ExplicitBegin);
|
||||
return std::move(*dirSpec);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
OmpDirectiveParser dparser_;
|
||||
bool implicit_;
|
||||
};
|
||||
|
||||
// Parse the directive that end a construct. In all cases the directive
|
||||
// must be preceded with an explicit "END". This parser is invoked directly
|
||||
// from other construct parsers, so it must handle the OpenMP sentinel.
|
||||
// Note: Even if OMPD_end_somename exists, the directive(s) to parse should
|
||||
// use the non-end id, i.e. OMPD_somename.
|
||||
struct OmpEndDirectiveParser {
|
||||
using resultType = OmpDirectiveSpecification;
|
||||
|
||||
constexpr OmpEndDirectiveParser(DirectiveSet dirs) : dirs_(dirs) {}
|
||||
constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) {
|
||||
dirs_.set(llvm::to_underlying(dir));
|
||||
}
|
||||
constexpr OmpEndDirectiveParser(DirectiveSet dirs) : dparser_(dirs) {}
|
||||
constexpr OmpEndDirectiveParser(llvm::omp::Directive dir) : dparser_(dir) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
if (startOmpLine.Parse(state)) {
|
||||
if (auto endToken{verbatim("END"_sptok).Parse(state)}) {
|
||||
if (auto &&spec{OmpBeginDirectiveParser(dirs_).Parse(state)}) {
|
||||
if (auto &&spec{dparser_.Parse(state)}) {
|
||||
// Extend the "source" on both the OmpDirectiveName and the
|
||||
// OmpDirectiveNameSpecification.
|
||||
CharBlock &nameSource{std::get<OmpDirectiveName>(spec->t).source};
|
||||
@@ -1967,16 +2009,18 @@ struct OmpEndDirectiveParser {
|
||||
}
|
||||
|
||||
private:
|
||||
DirectiveSet dirs_;
|
||||
OmpDirectiveParser dparser_;
|
||||
};
|
||||
|
||||
struct OmpStatementConstructParser {
|
||||
using resultType = OmpBlockConstruct;
|
||||
|
||||
constexpr OmpStatementConstructParser(llvm::omp::Directive dir) : dir_(dir) {}
|
||||
constexpr OmpStatementConstructParser(
|
||||
llvm::omp::Directive dir, bool implicit = true)
|
||||
: dir_(dir), implicit_(implicit) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
if (auto begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
|
||||
if (auto begin{OmpBeginDirectiveParser(dir_, implicit_).Parse(state)}) {
|
||||
Block body;
|
||||
if (auto stmt{attempt(validEPC).Parse(state)}) {
|
||||
body.emplace_back(std::move(*stmt));
|
||||
@@ -1994,15 +2038,18 @@ struct OmpStatementConstructParser {
|
||||
|
||||
private:
|
||||
llvm::omp::Directive dir_;
|
||||
bool implicit_;
|
||||
};
|
||||
|
||||
struct OmpBlockConstructParser {
|
||||
using resultType = OmpBlockConstruct;
|
||||
|
||||
constexpr OmpBlockConstructParser(llvm::omp::Directive dir) : dir_(dir) {}
|
||||
constexpr OmpBlockConstructParser(
|
||||
llvm::omp::Directive dir, bool implicit = true)
|
||||
: dir_(dir), implicit_(implicit) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
if (auto &&begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
|
||||
if (auto &&begin{OmpBeginDirectiveParser(dir_, implicit_).Parse(state)}) {
|
||||
if (IsStandaloneOrdered(*begin)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -2030,19 +2077,21 @@ struct OmpBlockConstructParser {
|
||||
|
||||
private:
|
||||
llvm::omp::Directive dir_;
|
||||
bool implicit_;
|
||||
};
|
||||
|
||||
struct OmpLoopConstructParser {
|
||||
using resultType = OpenMPLoopConstruct;
|
||||
|
||||
constexpr OmpLoopConstructParser(DirectiveSet dirs) : dirs_(dirs) {}
|
||||
constexpr OmpLoopConstructParser(DirectiveSet dirs, bool implicit = true)
|
||||
: dirs_(dirs), implicit_(implicit) {}
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
auto ompLoopConstruct{asBlock(predicated(executionPartConstruct,
|
||||
[](auto &epc) { return Unwrap<OpenMPLoopConstruct>(epc); }))};
|
||||
auto loopItem{LoopNestParser{} || ompLoopConstruct};
|
||||
|
||||
if (auto &&begin{OmpBeginDirectiveParser(dirs_).Parse(state)}) {
|
||||
if (auto &&begin{OmpBeginDirectiveParser(dirs_, implicit_).Parse(state)}) {
|
||||
auto loopDir{begin->DirId()};
|
||||
auto assoc{llvm::omp::getDirectiveAssociation(loopDir)};
|
||||
if (assoc == llvm::omp::Association::LoopNest) {
|
||||
@@ -2078,6 +2127,7 @@ struct OmpLoopConstructParser {
|
||||
|
||||
private:
|
||||
DirectiveSet dirs_;
|
||||
bool implicit_;
|
||||
};
|
||||
|
||||
struct OmpDeclarativeAllocateParser {
|
||||
@@ -2457,6 +2507,10 @@ TYPE_PARSER( //
|
||||
MakeBlockConstruct(llvm::omp::Directive::OMPD_workdistribute))
|
||||
#undef MakeBlockConstruct
|
||||
|
||||
TYPE_PARSER(sourced(
|
||||
construct<OmpDelimitedMetadirectiveDirective>(OmpBlockConstructParser{
|
||||
llvm::omp::Directive::OMPD_metadirective, /*implicit=*/false})))
|
||||
|
||||
// OMP SECTIONS Directive
|
||||
static constexpr DirectiveSet GetSectionsDirectives() {
|
||||
using Directive = llvm::omp::Directive;
|
||||
@@ -2493,8 +2547,12 @@ static bool IsExecutionPart(const OmpDirectiveName &name) {
|
||||
return name.IsExecutionPart();
|
||||
}
|
||||
|
||||
TYPE_PARSER(construct<OpenMPExecDirective>(
|
||||
startOmpLine >> predicated(Parser<OmpDirectiveName>{}, IsExecutionPart)))
|
||||
TYPE_PARSER(construct<OpenMPExecDirective>(startOmpLine >>
|
||||
first( //
|
||||
predicated(Parser<OmpDirectiveName>{}, IsExecutionPart),
|
||||
// begin/end metadirective
|
||||
predicated("BEGIN"_sptok >> Parser<OmpDirectiveName>{},
|
||||
IsDirective(llvm::omp::Directive::OMPD_metadirective)))))
|
||||
|
||||
TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
|
||||
startOmpLine >>
|
||||
@@ -2512,7 +2570,9 @@ TYPE_CONTEXT_PARSER("OpenMP construct"_en_US,
|
||||
construct<OpenMPConstruct>(Parser<OpenMPDispatchConstruct>{}),
|
||||
construct<OpenMPConstruct>(Parser<OpenMPAllocatorsConstruct>{}),
|
||||
construct<OpenMPConstruct>(Parser<OpenMPAssumeConstruct>{}),
|
||||
construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}))))
|
||||
construct<OpenMPConstruct>(Parser<OpenMPCriticalConstruct>{}),
|
||||
construct<OpenMPConstruct>(
|
||||
Parser<OmpDelimitedMetadirectiveDirective>{}))))
|
||||
|
||||
static constexpr DirectiveSet GetLoopDirectives() {
|
||||
using Directive = llvm::omp::Directive;
|
||||
@@ -2571,7 +2631,7 @@ static constexpr DirectiveSet GetAllDirectives() { //
|
||||
TYPE_PARSER(construct<OpenMPMisplacedEndDirective>(
|
||||
OmpEndDirectiveParser{GetAllDirectives()}))
|
||||
|
||||
TYPE_PARSER( //
|
||||
startOmpLine >> sourced(construct<OpenMPInvalidDirective>(
|
||||
!OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))
|
||||
TYPE_PARSER(startOmpLine >>
|
||||
sourced(construct<OpenMPInvalidDirective>(
|
||||
maybe("BEGIN"_sptok) >> !OmpDirectiveNameParser{} >> SkipTo<'\n'>{})))
|
||||
} // namespace Fortran::parser
|
||||
|
||||
@@ -2201,6 +2201,10 @@ public:
|
||||
void Unparse(const OmpBeginDirective &x) {
|
||||
BeginOpenMP();
|
||||
Word("!$OMP ");
|
||||
auto flags{std::get<OmpDirectiveSpecification::Flags>(x.t)};
|
||||
if (flags.test(OmpDirectiveSpecification::Flag::ExplicitBegin)) {
|
||||
Word("BEGIN ");
|
||||
}
|
||||
Walk(static_cast<const OmpDirectiveSpecification &>(x));
|
||||
Put("\n");
|
||||
EndOpenMP();
|
||||
|
||||
@@ -534,6 +534,45 @@ void OmpStructureChecker::CheckTraitSimd(
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
|
||||
// OmpDirectiveSpecification exists on its own only in clauses on
|
||||
// METADIRECTIVE.
|
||||
// In other cases it's a part of other constructs that handle directive
|
||||
// context stack by themselves.
|
||||
if (!GetDirectiveNest(MetadirectiveNest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::omp::Directive dirId{x.DirId()};
|
||||
if (const parser::OpenMPConstruct *meta{GetCurrentConstruct()}) {
|
||||
if (parser::Unwrap<parser::OmpDelimitedMetadirectiveDirective>(meta->u)) {
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
switch (llvm::omp::getDirectiveAssociation(dirId)) {
|
||||
case llvm::omp::Association::Block:
|
||||
case llvm::omp::Association::LoopNest:
|
||||
case llvm::omp::Association::LoopSeq:
|
||||
break;
|
||||
default:
|
||||
if (dirId != llvm::omp::Directive::OMPD_nothing) {
|
||||
context_.Say(x.DirName().source,
|
||||
"A directive in BEGIN %s should have a corresponding end-directive"_err_en_US,
|
||||
parser::omp::GetUpperName(
|
||||
llvm::omp::Directive::OMPD_metadirective, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PushContextAndClauseSets(
|
||||
std::get<parser::OmpDirectiveName>(x.t).source, dirId);
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &x) {
|
||||
if (GetDirectiveNest(MetadirectiveNest)) {
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
|
||||
EnterDirectiveNest(MetadirectiveNest);
|
||||
PushContextAndClauseSets(
|
||||
@@ -545,4 +584,14 @@ void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &) {
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(
|
||||
const parser::OmpDelimitedMetadirectiveDirective &x) {
|
||||
PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_metadirective);
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(
|
||||
const parser::OmpDelimitedMetadirectiveDirective &) {
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
|
||||
} // namespace Fortran::semantics
|
||||
|
||||
@@ -864,22 +864,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::DynGroupprivate &x) {
|
||||
OmpVerifyModifiers(x.v, llvm::omp::OMPC_dyn_groupprivate, source, context_);
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) {
|
||||
// OmpDirectiveSpecification exists on its own only in METADIRECTIVE.
|
||||
// In other cases it's a part of other constructs that handle directive
|
||||
// context stack by themselves.
|
||||
if (GetDirectiveNest(MetadirectiveNest)) {
|
||||
PushContextAndClauseSets(
|
||||
std::get<parser::OmpDirectiveName>(x.t).source, x.DirId());
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) {
|
||||
if (GetDirectiveNest(MetadirectiveNest)) {
|
||||
dirContext_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Checker> struct DirectiveSpellingVisitor {
|
||||
using Directive = llvm::omp::Directive;
|
||||
|
||||
@@ -1396,12 +1380,27 @@ void OmpStructureChecker::ChecksOnOrderedAsBlock() {
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OmpBeginDirective &) {
|
||||
switch (GetContext().directive) {
|
||||
void OmpStructureChecker::Enter(const parser::OmpBeginDirective &x) {
|
||||
switch (x.DirId()) {
|
||||
case llvm::omp::Directive::OMPD_metadirective:
|
||||
// Delimited METADIRECTIVE
|
||||
EnterDirectiveNest(MetadirectiveNest);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OmpBeginDirective &x) {
|
||||
switch (x.DirId()) {
|
||||
case llvm::omp::Directive::OMPD_ordered:
|
||||
// [5.1] 2.19.9 Ordered Construct Restriction
|
||||
ChecksOnOrderedAsBlock();
|
||||
break;
|
||||
case llvm::omp::Directive::OMPD_metadirective:
|
||||
// Delimited METADIRECTIVE
|
||||
ExitDirectiveNest(MetadirectiveNest);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -3433,7 +3432,7 @@ void OmpStructureChecker::Leave(const parser::OmpEndDirective &x) {
|
||||
// 2. Checks on clauses which fall under 'struct OmpClause' from parse-tree.h.
|
||||
// 3. Checks on clauses which are not in 'struct OmpClause' from parse-tree.h.
|
||||
|
||||
void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
|
||||
void OmpStructureChecker::Leave(const parser::OmpClauseList &x) {
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
|
||||
// 2.7.1 Loop Construct Restriction
|
||||
|
||||
@@ -113,6 +113,7 @@ public:
|
||||
void Leave(const parser::OpenMPInteropConstruct &);
|
||||
void Enter(const parser::OmpBlockConstruct &);
|
||||
void Leave(const parser::OmpBlockConstruct &);
|
||||
void Enter(const parser::OmpBeginDirective &);
|
||||
void Leave(const parser::OmpBeginDirective &);
|
||||
void Enter(const parser::OmpEndDirective &);
|
||||
void Leave(const parser::OmpEndDirective &);
|
||||
@@ -175,6 +176,8 @@ public:
|
||||
|
||||
void Enter(const parser::OmpMetadirectiveDirective &);
|
||||
void Leave(const parser::OmpMetadirectiveDirective &);
|
||||
void Enter(const parser::OmpDelimitedMetadirectiveDirective &);
|
||||
void Leave(const parser::OmpDelimitedMetadirectiveDirective &);
|
||||
|
||||
void Enter(const parser::OmpContextSelector &);
|
||||
void Leave(const parser::OmpContextSelector &);
|
||||
|
||||
@@ -469,8 +469,19 @@ public:
|
||||
}
|
||||
|
||||
template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
|
||||
template <typename A> bool Pre(const A &) { return true; }
|
||||
template <typename A> void Post(const A &) {}
|
||||
// Normally the catch-all Pre/Post functions are templates taking
|
||||
// "const T &". For a class D derived from B, and an explicit overload
|
||||
// of Pre(const B &), a call to Pre(D) will select the template instead
|
||||
// of the base clase overload.
|
||||
// Force user-defined conversion from any const-reference, to make sure
|
||||
// that the Pre(AbsorbAnyReference) and Post(AbsorbAnyReference) overloads
|
||||
// will be worse than derived-to-base conversions. This will, for example,
|
||||
// invoke Pre(const OmpBlockConstruct &) for directives derived from it.
|
||||
struct AbsorbAnyReference {
|
||||
template <typename T> AbsorbAnyReference(const T &) {}
|
||||
};
|
||||
bool Pre(AbsorbAnyReference) { return true; }
|
||||
void Post(AbsorbAnyReference) {}
|
||||
|
||||
bool Pre(const parser::SpecificationPart &) {
|
||||
partStack_.push_back(PartKind::SpecificationPart);
|
||||
|
||||
12
flang/test/Lower/OpenMP/Todo/begin-metadirective.f90
Normal file
12
flang/test/Lower/OpenMP/Todo/begin-metadirective.f90
Normal file
@@ -0,0 +1,12 @@
|
||||
! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
|
||||
|
||||
! CHECK: not yet implemented: OpenMP BEGIN/END METADIRECTIVE lowering
|
||||
subroutine test_begin_metadirective
|
||||
integer :: x
|
||||
x = 0
|
||||
!$omp begin metadirective &
|
||||
!$omp & when(implementation={vendor(llvm)}: parallel) &
|
||||
!$omp & otherwise(nothing)
|
||||
x = 1
|
||||
!$omp end metadirective
|
||||
end subroutine
|
||||
80
flang/test/Parser/OpenMP/begin-metadirective.f90
Normal file
80
flang/test/Parser/OpenMP/begin-metadirective.f90
Normal file
@@ -0,0 +1,80 @@
|
||||
!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
|
||||
!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
|
||||
|
||||
subroutine f00
|
||||
!$omp begin metadirective
|
||||
continue
|
||||
!$omp end metadirective
|
||||
end
|
||||
|
||||
!UNPARSE: SUBROUTINE f00
|
||||
!UNPARSE: !$OMP BEGIN METADIRECTIVE
|
||||
!UNPARSE: CONTINUE
|
||||
!UNPARSE: !$OMP END METADIRECTIVE
|
||||
!UNPARSE: END SUBROUTINE
|
||||
|
||||
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpDelimitedMetadirectiveDirective
|
||||
!PARSE-TREE: | OmpBeginDirective
|
||||
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
|
||||
!PARSE-TREE: | | OmpClauseList ->
|
||||
!PARSE-TREE: | | Flags = {ExplicitBegin}
|
||||
!PARSE-TREE: | Block
|
||||
!PARSE-TREE: | OmpEndDirective
|
||||
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
|
||||
!PARSE-TREE: | | OmpClauseList ->
|
||||
!PARSE-TREE: | | Flags = {}
|
||||
|
||||
subroutine f01(s)
|
||||
integer :: i
|
||||
integer :: s
|
||||
s = 0
|
||||
!$omp begin metadirective &
|
||||
!$omp & when(user={condition(.true.)}: parallel do reduction(+: s)) &
|
||||
!$omp & otherwise(do)
|
||||
do i = 1, 10
|
||||
s = s + i
|
||||
end do
|
||||
!$omp end metadirective
|
||||
end
|
||||
|
||||
!UNPARSE: SUBROUTINE f01 (s)
|
||||
!UNPARSE: INTEGER i
|
||||
!UNPARSE: INTEGER s
|
||||
!UNPARSE: s=0_4
|
||||
!UNPARSE: !$OMP BEGIN METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: PARALLEL DO REDUCTION(+: s)&
|
||||
!UNPARSE: !$OMP&) OTHERWISE(DO)
|
||||
!UNPARSE: DO i=1_4,10_4
|
||||
!UNPARSE: s=s+i
|
||||
!UNPARSE: END DO
|
||||
!UNPARSE: !$OMP END METADIRECTIVE
|
||||
!UNPARSE: END SUBROUTINE
|
||||
|
||||
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OmpDelimitedMetadirectiveDirective
|
||||
!PARSE-TREE: | OmpBeginDirective
|
||||
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
|
||||
!PARSE-TREE: | | OmpClauseList -> OmpClause -> When -> OmpWhenClause
|
||||
!PARSE-TREE: | | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
|
||||
!PARSE-TREE: | | | | OmpTraitSetSelectorName -> Value = User
|
||||
!PARSE-TREE: | | | | OmpTraitSelector
|
||||
!PARSE-TREE: | | | | | OmpTraitSelectorName -> Value = Condition
|
||||
!PARSE-TREE: | | | | | Properties
|
||||
!PARSE-TREE: | | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
|
||||
!PARSE-TREE: | | | | | | | LiteralConstant -> LogicalLiteralConstant
|
||||
!PARSE-TREE: | | | | | | | | bool = 'true'
|
||||
!PARSE-TREE: | | | OmpDirectiveSpecification
|
||||
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = parallel do
|
||||
!PARSE-TREE: | | | | OmpClauseList -> OmpClause -> Reduction -> OmpReductionClause
|
||||
!PARSE-TREE: | | | | | Modifier -> OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
|
||||
!PARSE-TREE: | | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 's'
|
||||
!PARSE-TREE: | | | | Flags = {}
|
||||
!PARSE-TREE: | | OmpClause -> Otherwise -> OmpOtherwiseClause -> OmpDirectiveSpecification
|
||||
!PARSE-TREE: | | | OmpDirectiveName -> llvm::omp::Directive = do
|
||||
!PARSE-TREE: | | | OmpClauseList ->
|
||||
!PARSE-TREE: | | | Flags = {}
|
||||
!PARSE-TREE: | | Flags = {ExplicitBegin}
|
||||
!PARSE-TREE: | Block
|
||||
!PARSE-TREE: | OmpEndDirective
|
||||
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = metadirective
|
||||
!PARSE-TREE: | | OmpClauseList ->
|
||||
!PARSE-TREE: | | Flags = {}
|
||||
|
||||
8
flang/test/Semantics/OpenMP/begin-metadirective.f90
Normal file
8
flang/test/Semantics/OpenMP/begin-metadirective.f90
Normal file
@@ -0,0 +1,8 @@
|
||||
!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
|
||||
|
||||
subroutine f00
|
||||
!ERROR: A directive in BEGIN METADIRECTIVE should have a corresponding end-directive
|
||||
!$omp begin metadirective when(user={condition(.true.)}: taskwait)
|
||||
continue
|
||||
!$omp end metadirective
|
||||
end
|
||||
Reference in New Issue
Block a user