FLANG

check-omp-structure.h
1 //===-- lib/Semantics/check-omp-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 //===----------------------------------------------------------------------===//
8
9 // OpenMP structure validity check list
10 // 1. invalid clauses on directive
11 // 2. invalid repeated clauses on directive
12 // 3. TODO: invalid nesting of regions
13
14 #ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
15 #define FORTRAN_SEMANTICS_CHECK_OMP_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/OpenMP/OMPConstants.h"
21
22 #include <unordered_map>
23
24 using OmpDirectiveSet = Fortran::common::EnumSet<llvm::omp::Directive,
25 llvm::omp::Directive_enumSize>;
26
27 using OmpClauseSet =
28 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
29
30 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
31 #include "llvm/Frontend/OpenMP/OMP.cpp.inc"
32
33 namespace llvm {
34 namespace omp {
35 static OmpDirectiveSet parallelSet{Directive::OMPD_distribute_parallel_do,
36 Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel,
37 Directive::OMPD_parallel_do, Directive::OMPD_parallel_do_simd,
38 Directive::OMPD_parallel_sections, Directive::OMPD_parallel_workshare,
39 Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do,
40 Directive::OMPD_target_parallel_do_simd,
41 Directive::OMPD_target_teams_distribute_parallel_do,
42 Directive::OMPD_target_teams_distribute_parallel_do_simd,
43 Directive::OMPD_teams_distribute_parallel_do,
44 Directive::OMPD_teams_distribute_parallel_do_simd};
45 static OmpDirectiveSet doSet{Directive::OMPD_distribute_parallel_do,
46 Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel,
47 Directive::OMPD_parallel_do, Directive::OMPD_parallel_do_simd,
48 Directive::OMPD_do, Directive::OMPD_do_simd,
49 Directive::OMPD_target_parallel_do, Directive::OMPD_target_parallel_do_simd,
50 Directive::OMPD_target_teams_distribute_parallel_do,
51 Directive::OMPD_target_teams_distribute_parallel_do_simd,
52 Directive::OMPD_teams_distribute_parallel_do,
53 Directive::OMPD_teams_distribute_parallel_do_simd};
54 static OmpDirectiveSet doSimdSet{Directive::OMPD_distribute_parallel_do_simd,
55 Directive::OMPD_parallel_do_simd, Directive::OMPD_do_simd,
56 Directive::OMPD_target_parallel_do_simd,
57 Directive::OMPD_target_teams_distribute_parallel_do_simd,
58 Directive::OMPD_teams_distribute_parallel_do_simd};
59 static OmpDirectiveSet taskloopSet{
60 Directive::OMPD_taskloop, Directive::OMPD_taskloop_simd};
61 static OmpDirectiveSet targetSet{Directive::OMPD_target,
62 Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do,
63 Directive::OMPD_target_parallel_do_simd, Directive::OMPD_target_simd,
64 Directive::OMPD_target_teams, Directive::OMPD_target_teams_distribute,
65 Directive::OMPD_target_teams_distribute_simd};
66 static OmpDirectiveSet simdSet{Directive::OMPD_distribute_parallel_do_simd,
67 Directive::OMPD_distribute_simd, Directive::OMPD_parallel_do_simd,
68 Directive::OMPD_do_simd, Directive::OMPD_simd,
69 Directive::OMPD_target_parallel_do_simd,
70 Directive::OMPD_target_teams_distribute_parallel_do_simd,
71 Directive::OMPD_target_teams_distribute_simd, Directive::OMPD_target_simd,
72 Directive::OMPD_taskloop_simd,
73 Directive::OMPD_teams_distribute_parallel_do_simd,
74 Directive::OMPD_teams_distribute_simd};
75 static OmpDirectiveSet taskGeneratingSet{
76 OmpDirectiveSet{Directive::OMPD_task} | taskloopSet};
77 } // namespace omp
78 } // namespace llvm
79
80 namespace Fortran::semantics {
81
82 class OmpStructureChecker : public virtual BaseChecker {
83 public:
84 OmpStructureChecker(SemanticsContext &context) : context_{context} {}
85
86 void Enter(const parser::OpenMPConstruct &);
87 void Enter(const parser::OpenMPLoopConstruct &);
88 void Leave(const parser::OpenMPLoopConstruct &);
89 void Enter(const parser::OmpEndLoopDirective &);
90
91 void Enter(const parser::OpenMPBlockConstruct &);
92 void Leave(const parser::OpenMPBlockConstruct &);
93 void Enter(const parser::OmpEndBlockDirective &);
94
95 void Enter(const parser::OpenMPSectionsConstruct &);
96 void Leave(const parser::OpenMPSectionsConstruct &);
97 void Enter(const parser::OmpEndSectionsDirective &);
98
99 void Enter(const parser::OpenMPDeclareSimdConstruct &);
100 void Leave(const parser::OpenMPDeclareSimdConstruct &);
101 void Enter(const parser::OpenMPDeclareTargetConstruct &);
102 void Leave(const parser::OpenMPDeclareTargetConstruct &);
103
104 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
105 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
106 void Enter(const parser::OpenMPFlushConstruct &);
107 void Leave(const parser::OpenMPFlushConstruct &);
108 void Enter(const parser::OpenMPCancelConstruct &);
109 void Leave(const parser::OpenMPCancelConstruct &);
110 void Enter(const parser::OpenMPCancellationPointConstruct &);
111 void Leave(const parser::OpenMPCancellationPointConstruct &);
112
113 void Leave(const parser::OmpClauseList &);
114 void Enter(const parser::OmpClause &);
115 void Enter(const parser::OmpNowait &);
116 void Enter(const parser::OmpClause::Inbranch &);
117 void Enter(const parser::OmpClause::Mergeable &);
118 void Enter(const parser::OmpClause::Nogroup &);
119 void Enter(const parser::OmpClause::Notinbranch &);
120 void Enter(const parser::OmpClause::Untied &);
121 void Enter(const parser::OmpClause::Collapse &);
122 void Enter(const parser::OmpClause::Copyin &);
123 void Enter(const parser::OmpClause::Copyprivate &);
124 void Enter(const parser::OmpClause::Device &);
125 void Enter(const parser::OmpClause::DistSchedule &);
126 void Enter(const parser::OmpClause::Final &);
127 void Enter(const parser::OmpClause::Firstprivate &);
128 void Enter(const parser::OmpClause::From &);
129 void Enter(const parser::OmpClause::Grainsize &);
130 void Enter(const parser::OmpClause::Lastprivate &);
131 void Enter(const parser::OmpClause::NumTasks &);
132 void Enter(const parser::OmpClause::NumTeams &);
133 void Enter(const parser::OmpClause::NumThreads &);
134 void Enter(const parser::OmpClause::Ordered &);
135 void Enter(const parser::OmpClause::Priority &);
136 void Enter(const parser::OmpClause::Private &);
137 void Enter(const parser::OmpClause::Safelen &);
138 void Enter(const parser::OmpClause::Shared &);
139 void Enter(const parser::OmpClause::Simdlen &);
140 void Enter(const parser::OmpClause::ThreadLimit &);
141 void Enter(const parser::OmpClause::To &);
142 void Enter(const parser::OmpClause::Link &);
143 void Enter(const parser::OmpClause::Uniform &);
144 void Enter(const parser::OmpClause::UseDevicePtr &);
145 void Enter(const parser::OmpClause::IsDevicePtr &);
146
147 void Enter(const parser::OmpAlignedClause &);
148 void Enter(const parser::OmpDefaultClause &);
149 void Enter(const parser::OmpDefaultmapClause &);
150 void Enter(const parser::OmpDependClause &);
151 void Enter(const parser::OmpIfClause &);
152 void Enter(const parser::OmpLinearClause &);
153 void Enter(const parser::OmpMapClause &);
154 void Enter(const parser::OmpProcBindClause &);
155 void Enter(const parser::OmpReductionClause &);
156 void Enter(const parser::OmpScheduleClause &);
157
158 private:
159 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
160 #include "llvm/Frontend/OpenMP/OMP.cpp.inc"
161
162 struct OmpContext {
163 OmpContext(parser::CharBlock source, llvm::omp::Directive d)
164 : directiveSource{source}, directive{d} {}
165 parser::CharBlock directiveSource{nullptr};
166 parser::CharBlock clauseSource{nullptr};
167 llvm::omp::Directive directive;
168 OmpClauseSet allowedClauses{};
169 OmpClauseSet allowedOnceClauses{};
170 OmpClauseSet allowedExclusiveClauses{};
171 OmpClauseSet requiredClauses{};
172
173 const parser::OmpClause *clause{nullptr};
174 std::multimap<llvm::omp::Clause, const parser::OmpClause *> clauseInfo;
175 };
176 // back() is the top of the stack
177 OmpContext &GetContext() {
178 CHECK(!ompContext_.empty());
179 return ompContext_.back();
180 }
181 // reset source location, check information, and
182 // collected information for END directive
183 void ResetPartialContext(const parser::CharBlock &source) {
184 CHECK(!ompContext_.empty());
185 SetContextDirectiveSource(source);
186 GetContext().allowedClauses = {};
187 GetContext().allowedOnceClauses = {};
188 GetContext().allowedExclusiveClauses = {};
189 GetContext().requiredClauses = {};
190 GetContext().clauseInfo = {};
191 }
192 void SetContextDirectiveSource(const parser::CharBlock &directive) {
193 GetContext().directiveSource = directive;
194 }
195 void SetContextClause(const parser::OmpClause &clause) {
196 GetContext().clauseSource = clause.source;
197 GetContext().clause = &clause;
198 }
199 void SetContextDirectiveEnum(llvm::omp::Directive dir) {
200 GetContext().directive = dir;
201 }
202 void SetContextAllowed(const OmpClauseSet &allowed) {
203 GetContext().allowedClauses = allowed;
204 }
205 void SetContextAllowedOnce(const OmpClauseSet &allowedOnce) {
206 GetContext().allowedOnceClauses = allowedOnce;
207 }
208 void SetContextAllowedExclusive(const OmpClauseSet &allowedExclusive) {
209 GetContext().allowedExclusiveClauses = allowedExclusive;
210 }
211 void SetContextRequired(const OmpClauseSet &required) {
212 GetContext().requiredClauses = required;
213 }
214 void SetContextClauseInfo(llvm::omp::Clause type) {
215 GetContext().clauseInfo.emplace(type, GetContext().clause);
216 }
217 const parser::OmpClause *FindClause(llvm::omp::Clause type) {
218 auto it{GetContext().clauseInfo.find(type)};
219 if (it != GetContext().clauseInfo.end()) {
220 return it->second;
221 }
222 return nullptr;
223 }
224 void PushContext(const parser::CharBlock &source, llvm::omp::Directive dir) {
225 ompContext_.emplace_back(source, dir);
226 }
227 void SetClauseSets(llvm::omp::Directive dir) {
228 ompContext_.back().allowedClauses = directiveClausesTable[dir].allowed;
229 ompContext_.back().allowedOnceClauses =
230 directiveClausesTable[dir].allowedOnce;
231 ompContext_.back().allowedExclusiveClauses =
232 directiveClausesTable[dir].allowedExclusive;
233 ompContext_.back().requiredClauses =
234 directiveClausesTable[dir].requiredOneOf;
235 }
236 void PushContextAndClauseSets(
237 const parser::CharBlock &source, llvm::omp::Directive dir) {
238 PushContext(source, dir);
239 SetClauseSets(dir);
240 }
241 void RequiresConstantPositiveParameter(
242 const llvm::omp::Clause &clause, const parser::ScalarIntConstantExpr &i);
243 void RequiresPositiveParameter(
244 const llvm::omp::Clause &clause, const parser::ScalarIntExpr &i);
245
246 bool CurrentDirectiveIsNested() { return ompContext_.size() > 0; };
247 bool HasInvalidWorksharingNesting(
248 const parser::CharBlock &, const OmpDirectiveSet &);
249 void CheckAllowed(llvm::omp::Clause);
250 void CheckRequired(llvm::omp::Clause);
251 std::string ContextDirectiveAsFortran();
252 void SayNotMatching(const parser::CharBlock &, const parser::CharBlock &);
253 template <typename A, typename B, typename C>
254 const A &CheckMatching(const B &beginDir, const C &endDir) {
255 const A &begin{std::get<A>(beginDir.t)};
256 const A &end{std::get<A>(endDir.t)};
257 if (begin.v != end.v) {
258 SayNotMatching(begin.source, end.source);
259 }
260 return begin;
261 }
262
263 // specific clause related
264 bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
265 const parser::OmpScheduleModifierType::ModType &);
266
267 SemanticsContext &context_;
268 std::vector<OmpContext> ompContext_; // used as a stack
269 };
270 } // namespace Fortran::semantics
271 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Fortran::parser::OmpEndSectionsDirective
Definition: parse-tree.h:3512
Fortran::parser::OmpDefaultmapClause
Definition: parse-tree.h:3326
Fortran::parser::OmpMapClause
Definition: parse-tree.h:3320
Fortran::parser::OpenMPBlockConstruct
Definition: parse-tree.h:3776
Fortran::semantics::SemanticsContext
Definition: semantics.h:60
Fortran::parser::OmpDependClause
Definition: parse-tree.h:3434
Fortran::semantics::OmpStructureChecker
Definition: check-omp-structure.h:82
Fortran::parser::OpenMPSimpleStandaloneConstruct
Definition: parse-tree.h:3738
Fortran::parser::OpenMPDeclareTargetConstruct
Definition: parse-tree.h:3556
Fortran::parser::OmpReductionClause
Definition: parse-tree.h:3409
Fortran::parser::OpenMPLoopConstruct
Definition: parse-tree.h:3782
Fortran::parser::OmpEndBlockDirective
Definition: parse-tree.h:3770
Fortran::parser::OpenMPCancelConstruct
Definition: parse-tree.h:3707
Fortran::parser::OmpClauseList
Definition: parse-tree.h:3495
Fortran::parser::OmpLinearClause
Definition: parse-tree.h:3378
Fortran::parser::Scalar< IntConstantExpr >
Fortran::parser::OmpAlignedClause
Definition: parse-tree.h:3365
Fortran::parser::OmpScheduleClause
Definition: parse-tree.h:3348
Fortran::parser::OpenMPConstruct
Definition: parse-tree.h:3791
Fortran::semantics::BaseChecker
Definition: semantics.h:227
Fortran::parser::OmpProcBindClause
Definition: parse-tree.h:3289
Fortran::parser::OmpClause
Definition: parse-tree.h:3449
Fortran::parser::OmpDefaultClause
Definition: parse-tree.h:3295
Fortran::common::EnumSet
Definition: enum-set.h:28
Fortran::parser::OpenMPCancellationPointConstruct
Definition: parse-tree.h:3700
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::parser::OmpIfClause
Definition: parse-tree.h:3357
Fortran::parser::OpenMPSectionsConstruct
Definition: parse-tree.h:3525
Fortran::parser::OmpEndLoopDirective
Definition: parse-tree.h:3758
Fortran::parser::OpenMPFlushConstruct
Definition: parse-tree.h:3725
Fortran::parser::OpenMPDeclareSimdConstruct
Definition: parse-tree.h:3582