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 "check-directive-structure.h"
18#include "flang/Common/enum-set.h"
19#include "flang/Parser/parse-tree.h"
20#include "flang/Semantics/openmp-directive-sets.h"
21#include "flang/Semantics/semantics.h"
22
23using OmpClauseSet =
25
26#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
27#include "llvm/Frontend/OpenMP/OMP.inc"
28
29namespace llvm {
30namespace omp {
31static OmpClauseSet privateSet{
32 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
33static OmpClauseSet privateReductionSet{
34 OmpClauseSet{Clause::OMPC_reduction} | privateSet};
35// omp.td cannot differentiate allowed/not allowed clause list for few
36// directives for fortran. nowait is not allowed on begin directive clause list
37// for below list of directives. Directives with conflicting list of clauses are
38// included in below list.
39static const OmpDirectiveSet noWaitClauseNotAllowedSet{
40 Directive::OMPD_do,
41 Directive::OMPD_do_simd,
42 Directive::OMPD_sections,
43 Directive::OMPD_single,
44 Directive::OMPD_workshare,
45};
46} // namespace omp
47} // namespace llvm
48
49namespace Fortran::semantics {
50struct AnalyzedCondStmt;
51
52// Mapping from 'Symbol' to 'Source' to keep track of the variables
53// used in multiple clauses
54using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
55// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
56using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
57 std::pair<llvm::omp::Directive, const OmpClauseSet>>;
58
59using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,
60 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
61
62class OmpStructureChecker : public OmpStructureCheckerBase {
63public:
64 using Base = OmpStructureCheckerBase;
65
66 OmpStructureChecker(SemanticsContext &context);
67
68 using llvmOmpClause = const llvm::omp::Clause;
69
70 bool Enter(const parser::MainProgram &);
71 void Leave(const parser::MainProgram &);
72 bool Enter(const parser::BlockData &);
73 void Leave(const parser::BlockData &);
74 bool Enter(const parser::Module &);
75 void Leave(const parser::Module &);
76 bool Enter(const parser::Submodule &);
77 void Leave(const parser::Submodule &);
78 bool Enter(const parser::SubroutineStmt &);
79 bool Enter(const parser::EndSubroutineStmt &);
80 bool Enter(const parser::FunctionStmt &);
81 bool Enter(const parser::EndFunctionStmt &);
82 bool Enter(const parser::BlockConstruct &);
83 void Leave(const parser::BlockConstruct &);
84
85 void Enter(const parser::SpecificationPart &);
86 void Leave(const parser::SpecificationPart &);
87 void Enter(const parser::ExecutionPart &);
88 void Leave(const parser::ExecutionPart &);
89
90 void Enter(const parser::OpenMPConstruct &);
91 void Leave(const parser::OpenMPConstruct &);
92 void Enter(const parser::OpenMPInteropConstruct &);
93 void Leave(const parser::OpenMPInteropConstruct &);
94 void Enter(const parser::OpenMPDeclarativeConstruct &);
95 void Leave(const parser::OpenMPDeclarativeConstruct &);
96
97 void Enter(const parser::OpenMPLoopConstruct &);
98 void Leave(const parser::OpenMPLoopConstruct &);
99 void Enter(const parser::OmpEndLoopDirective &);
100 void Leave(const parser::OmpEndLoopDirective &);
101
102 void Enter(const parser::OpenMPAssumeConstruct &);
103 void Leave(const parser::OpenMPAssumeConstruct &);
104 void Enter(const parser::OpenMPDeclarativeAssumes &);
105 void Leave(const parser::OpenMPDeclarativeAssumes &);
106 void Enter(const parser::OmpBlockConstruct &);
107 void Leave(const parser::OmpBlockConstruct &);
108 void Leave(const parser::OmpBeginDirective &);
109 void Enter(const parser::OmpEndDirective &);
110 void Leave(const parser::OmpEndDirective &);
111
112 void Enter(const parser::OpenMPSectionsConstruct &);
113 void Leave(const parser::OpenMPSectionsConstruct &);
114 void Enter(const parser::OmpEndSectionsDirective &);
115 void Leave(const parser::OmpEndSectionsDirective &);
116
117 void Enter(const parser::OmpDeclareVariantDirective &);
118 void Leave(const parser::OmpDeclareVariantDirective &);
119 void Enter(const parser::OpenMPDeclareSimdConstruct &);
120 void Leave(const parser::OpenMPDeclareSimdConstruct &);
121 void Enter(const parser::OmpAllocateDirective &);
122 void Leave(const parser::OmpAllocateDirective &);
123 void Enter(const parser::OpenMPDeclareMapperConstruct &);
124 void Leave(const parser::OpenMPDeclareMapperConstruct &);
125 void Enter(const parser::OpenMPDeclareReductionConstruct &);
126 void Leave(const parser::OpenMPDeclareReductionConstruct &);
127 void Enter(const parser::OpenMPDeclareTargetConstruct &);
128 void Leave(const parser::OpenMPDeclareTargetConstruct &);
129 void Enter(const parser::OpenMPDepobjConstruct &);
130 void Leave(const parser::OpenMPDepobjConstruct &);
131 void Enter(const parser::OpenMPDispatchConstruct &);
132 void Leave(const parser::OpenMPDispatchConstruct &);
133 void Enter(const parser::OmpErrorDirective &);
134 void Leave(const parser::OmpErrorDirective &);
135 void Enter(const parser::OmpNothingDirective &);
136 void Leave(const parser::OmpNothingDirective &);
137 void Enter(const parser::OpenMPAllocatorsConstruct &);
138 void Leave(const parser::OpenMPAllocatorsConstruct &);
139 void Enter(const parser::OpenMPRequiresConstruct &);
140 void Leave(const parser::OpenMPRequiresConstruct &);
141 void Enter(const parser::OpenMPGroupprivate &);
142 void Leave(const parser::OpenMPGroupprivate &);
143 void Enter(const parser::OpenMPThreadprivate &);
144 void Leave(const parser::OpenMPThreadprivate &);
145
146 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
147 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
148 void Enter(const parser::OpenMPFlushConstruct &);
149 void Leave(const parser::OpenMPFlushConstruct &);
150 void Enter(const parser::OpenMPCancelConstruct &);
151 void Leave(const parser::OpenMPCancelConstruct &);
154 void Enter(const parser::OpenMPCriticalConstruct &);
155 void Leave(const parser::OpenMPCriticalConstruct &);
156 void Enter(const parser::OpenMPAtomicConstruct &);
157 void Leave(const parser::OpenMPAtomicConstruct &);
158
159 void Leave(const parser::OmpClauseList &);
160 void Enter(const parser::OmpClause &);
161
162 void Enter(const parser::DoConstruct &);
163 void Leave(const parser::DoConstruct &);
164
165 void Enter(const parser::OmpDirectiveSpecification &);
166 void Leave(const parser::OmpDirectiveSpecification &);
167
168 void Enter(const parser::OmpMetadirectiveDirective &);
169 void Leave(const parser::OmpMetadirectiveDirective &);
170
171 void Enter(const parser::OmpContextSelector &);
172 void Leave(const parser::OmpContextSelector &);
173
174#define GEN_FLANG_CLAUSE_CHECK_ENTER
175#include "llvm/Frontend/OpenMP/OMP.inc"
176
177private:
178 bool CheckAllowedClause(llvmOmpClause clause);
179 void CheckVariableListItem(const SymbolSourceMap &symbols);
180 void CheckDirectiveSpelling(
181 parser::CharBlock spelling, llvm::omp::Directive id);
182 void AnalyzeObject(const parser::OmpObject &object);
183 void AnalyzeObjects(const parser::OmpObjectList &objects);
184 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
185 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
186 const std::string &clauseName);
187 void CheckMultListItems();
188 void CheckStructureComponent(
189 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
190 bool HasInvalidWorksharingNesting(
191 const parser::CharBlock &, const OmpDirectiveSet &);
192 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
193 bool IsNestedInDirective(llvm::omp::Directive directive);
194 bool InTargetRegion();
195 void HasInvalidTeamsNesting(
196 const llvm::omp::Directive &dir, const parser::CharBlock &source);
197 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
198 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
199 bool HasRequires(llvm::omp::Clause req);
200 // specific clause related
201 void CheckAllowedMapTypes(
202 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
203
204 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
206 std::optional<llvm::omp::Clause> GetClauseFromProperty(
208
209 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
210 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
211 void CheckTraitScore(const parser::OmpTraitScore &);
212 bool VerifyTraitPropertyLists(
214 void CheckTraitSelector(
216 void CheckTraitADMO(
218 void CheckTraitCondition(
220 void CheckTraitDeviceNum(
222 void CheckTraitRequires(
224 void CheckTraitSimd(
226
227 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
228 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
229
230 template < //
231 typename LessTy, typename RangeTy,
232 typename IterTy = decltype(std::declval<RangeTy>().begin())>
233 std::optional<IterTy> FindDuplicate(RangeTy &&);
234
235 void CheckDependList(const parser::DataRef &);
236 void CheckDependArraySection(
238 void CheckDoacross(const parser::OmpDoacross &doa);
239 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
240 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
241 const parser::OmpObject &obj, llvm::StringRef clause = "");
242 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
243 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
244 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
245 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
246 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
247 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
248 void CheckSymbolName(
249 const parser::CharBlock &source, const parser::OmpObject &object);
250 void CheckSymbolNames(
251 const parser::CharBlock &source, const parser::OmpObjectList &objList);
252 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
253 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
254 void CheckCrayPointee(const parser::OmpObjectList &objectList,
255 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
256 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
257 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
258 void CheckCopyingPolymorphicAllocatable(
259 SymbolSourceMap &, const llvm::omp::Clause);
260 void CheckPrivateSymbolsInOuterCxt(
261 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
262 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
263 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
264 void CheckIsLoopIvPartOfClause(
265 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
266 bool CheckTargetBlockOnlyTeams(const parser::Block &);
267 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
268 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
269 void CheckIndividualAllocateDirective(
270 const parser::OmpAllocateDirective &x, bool isExecutable);
271 void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
272
273 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
274 void CheckIteratorModifier(const parser::OmpIterator &x);
275 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
276 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
277 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
278 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
279
280 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
282 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
283 void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
284 std::string_view name, bool checkTypeOnPointer = true);
285 void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
286 parser::CharBlock, bool checkTypeOnPointer = true);
287 std::pair<const parser::ExecutionPartConstruct *,
289 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
291 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
292 const SomeExpr &atom, parser::CharBlock source);
293 void CheckAtomicReadAssignment(
294 const evaluate::Assignment &read, parser::CharBlock source);
295 void CheckAtomicWriteAssignment(
296 const evaluate::Assignment &write, parser::CharBlock source);
297 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
298 const evaluate::Assignment &update, parser::CharBlock source);
299 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
300 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
301 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
302 parser::CharBlock condSource, const evaluate::Assignment &assign,
303 parser::CharBlock assignSource);
304 void CheckAtomicConditionalUpdateStmt(
305 const AnalyzedCondStmt &update, parser::CharBlock source);
306 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
307 const parser::Block &body, parser::CharBlock source);
308 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
309 const parser::Block &body, parser::CharBlock source);
310 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
311 const parser::Block &body, parser::CharBlock source);
312 void CheckAtomicConditionalUpdateCapture(
313 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
314 parser::CharBlock source);
315 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
316 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
317 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
318
319 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
320 void CheckSIMDNest(const parser::OpenMPConstruct &x);
321 void CheckTargetNest(const parser::OpenMPConstruct &x);
322 void CheckTargetUpdate();
323 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
324 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
325 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
326 std::optional<llvm::omp::Directive> GetCancelType(
327 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
328 const std::optional<parser::OmpClauseList> &maybeClauses);
329 void CheckCancellationNest(
330 const parser::CharBlock &source, llvm::omp::Directive type);
331 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
332 void CheckReductionObjects(
333 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
334 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
335 parser::CharBlock source, llvm::omp::Clause clauseId);
336 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
337 const parser::OmpReductionIdentifier &ident);
338 void CheckReductionModifier(const parser::OmpReductionModifier &);
339 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
340 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
341 void ChecksOnOrderedAsBlock();
342 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
343 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
344 void ChecksOnOrderedAsStandalone();
345 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
346 void CheckReductionArraySection(
347 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
348 void CheckArraySection(const parser::ArrayElement &arrayElement,
349 const parser::Name &name, const llvm::omp::Clause clause);
350 void CheckSharedBindingInOuterContext(
351 const parser::OmpObjectList &ompObjectList);
352 void CheckIfContiguous(const parser::OmpObject &object);
353 const parser::Name *GetObjectName(const parser::OmpObject &object);
354
355 void CheckAllowedRequiresClause(llvmOmpClause clause);
356 bool deviceConstructFound_{false};
357
358 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
359
360 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
361 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
362 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
363 inline void ErrIfAllocatableVariable(const parser::Variable &);
364 inline void ErrIfLHSAndRHSSymbolsMatch(
365 const parser::Variable &, const parser::Expr &);
366 inline void ErrIfNonScalarAssignmentStmt(
367 const parser::Variable &, const parser::Expr &);
368 enum directiveNestType : int {
369 SIMDNest,
370 TargetBlockOnlyTeams,
371 TargetNest,
372 DeclarativeNest,
373 ContextSelectorNest,
374 MetadirectiveNest,
375 LastType = MetadirectiveNest,
376 };
377 int directiveNest_[LastType + 1] = {0};
378
379 int allocateDirectiveLevel{0};
380 parser::CharBlock visitedAtomicSource_;
381 SymbolSourceMap deferredNonVariables_;
382
383 using LoopConstruct = std::variant<const parser::DoConstruct *,
385 std::vector<LoopConstruct> loopStack_;
386 // Scopes for scoping units.
387 std::vector<const Scope *> scopeStack_;
388
389 enum class PartKind : int {
390 // There are also other "parts", such as internal-subprogram-part, etc,
391 // but we're keeping track of these two for now.
392 SpecificationPart,
393 ExecutionPart,
394 };
395 std::vector<PartKind> partStack_;
396};
397
400template <typename LessTy, typename RangeTy, typename IterTy>
401std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
402 // Deal with iterators, since the actual elements may be rvalues (i.e.
403 // have no addresses), for example with custom-constructed ranges that
404 // are not simple c.begin()..c.end().
405 std::set<IterTy, LessTy> uniq;
406 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
407 if (!uniq.insert(it).second) {
408 return it;
409 }
410 }
411 return std::nullopt;
412}
413
414} // namespace Fortran::semantics
415#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Definition enum-set.h:28
Definition indirection.h:31
Definition expression.h:878
Definition common.h:214
Definition char-block.h:28
Definition check-directive-structure.h:183
Definition semantics.h:67
Definition FIRType.h:92
Definition parse-tree.h:1915
Definition parse-tree.h:2199
Definition parse-tree.h:3031
Definition parse-tree.h:1822
Definition parse-tree.h:1861
Definition parse-tree.h:2342
Definition parse-tree.h:550
Definition parse-tree.h:1704
Definition parse-tree.h:3153
Definition parse-tree.h:2940
Definition parse-tree.h:2975
Definition parse-tree.h:583
Definition parse-tree.h:5182
Definition parse-tree.h:4976
Definition parse-tree.h:4986
Definition parse-tree.h:4947
Definition parse-tree.h:4931
Definition parse-tree.h:4954
Definition parse-tree.h:4412
Definition parse-tree.h:4981
Definition parse-tree.h:5323
Definition parse-tree.h:5052
Definition parse-tree.h:5014
Definition parse-tree.h:4999
Definition parse-tree.h:5008
Definition parse-tree.h:3541
Definition parse-tree.h:3529
Definition parse-tree.h:3585
Definition parse-tree.h:5208
Definition parse-tree.h:5041
Definition parse-tree.h:5213
Definition parse-tree.h:5250
Definition parse-tree.h:5353
Definition parse-tree.h:5198
Definition parse-tree.h:5029
Definition parse-tree.h:5261
Definition parse-tree.h:5275
Definition parse-tree.h:5291
Definition parse-tree.h:5137
Definition parse-tree.h:5299
Definition parse-tree.h:5330
Definition parse-tree.h:5143
Definition parse-tree.h:5067
Definition parse-tree.h:5149
Definition parse-tree.h:448
Definition parse-tree.h:3017
Definition parse-tree.h:3172
Definition parse-tree.h:1869
Definition parse-tree.h:4029
Definition parse-tree.h:4039
Definition parse-tree.h:4047
Definition parse-tree.h:4147
Definition parse-tree.h:3731
Definition parse-tree.h:3697
Definition parse-tree.h:3770
Definition parse-tree.h:3792
Definition check-omp-atomic.cpp:240