FLANG

check-acc-structure.h
1 //===-- lib/Semantics/check-acc-structure.h ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 // OpenACC structure validity check list
8 // 1. invalid clauses on directive
9 // 2. invalid repeated clauses on directive
10 // 3. invalid nesting of regions
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
15 #define FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
16
17 #include "flang/Common/enum-set.h"
18 #include "flang/Parser/parse-tree.h"
19 #include "flang/Semantics/semantics.h"
20 #include "llvm/Frontend/OpenACC/ACC.h.inc"
21
22 #include <unordered_map>
23
24 using AccDirectiveSet = Fortran::common::EnumSet<llvm::acc::Directive,
25 llvm::acc::Directive_enumSize>;
26
27 using AccClauseSet =
28 Fortran::common::EnumSet<llvm::acc::Clause, llvm::acc::Clause_enumSize>;
29
30 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
31 #include "llvm/Frontend/OpenACC/ACC.cpp.inc"
32
33 namespace Fortran::semantics {
34
35 class AccStructureChecker : public virtual BaseChecker {
36 public:
37 AccStructureChecker(SemanticsContext &context) : context_{context} {}
38
39 // Construct and directives
40 void Enter(const parser::OpenACCBlockConstruct &);
41 void Leave(const parser::OpenACCBlockConstruct &);
42 void Enter(const parser::OpenACCCombinedConstruct &);
43 void Leave(const parser::OpenACCCombinedConstruct &);
44 void Enter(const parser::OpenACCLoopConstruct &);
45 void Leave(const parser::OpenACCLoopConstruct &);
46 void Enter(const parser::OpenACCRoutineConstruct &);
47 void Leave(const parser::OpenACCRoutineConstruct &);
48 void Enter(const parser::OpenACCStandaloneConstruct &);
49 void Leave(const parser::OpenACCStandaloneConstruct &);
50 void Enter(const parser::OpenACCStandaloneDeclarativeConstruct &);
51 void Leave(const parser::OpenACCStandaloneDeclarativeConstruct &);
52
53 // Clauses
54 void Leave(const parser::AccClauseList &);
55 void Enter(const parser::AccClause &);
56
57 void Enter(const parser::AccClause::Auto &);
58 void Enter(const parser::AccClause::Async &);
59 void Enter(const parser::AccClause::Attach &);
60 void Enter(const parser::AccClause::Bind &);
61 void Enter(const parser::AccClause::Capture &);
62 void Enter(const parser::AccClause::Create &);
63 void Enter(const parser::AccClause::Collapse &);
64 void Enter(const parser::AccClause::Copy &);
65 void Enter(const parser::AccClause::Copyin &);
66 void Enter(const parser::AccClause::Copyout &);
67 void Enter(const parser::AccClause::Default &);
68 void Enter(const parser::AccClause::DefaultAsync &);
69 void Enter(const parser::AccClause::Delete &);
70 void Enter(const parser::AccClause::Detach &);
71 void Enter(const parser::AccClause::Device &);
72 void Enter(const parser::AccClause::DeviceNum &);
73 void Enter(const parser::AccClause::DevicePtr &);
74 void Enter(const parser::AccClause::DeviceResident &);
75 void Enter(const parser::AccClause::DeviceType &);
76 void Enter(const parser::AccClause::Finalize &);
77 void Enter(const parser::AccClause::FirstPrivate &);
78 void Enter(const parser::AccClause::Gang &);
79 void Enter(const parser::AccClause::Host &);
80 void Enter(const parser::AccClause::If &);
81 void Enter(const parser::AccClause::IfPresent &);
82 void Enter(const parser::AccClause::Independent &);
83 void Enter(const parser::AccClause::Link &);
84 void Enter(const parser::AccClause::NoCreate &);
85 void Enter(const parser::AccClause::NoHost &);
86 void Enter(const parser::AccClause::NumGangs &);
87 void Enter(const parser::AccClause::NumWorkers &);
88 void Enter(const parser::AccClause::Present &);
89 void Enter(const parser::AccClause::Private &);
90 void Enter(const parser::AccClause::Read &);
91 void Enter(const parser::AccClause::Reduction &);
92 void Enter(const parser::AccClause::Self &);
93 void Enter(const parser::AccClause::Seq &);
94 void Enter(const parser::AccClause::Tile &);
95 void Enter(const parser::AccClause::UseDevice &);
96 void Enter(const parser::AccClause::Vector &);
97 void Enter(const parser::AccClause::VectorLength &);
98 void Enter(const parser::AccClause::Wait &);
99 void Enter(const parser::AccClause::Worker &);
100 void Enter(const parser::AccClause::Write &);
101
102 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();
186
187 void CheckNoBranching(const parser::Block &block,
188 const llvm::acc::Directive directive,
189 const parser::CharBlock &directiveSource) const;
190
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);
200 };
201
202 } // namespace Fortran::semantics
203
204 #endif // FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
Fortran::parser::OpenACCStandaloneConstruct
Definition: parse-tree.h:4066
Fortran::parser::OpenACCRoutineConstruct
Definition: parse-tree.h:3949
Fortran::semantics::SemanticsContext
Definition: semantics.h:60
Fortran::parser::AccClauseList
Definition: parse-tree.h:3944
Fortran::parser::Scalar< IntConstantExpr >
Fortran::parser::OpenACCCombinedConstruct
Definition: parse-tree.h:4044
Fortran::semantics::BaseChecker
Definition: semantics.h:227
Fortran::common::EnumSet
Definition: enum-set.h:28
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::parser::OpenACCBlockConstruct
Definition: parse-tree.h:4023
Fortran::parser::AccClause
Definition: parse-tree.h:3884
Fortran::semantics::AccStructureChecker
Definition: check-acc-structure.h:35
Fortran::parser::OpenACCLoopConstruct
Definition: parse-tree.h:4059
Fortran::parser::OpenACCStandaloneDeclarativeConstruct
Definition: parse-tree.h:4028