Skip to content

Commit 4062618

Browse files
committed
[flang][NFC] Unify OpenMP and OpenACC structure checker
This patch remove duplicated code between the check-omp-structure and the check-acc-structure and unify it into a check-directive-structure templated class. Reviewed By: kiranchandramohan, sscalpone, ichoyjx Differential Revision: https://reviews.llvm.org/D85104
1 parent 9fdd0df commit 4062618

11 files changed

+464
-504
lines changed

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

Lines changed: 11 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ void AccStructureChecker::Leave(const parser::OpenACCBlockConstruct &x) {
132132
default:
133133
break;
134134
}
135-
accContext_.pop_back();
135+
dirContext_.pop_back();
136136
}
137137

138138
void AccStructureChecker::CheckNoBranching(const parser::Block &block,
@@ -152,7 +152,7 @@ void AccStructureChecker::Leave(
152152
const parser::OpenACCStandaloneDeclarativeConstruct &) {
153153
// Restriction - 2075
154154
CheckAtLeastOneClause();
155-
accContext_.pop_back();
155+
dirContext_.pop_back();
156156
}
157157

158158
void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
@@ -185,12 +185,7 @@ void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
185185
default:
186186
break;
187187
}
188-
accContext_.pop_back();
189-
}
190-
191-
std::string AccStructureChecker::ContextDirectiveAsFortran() {
192-
return parser::ToUpperCaseLetters(
193-
llvm::acc::getOpenACCDirectiveName(GetContext().directive).str());
188+
dirContext_.pop_back();
194189
}
195190

196191
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
@@ -211,7 +206,7 @@ void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
211206
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
212207
llvm::acc::Clause::ACCC_worker});
213208
}
214-
accContext_.pop_back();
209+
dirContext_.pop_back();
215210
}
216211

217212
void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) {
@@ -238,7 +233,7 @@ void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) {
238233
default:
239234
break;
240235
}
241-
accContext_.pop_back();
236+
dirContext_.pop_back();
242237
}
243238

244239
void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) {
@@ -250,7 +245,7 @@ void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) {
250245
// Restriction - 2407-2408
251246
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
252247
routineOnlyAllowedAfterDeviceTypeClauses);
253-
accContext_.pop_back();
248+
dirContext_.pop_back();
254249
}
255250

256251
// Clause checkers
@@ -348,154 +343,13 @@ void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) {
348343
}
349344
}
350345

