Skip to content

Commit 638943b

Browse files
authored
[flang][OpenMP] Convert AST node for ALLOCATORS to use Block as body (#148005)
The ALLOCATORS construct is one of the few constructs that require a special form of the associated block. Convert the AST node to use OmpDirectiveSpecification for the directive and the optional end directive, and to use parser::Block as the body: the form of the block is checked in the semantic checks (with a more meaningful message).
1 parent c040172 commit 638943b

File tree

12 files changed

+252
-144
lines changed

12 files changed

+252
-144
lines changed

flang/examples/FeatureList/FeatureList.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,6 @@ struct NodeVisitor {
472472
READ_FEATURE(OmpIteration)
473473
READ_FEATURE(OmpIterationOffset)
474474
READ_FEATURE(OmpIterationVector)
475-
READ_FEATURE(OmpEndAllocators)
476475
READ_FEATURE(OmpEndBlockDirective)
477476
READ_FEATURE(OmpEndCriticalDirective)
478477
READ_FEATURE(OmpEndLoopDirective)

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,6 @@ class ParseTreeDumper {
578578
NODE(parser, OmpDetachClause)
579579
NODE(parser, OmpDoacrossClause)
580580
NODE(parser, OmpDestroyClause)
581-
NODE(parser, OmpEndAllocators)
582581
NODE(parser, OmpEndBlockDirective)
583582
NODE(parser, OmpEndCriticalDirective)
584583
NODE(parser, OmpEndLoopDirective)

flang/include/flang/Parser/parse-tree.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4598,8 +4598,11 @@ struct OmpClauseList {
45984598
struct OmpDirectiveSpecification {
45994599
ENUM_CLASS(Flags, None, DeprecatedSyntax);
46004600
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
4601+
const OmpDirectiveName &DirName() const {
4602+
return std::get<OmpDirectiveName>(t);
4603+
}
46014604
llvm::omp::Directive DirId() const { //
4602-
return std::get<OmpDirectiveName>(t).v;
4605+
return DirName().v;
46034606
}
46044607
const OmpArgumentList &Arguments() const;
46054608
const OmpClauseList &Clauses() const;
@@ -4839,17 +4842,17 @@ struct OpenMPExecutableAllocate {
48394842
t;
48404843
};
48414844

4842-
EMPTY_CLASS(OmpEndAllocators);
4843-
4844-
// 6.7 Allocators construct [OpenMP 5.2]
4845-
// allocators-construct -> ALLOCATORS [allocate-clause [,]]
4846-
// allocate-stmt
4847-
// [omp-end-allocators-construct]
4845+
// Ref: [5.2:180-181], [6.0:315]
4846+
//
4847+
// allocators-construct ->
4848+
// ALLOCATORS [allocate-clause...]
4849+
// block
4850+
// [END ALLOCATORS]
48484851
struct OpenMPAllocatorsConstruct {
48494852
TUPLE_CLASS_BOILERPLATE(OpenMPAllocatorsConstruct);
48504853
CharBlock source;
4851-
std::tuple<Verbatim, OmpClauseList, Statement<AllocateStmt>,
4852-
std::optional<OmpEndAllocators>>
4854+
std::tuple<OmpDirectiveSpecification, Block,
4855+
std::optional<OmpDirectiveSpecification>>
48534856
t;
48544857
};
48554858

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,32 @@ struct OmpEndDirectiveParser {
12761276
llvm::omp::Directive dir_;
12771277
};
12781278

1279+
struct OmpAllocatorsConstructParser {
1280+
using resultType = OpenMPAllocatorsConstruct;
1281+
1282+
std::optional<resultType> Parse(ParseState &state) const {
1283+
auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1284+
if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_allocators) {
1285+
return std::nullopt;
1286+
}
1287+
1288+
// This should be an allocate-stmt. That will be checked in semantics.
1289+
Block block;
1290+
if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
1291+
block.emplace_back(std::move(*stmt));
1292+
}
1293+
// Allow empty block. Check for this in semantics.
1294+
1295+
auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_allocators}};
1296+
return OpenMPAllocatorsConstruct{
1297+
std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)};
1298+
}
1299+
};
1300+
1301+
TYPE_PARSER(sourced( //
1302+
construct<OpenMPAllocatorsConstruct>(
1303+
"ALLOCATORS"_tok >= OmpAllocatorsConstructParser{})))
1304+
12791305
// Parser for an arbitrary OpenMP ATOMIC construct.
12801306
//
12811307
// Depending on circumstances, an ATOMIC construct applies to one or more
@@ -1622,16 +1648,6 @@ TYPE_PARSER(
16221648
maybe(nonemptyList(Parser<OpenMPDeclarativeAllocate>{})) / endOmpLine,
16231649
statement(allocateStmt))))
16241650

1625-
// 6.7 Allocators construct [OpenMP 5.2]
1626-
// allocators-construct -> ALLOCATORS [allocate-clause [,]]
1627-
// allocate-stmt
1628-
// [omp-end-allocators-construct]
1629-
TYPE_PARSER(sourced(construct<OpenMPAllocatorsConstruct>(
1630-
verbatim("ALLOCATORS"_tok), Parser<OmpClauseList>{} / endOmpLine,
1631-
statement(allocateStmt), maybe(Parser<OmpEndAllocators>{} / endOmpLine))))
1632-
1633-
TYPE_PARSER(construct<OmpEndAllocators>(startOmpLine >> "END ALLOCATORS"_tok))
1634-
16351651
// 2.8.2 Declare Simd construct
16361652
TYPE_PARSER(sourced(construct<OpenMPDeclareSimdConstruct>(
16371653
verbatim("DECLARE SIMD"_tok) || verbatim("DECLARE_SIMD"_tok),

flang/lib/Parser/unparse.cpp

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,7 +2571,7 @@ class UnparseVisitor {
25712571
Word(ToUpperCaseLetters(common::EnumToString(x)));
25722572
}
25732573

2574-
void Unparse(const OpenMPAtomicConstruct &x) {
2574+
template <typename Construct> void UnparseBlockConstruct(const Construct &x) {
25752575
BeginOpenMP();
25762576
Word("!$OMP ");
25772577
Walk(std::get<OmpDirectiveSpecification>(x.t));
@@ -2587,6 +2587,10 @@ class UnparseVisitor {
25872587
}
25882588
}
25892589

2590+
void Unparse(const OpenMPAtomicConstruct &x) { //
2591+
UnparseBlockConstruct(x);
2592+
}
2593+
25902594
void Unparse(const OpenMPExecutableAllocate &x) {
25912595
const auto &fields =
25922596
std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
@@ -2614,22 +2618,8 @@ class UnparseVisitor {
26142618
Put("\n");
26152619
EndOpenMP();
26162620
}
2617-
void Unparse(const OmpEndAllocators &x) {
2618-
BeginOpenMP();
2619-
Word("!$OMP END ALLOCATE");
2620-
Put("\n");
2621-
EndOpenMP();
2622-
}
2623-
void Unparse(const OpenMPAllocatorsConstruct &x) {
2624-
BeginOpenMP();
2625-
Word("!$OMP ALLOCATE");
2626-
Walk(std::get<OmpClauseList>(x.t));
2627-
Put("\n");
2628-
EndOpenMP();
2629-
Walk(std::get<Statement<AllocateStmt>>(x.t));
2630-
if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) {
2631-
Walk(*end);
2632-
}
2621+
void Unparse(const OpenMPAllocatorsConstruct &x) { //
2622+
UnparseBlockConstruct(x);
26332623
}
26342624
void Unparse(const OmpAssumeDirective &x) {
26352625
BeginOpenMP();

flang/lib/Semantics/check-omp-atomic.cpp

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,12 @@ static bool operator!=(const evaluate::Expr<T> &e, const evaluate::Expr<U> &f) {
4747
return !(e == f);
4848
}
4949

50-
// There is no consistent way to get the source of a given ActionStmt, so
51-
// extract the source information from Statement<ActionStmt> when we can,
52-
// and keep it around for error reporting in further analyses.
53-
struct SourcedActionStmt {
54-
const parser::ActionStmt *stmt{nullptr};
55-
parser::CharBlock source;
56-
57-
operator bool() const { return stmt != nullptr; }
58-
};
59-
6050
struct AnalyzedCondStmt {
6151
SomeExpr cond{evaluate::NullPointer{}}; // Default ctor is deleted
6252
parser::CharBlock source;
6353
SourcedActionStmt ift, iff;
6454
};
6555

66-
static SourcedActionStmt GetActionStmt(
67-
const parser::ExecutionPartConstruct *x) {
68-
if (x == nullptr) {
69-
return SourcedActionStmt{};
70-
}
71-
if (auto *exec{std::get_if<parser::ExecutableConstruct>(&x->u)}) {
72-
using ActionStmt = parser::Statement<parser::ActionStmt>;
73-
if (auto *stmt{std::get_if<ActionStmt>(&exec->u)}) {
74-
return SourcedActionStmt{&stmt->statement, stmt->source};
75-
}
76-
}
77-
return SourcedActionStmt{};
78-
}
79-
80-
static SourcedActionStmt GetActionStmt(const parser::Block &block) {
81-
if (block.size() == 1) {
82-
return GetActionStmt(&block.front());
83-
}
84-
return SourcedActionStmt{};
85-
}
86-
8756
// Compute the `evaluate::Assignment` from parser::ActionStmt. The assumption
8857
// is that the ActionStmt will be either an assignment or a pointer-assignment,
8958
// otherwise return std::nullopt.

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,12 @@ template <typename Checker> struct DirectiveSpellingVisitor {
495495
template <typename T> bool Pre(const T &) { return true; }
496496
template <typename T> void Post(const T &) {}
497497

498+
template <typename... Ts>
499+
static const parser::OmpDirectiveName &GetDirName(
500+
const std::tuple<Ts...> &t) {
501+
return std::get<parser::OmpDirectiveSpecification>(t).DirName();
502+
}
503+
498504
bool Pre(const parser::OmpSectionsDirective &x) {
499505
checker_(x.source, x.v);
500506
return false;
@@ -520,8 +526,7 @@ template <typename Checker> struct DirectiveSpellingVisitor {
520526
return false;
521527
}
522528
bool Pre(const parser::OpenMPAllocatorsConstruct &x) {
523-
checker_(
524-
std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocators);
529+
checker_(GetDirName(x.t).source, Directive::OMPD_allocators);
525530
return false;
526531
}
527532
bool Pre(const parser::OmpAssumeDirective &x) {
@@ -1657,26 +1662,45 @@ void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
16571662

16581663
void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
16591664
isPredefinedAllocator = true;
1660-
const auto &dir{std::get<parser::Verbatim>(x.t)};
1661-
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocators);
1662-
const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
1663-
for (const auto &clause : clauseList.v) {
1665+
1666+
auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
1667+
auto &block{std::get<parser::Block>(x.t)};
1668+
PushContextAndClauseSets(
1669+
dirSpec.DirName().source, llvm::omp::Directive::OMPD_allocators);
1670+
1671+
if (block.empty()) {
1672+
context_.Say(dirSpec.source,
1673+
"The ALLOCATORS construct should contain a single ALLOCATE statement"_err_en_US);
1674+
return;
1675+
}
1676+
1677+
omp::SourcedActionStmt action{omp::GetActionStmt(block)};
1678+
const auto *allocate{
1679+
action ? parser::Unwrap<parser::AllocateStmt>(action.stmt) : nullptr};
1680+
1681+
if (!allocate) {
1682+
const parser::CharBlock &source = action ? action.source : x.source;
1683+
context_.Say(source,
1684+
"The body of the ALLOCATORS construct should be an ALLOCATE statement"_err_en_US);
1685+
}
1686+
1687+
for (const auto &clause : dirSpec.Clauses().v) {
16641688
if (const auto *allocClause{
16651689
parser::Unwrap<parser::OmpClause::Allocate>(clause)}) {
16661690
CheckVarIsNotPartOfAnotherVar(
1667-
dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
1691+
dirSpec.source, std::get<parser::OmpObjectList>(allocClause->v.t));
16681692
}
16691693
}
16701694
}
16711695

16721696
void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
1673-
const auto &dir{std::get<parser::Verbatim>(x.t)};
1674-
const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
1675-
for (const auto &clause : clauseList.v) {
1697+
auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
1698+
1699+
for (const auto &clause : dirSpec.Clauses().v) {
16761700
if (const auto *allocClause{
16771701
std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
16781702
CheckPredefinedAllocatorRestriction(
1679-
dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
1703+
dirSpec.source, std::get<parser::OmpObjectList>(allocClause->v.t));
16801704
}
16811705
}
16821706
dirContext_.pop_back();

flang/lib/Semantics/openmp-utils.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@
3838

3939
namespace Fortran::semantics::omp {
4040

41+
SourcedActionStmt GetActionStmt(const parser::ExecutionPartConstruct *x) {
42+
if (x == nullptr) {
43+
return SourcedActionStmt{};
44+
}
45+
if (auto *exec{std::get_if<parser::ExecutableConstruct>(&x->u)}) {
46+
using ActionStmt = parser::Statement<parser::ActionStmt>;
47+
if (auto *stmt{std::get_if<ActionStmt>(&exec->u)}) {
48+
return SourcedActionStmt{&stmt->statement, stmt->source};
49+
}
50+
}
51+
return SourcedActionStmt{};
52+
}
53+
54+
SourcedActionStmt GetActionStmt(const parser::Block &block) {
55+
if (block.size() == 1) {
56+
return GetActionStmt(&block.front());
57+
}
58+
return SourcedActionStmt{};
59+
}
60+
4161
std::string ThisVersion(unsigned version) {
4262
std::string tv{
4363
std::to_string(version / 10) + "." + std::to_string(version % 10)};

flang/lib/Semantics/openmp-utils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ class Symbol;
2929

3030
// Add this namespace to avoid potential conflicts
3131
namespace omp {
32+
// There is no consistent way to get the source of an ActionStmt, but there
33+
// is "source" in Statement<T>. This structure keeps the ActionStmt with the
34+
// extracted source for further use.
35+
struct SourcedActionStmt {
36+
const parser::ActionStmt *stmt{nullptr};
37+
parser::CharBlock source;
38+
39+
operator bool() const { return stmt != nullptr; }
40+
};
41+
42+
SourcedActionStmt GetActionStmt(const parser::ExecutionPartConstruct *x);
43+
SourcedActionStmt GetActionStmt(const parser::Block &block);
44+
3245
std::string ThisVersion(unsigned version);
3346
std::string TryVersion(unsigned version);
3447

0 commit comments

Comments
 (0)