351-
void AccStructureChecker::CheckAllowed(llvm::acc::Clause clause) {
352-
if (!GetContext().allowedClauses.test(clause) &&
353-
!GetContext().allowedOnceClauses.test(clause) &&
354-
!GetContext().allowedExclusiveClauses.test(clause) &&
355-
!GetContext().requiredClauses.test(clause)) {
356-
context_.Say(GetContext().clauseSource,
357-
"%s clause is not allowed on the %s directive"_err_en_US,
358-
parser::ToUpperCaseLetters(
359-
llvm::acc::getOpenACCClauseName(clause).str()),
360-
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
361-
return;
362-
}
363-
if ((GetContext().allowedOnceClauses.test(clause) ||
364-
GetContext().allowedExclusiveClauses.test(clause)) &&
365-
FindClause(clause)) {
366-
context_.Say(GetContext().clauseSource,
367-
"At most one %s clause can appear on the %s directive"_err_en_US,
368-
parser::ToUpperCaseLetters(
369-
llvm::acc::getOpenACCClauseName(clause).str()),
370-
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
371-
return;
372-
}
373-
if (GetContext().allowedExclusiveClauses.test(clause)) {
374-
std::vector<llvm::acc::Clause> others;
375-
GetContext().allowedExclusiveClauses.IterateOverMembers(
376-
[&](llvm::acc::Clause o) {
377-
if (FindClause(o)) {
378-
others.emplace_back(o);
379-
}
380-
});
381-
for (const auto &e : others) {
382-
context_.Say(GetContext().clauseSource,
383-
"%s and %s clauses are mutually exclusive and may not appear on the "
384-
"same %s directive"_err_en_US,
385-
parser::ToUpperCaseLetters(
386-
llvm::acc::getOpenACCClauseName(clause).str()),
387-
parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(e).str()),
388-
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
389-
}
390-
if (!others.empty()) {
391-
return;
392-
}
393-
}
394-
SetContextClauseInfo(clause);
395-
AddClauseToCrtContext(clause);
396-
}
397-
398-
void AccStructureChecker::CheckOnlyAllowedAfter(
399-
llvm::acc::Clause clause, AccClauseSet set) {
400-
bool enforceCheck = false;
401-
for (auto cl : GetContext().actualClauses) {
402-
if (cl == clause) {
403-
enforceCheck = true;
404-
continue;
405-
} else if (enforceCheck && !set.test(cl)) {
406-
auto parserClause = GetContext().clauseInfo.find(cl);
407-
context_.Say(parserClause->second->source,
408-
"Clause %s is not allowed after clause %s on the %s "
409-
"directive"_err_en_US,
410-
parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
411-
parser::ToUpperCaseLetters(
412-
llvm::acc::getOpenACCClauseName(clause).str()),
413-
ContextDirectiveAsFortran());
414-
}
415-
}
416-
}
417-
418-
void AccStructureChecker::CheckRequireAtLeastOneOf() {
419-
for (auto cl : GetContext().actualClauses) {
420-
if (GetContext().requiredClauses.test(cl))
421-
return;
422-
}
423-
// No clause matched in the actual clauses list
424-
context_.Say(GetContext().directiveSource,
425-
"At least one of %s clause must appear on the %s directive"_err_en_US,
426-
ClauseSetToString(GetContext().requiredClauses),
427-
ContextDirectiveAsFortran());
428-
}
429-
430-
void AccStructureChecker::CheckAtLeastOneClause() {
431-
if (GetContext().actualClauses.empty()) {
432-
context_.Say(GetContext().directiveSource,
433-
"At least one clause is required on the %s directive"_err_en_US,
434-
ContextDirectiveAsFortran());
435-
}
436-
}
437-
438-
// Enforce restriction where clauses in the given set are not allowed if the
439-
// given clause appears.
440-
void AccStructureChecker::CheckNotAllowedIfClause(
441-
llvm::acc::Clause clause, AccClauseSet set) {
442-
if (std::find(GetContext().actualClauses.begin(),
443-
GetContext().actualClauses.end(),
444-
clause) == GetContext().actualClauses.end()) {
445-
return; // Clause is not present
446-
}
447-
448-
for (auto cl : GetContext().actualClauses) {
449-
if (set.test(cl)) {
450-
context_.Say(GetContext().directiveSource,
451-
"Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
452-
parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
453-
parser::ToUpperCaseLetters(
454-
llvm::acc::getOpenACCClauseName(clause).str()),
455-
ContextDirectiveAsFortran());
456-
}
457-
}
458-
}
459-
460-
void AccStructureChecker::RequiresConstantPositiveParameter(
461-
const llvm::acc::Clause &clause, const parser::ScalarIntConstantExpr &i) {
462-
if (const auto v{GetIntValue(i)}) {
463-
if (*v <= 0) {
464-
context_.Say(GetContext().clauseSource,
465-
"The parameter of the %s clause on the %s directive must be "
466-
"a constant positive integer expression"_err_en_US,
467-
parser::ToUpperCaseLetters(
468-
llvm::acc::getOpenACCClauseName(clause).str()),
469-
ContextDirectiveAsFortran());
470-
}
471-
}
472-
}
473-
474-
void AccStructureChecker::OptionalConstantPositiveParameter(
475-
const llvm::acc::Clause &clause,
476-
const std::optional<parser::ScalarIntConstantExpr> &o) {
477-
if (o != std::nullopt) {
478-
RequiresConstantPositiveParameter(clause, o.value());
479-
}
480-
}
481-
482-
std::string AccStructureChecker::ClauseSetToString(const AccClauseSet set) {
483-
std::string list;
484-
set.IterateOverMembers([&](llvm::acc::Clause o) {
485-
if (!list.empty())
486-
list.append(", ");
487-
list.append(
488-
parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(o).str()));
489-
});
490-
return list;
346+
llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) {
347+
return llvm::acc::getOpenACCClauseName(clause);
491348
}
492349

493-
void AccStructureChecker::SayNotMatching(
494-
const parser::CharBlock &beginSource, const parser::CharBlock &endSource) {
495-
context_
496-
.Say(endSource, "Unmatched %s directive"_err_en_US,
497-
parser::ToUpperCaseLetters(endSource.ToString()))
498-
.Attach(beginSource, "Does not match directive"_en_US);
350+
llvm::StringRef AccStructureChecker::getDirectiveName(
351+
llvm::acc::Directive directive) {
352+
return llvm::acc::getOpenACCDirectiveName(directive);
499353
}
500354

501355
} // namespace Fortran::semantics

flang/lib/Semantics/check-acc-structure.h

Lines changed: 12 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@
1414
#ifndef FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
1515
#define FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
1616

17+
#include "check-directive-structure.h"
1718
#include "flang/Common/enum-set.h"
1819
#include "flang/Parser/parse-tree.h"
1920
#include "flang/Semantics/semantics.h"
2021
#include "llvm/Frontend/OpenACC/ACC.h.inc"
2122

22-
#include <unordered_map>
23-
2423
using AccDirectiveSet = Fortran::common::EnumSet<llvm::acc::Directive,
2524
llvm::acc::Directive_enumSize>;
2625

@@ -32,9 +31,16 @@ using AccClauseSet =
3231

3332
namespace Fortran::semantics {
3433

35-
class AccStructureChecker : public virtual BaseChecker {
34+
class AccStructureChecker
35+
: public DirectiveStructureChecker<llvm::acc::Directive, llvm::acc::Clause,
36+
parser::AccClause, llvm::acc::Clause_enumSize> {
3637
public:
37-
AccStructureChecker(SemanticsContext &context) : context_{context} {}
38+
AccStructureChecker(SemanticsContext &context)
39+
: DirectiveStructureChecker(context,
40+
#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
41+
#include "llvm/Frontend/OpenACC/ACC.cpp.inc"
42+
) {
43+
}
3844

3945
// Construct and directives
4046
void Enter(const parser::OpenACCBlockConstruct &);
@@ -100,103 +106,13 @@ class AccStructureChecker : public virtual BaseChecker {
100106
void Enter(const parser::AccClause::Write &);
101107

102108
private:
103-
#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
104-
#include "llvm/Frontend/OpenACC/ACC.cpp.inc"
105-
106-
struct AccContext {
107-
AccContext(parser::CharBlock source, llvm::acc::Directive d)
108-
: directiveSource{source}, directive{d} {}
109-
110-
parser::CharBlock directiveSource{nullptr};
111-
parser::CharBlock clauseSource{nullptr};
112-
llvm::acc::Directive directive;
113-
AccClauseSet allowedClauses{};
114-
AccClauseSet allowedOnceClauses{};
115-
AccClauseSet allowedExclusiveClauses{};
116-
AccClauseSet requiredClauses{};
117-
118-
const parser::AccClause *clause{nullptr};
119-
std::multimap<llvm::acc::Clause, const parser::AccClause *> clauseInfo;
120-
std::list<llvm::acc::Clause> actualClauses;
121-
};
122-
123-
// back() is the top of the stack
124-
AccContext &GetContext() {
125-
CHECK(!accContext_.empty());
126-
return accContext_.back();
127-
}
128-
129-
void SetContextClause(const parser::AccClause &clause) {
130-
GetContext().clauseSource = clause.source;
131-
GetContext().clause = &clause;
132-
}
133-
134-
void SetContextClauseInfo(llvm::acc::Clause type) {
135-
GetContext().clauseInfo.emplace(type, GetContext().clause);
136-
}
137-
138-
void AddClauseToCrtContext(llvm::acc::Clause type) {
139-
GetContext().actualClauses.push_back(type);
140-
}
141-
142-
const parser::AccClause *FindClause(llvm::acc::Clause type) {
143-
auto it{GetContext().clauseInfo.find(type)};
144-
if (it != GetContext().clauseInfo.end()) {
145-
return it->second;
146-
}
147-
return nullptr;
148-
}
149-
150-
void PushContext(const parser::CharBlock &source, llvm::acc::Directive dir) {
151-
accContext_.emplace_back(source, dir);
152-
}
153-
154-
void SetClauseSets(llvm::acc::Directive dir) {
155-
accContext_.back().allowedClauses = directiveClausesTable[dir].allowed;
156-
accContext_.back().allowedOnceClauses =
157-
directiveClausesTable[dir].allowedOnce;
158-
accContext_.back().allowedExclusiveClauses =
159-
directiveClausesTable[dir].allowedExclusive;
160-
accContext_.back().requiredClauses =
161-
directiveClausesTable[dir].requiredOneOf;
162-
}
163-
void PushContextAndClauseSets(
164-
const parser::CharBlock &source, llvm::acc::Directive dir) {
165-
PushContext(source, dir);
166-
SetClauseSets(dir);
167-
}
168-
169-
void SayNotMatching(const parser::CharBlock &, const parser::CharBlock &);
170-
171-
template <typename B> void CheckMatching(const B &beginDir, const B &endDir) {
172-
const auto &begin{beginDir.v};
173-
const auto &end{endDir.v};
174-
if (begin != end) {
175-
SayNotMatching(beginDir.source, endDir.source);
176-
}
177-
}
178-
179-
// Check that only clauses in set are after the specific clauses.
180-
void CheckOnlyAllowedAfter(llvm::acc::Clause clause, AccClauseSet set);
181-
void CheckRequireAtLeastOneOf();
182-
void CheckAllowed(llvm::acc::Clause clause);
183-
void CheckAtLeastOneClause();
184-
void CheckNotAllowedIfClause(llvm::acc::Clause clause, AccClauseSet set);
185-
std::string ContextDirectiveAsFortran();
186109

187110
void CheckNoBranching(const parser::Block &block,
188111
const llvm::acc::Directive directive,
189112
const parser::CharBlock &directiveSource) const;
190113

191-
void RequiresConstantPositiveParameter(
192-
const llvm::acc::Clause &clause, const parser::ScalarIntConstantExpr &i);
193-
void OptionalConstantPositiveParameter(const llvm::acc::Clause &clause,
194-
const std::optional<parser::ScalarIntConstantExpr> &o);
195-
196-
SemanticsContext &context_;
197-
std::vector<AccContext> accContext_; // used as a stack
198-
199-
std::string ClauseSetToString(const AccClauseSet set);
114+
llvm::StringRef getClauseName(llvm::acc::Clause clause) override;
115+
llvm::StringRef getDirectiveName(llvm::acc::Directive directive) override;
200116
};
201117

202118
} // namespace Fortran::semantics

0 commit comments

Comments
 (0)