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::OpenMPMisplacedEndDirective &);
98 void Leave(const parser::OpenMPMisplacedEndDirective &);
99 void Enter(const parser::OpenMPInvalidDirective &);
100 void Leave(const parser::OpenMPInvalidDirective &);
101
102 void Enter(const parser::OpenMPLoopConstruct &);
103 void Leave(const parser::OpenMPLoopConstruct &);
104 void Enter(const parser::OmpEndLoopDirective &);
105 void Leave(const parser::OmpEndLoopDirective &);
106
107 void Enter(const parser::OpenMPAssumeConstruct &);
108 void Leave(const parser::OpenMPAssumeConstruct &);
109 void Enter(const parser::OpenMPDeclarativeAssumes &);
110 void Leave(const parser::OpenMPDeclarativeAssumes &);
111 void Enter(const parser::OmpBlockConstruct &);
112 void Leave(const parser::OmpBlockConstruct &);
113 void Leave(const parser::OmpBeginDirective &);
114 void Enter(const parser::OmpEndDirective &);
115 void Leave(const parser::OmpEndDirective &);
116
117 void Enter(const parser::OpenMPSectionsConstruct &);
118 void Leave(const parser::OpenMPSectionsConstruct &);
119 void Enter(const parser::OmpEndSectionsDirective &);
120 void Leave(const parser::OmpEndSectionsDirective &);
121
122 void Enter(const parser::OmpDeclareVariantDirective &);
123 void Leave(const parser::OmpDeclareVariantDirective &);
124 void Enter(const parser::OpenMPDeclareSimdConstruct &);
125 void Leave(const parser::OpenMPDeclareSimdConstruct &);
126 void Enter(const parser::OmpAllocateDirective &);
127 void Leave(const parser::OmpAllocateDirective &);
128 void Enter(const parser::OpenMPDeclareMapperConstruct &);
129 void Leave(const parser::OpenMPDeclareMapperConstruct &);
130 void Enter(const parser::OpenMPDeclareReductionConstruct &);
131 void Leave(const parser::OpenMPDeclareReductionConstruct &);
132 void Enter(const parser::OpenMPDeclareTargetConstruct &);
133 void Leave(const parser::OpenMPDeclareTargetConstruct &);
134 void Enter(const parser::OpenMPDepobjConstruct &);
135 void Leave(const parser::OpenMPDepobjConstruct &);
136 void Enter(const parser::OpenMPDispatchConstruct &);
137 void Leave(const parser::OpenMPDispatchConstruct &);
138 void Enter(const parser::OmpErrorDirective &);
139 void Leave(const parser::OmpErrorDirective &);
140 void Enter(const parser::OmpNothingDirective &);
141 void Leave(const parser::OmpNothingDirective &);
142 void Enter(const parser::OpenMPAllocatorsConstruct &);
143 void Leave(const parser::OpenMPAllocatorsConstruct &);
144 void Enter(const parser::OpenMPRequiresConstruct &);
145 void Leave(const parser::OpenMPRequiresConstruct &);
146 void Enter(const parser::OpenMPGroupprivate &);
147 void Leave(const parser::OpenMPGroupprivate &);
148 void Enter(const parser::OpenMPThreadprivate &);
149 void Leave(const parser::OpenMPThreadprivate &);
150
151 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
152 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
153 void Enter(const parser::OpenMPFlushConstruct &);
154 void Leave(const parser::OpenMPFlushConstruct &);
155 void Enter(const parser::OpenMPCancelConstruct &);
156 void Leave(const parser::OpenMPCancelConstruct &);
159 void Enter(const parser::OpenMPCriticalConstruct &);
160 void Leave(const parser::OpenMPCriticalConstruct &);
161 void Enter(const parser::OpenMPAtomicConstruct &);
162 void Leave(const parser::OpenMPAtomicConstruct &);
163
164 void Leave(const parser::OmpClauseList &);
165 void Enter(const parser::OmpClause &);
166
167 void Enter(const parser::DoConstruct &);
168 void Leave(const parser::DoConstruct &);
169
170 void Enter(const parser::OmpDirectiveSpecification &);
171 void Leave(const parser::OmpDirectiveSpecification &);
172
173 void Enter(const parser::OmpMetadirectiveDirective &);
174 void Leave(const parser::OmpMetadirectiveDirective &);
175
176 void Enter(const parser::OmpContextSelector &);
177 void Leave(const parser::OmpContextSelector &);
178
179#define GEN_FLANG_CLAUSE_CHECK_ENTER
180#include "llvm/Frontend/OpenMP/OMP.inc"
181
182private:
183 bool CheckAllowedClause(llvmOmpClause clause);
184 void CheckVariableListItem(const SymbolSourceMap &symbols);
185 void CheckDirectiveSpelling(
186 parser::CharBlock spelling, llvm::omp::Directive id);
187 void AnalyzeObject(const parser::OmpObject &object);
188 void AnalyzeObjects(const parser::OmpObjectList &objects);
189 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
190 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
191 const std::string &clauseName);
192 void CheckMultListItems();
193 void CheckStructureComponent(
194 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
195 bool HasInvalidWorksharingNesting(
196 const parser::OmpDirectiveName &name, const OmpDirectiveSet &);
197
198 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
199 bool IsNestedInDirective(llvm::omp::Directive directive);
200 bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const;
201 bool InTargetRegion();
202 void HasInvalidTeamsNesting(
203 const llvm::omp::Directive &dir, const parser::CharBlock &source);
204 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
205 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
206 bool HasRequires(llvm::omp::Clause req);
207 // specific clause related
208 void CheckAllowedMapTypes(
209 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
210
211 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
213 std::optional<llvm::omp::Clause> GetClauseFromProperty(
215
216 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
217 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
218 void CheckTraitScore(const parser::OmpTraitScore &);
219 bool VerifyTraitPropertyLists(
221 void CheckTraitSelector(
223 void CheckTraitADMO(
225 void CheckTraitCondition(
227 void CheckTraitDeviceNum(
229 void CheckTraitRequires(
231 void CheckTraitSimd(
233
234 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
235 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
236
237 template < //
238 typename LessTy, typename RangeTy,
239 typename IterTy = decltype(std::declval<RangeTy>().begin())>
240 std::optional<IterTy> FindDuplicate(RangeTy &&);
241
242 void CheckDependList(const parser::DataRef &);
243 void CheckDependArraySection(
245 void CheckDoacross(const parser::OmpDoacross &doa);
246 void CheckDimsModifier(parser::CharBlock source, size_t numValues,
247 const parser::OmpDimsModifier &x);
248 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
249 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
250 const parser::OmpObject &obj, llvm::StringRef clause = "");
251 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
252 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
253 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
254 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
255 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
256 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
257 void CheckSymbolName(
258 const parser::CharBlock &source, const parser::OmpObject &object);
259 void CheckSymbolNames(
260 const parser::CharBlock &source, const parser::OmpObjectList &objList);
261 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
262 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
263 void CheckCrayPointee(const parser::OmpObjectList &objectList,
264 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
265 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
266 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
267 void CheckCopyingPolymorphicAllocatable(
268 SymbolSourceMap &, const llvm::omp::Clause);
269 void CheckPrivateSymbolsInOuterCxt(
270 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
271 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
272 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
273 void CheckIsLoopIvPartOfClause(
274 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
275 bool CheckTargetBlockOnlyTeams(const parser::Block &);
276 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
277 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
278 void CheckIndividualAllocateDirective(
279 const parser::OmpAllocateDirective &x, bool isExecutable);
280 void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
281
282 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
283 void CheckIteratorModifier(const parser::OmpIterator &x);
284 void CheckIterationVariableType(const parser::OpenMPLoopConstruct &x);
285 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
286 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
287 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
288
289 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
291 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
292 void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
293 std::string_view name, bool checkTypeOnPointer = true);
294 void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
295 parser::CharBlock, bool checkTypeOnPointer = true);
296 std::pair<const parser::ExecutionPartConstruct *,
298 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
300 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
301 const SomeExpr &atom, parser::CharBlock source);
302 void CheckAtomicReadAssignment(
303 const evaluate::Assignment &read, parser::CharBlock source);
304 void CheckAtomicWriteAssignment(
305 const evaluate::Assignment &write, parser::CharBlock source);
306 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
307 const evaluate::Assignment &update, parser::CharBlock source);
308 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
309 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
310 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
311 parser::CharBlock condSource, const evaluate::Assignment &assign,
312 parser::CharBlock assignSource);
313 void CheckAtomicConditionalUpdateStmt(
314 const AnalyzedCondStmt &update, parser::CharBlock source);
315 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
316 const parser::Block &body, parser::CharBlock source);
317 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
318 const parser::Block &body, parser::CharBlock source);
319 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
320 const parser::Block &body, parser::CharBlock source);
321 void CheckAtomicConditionalUpdateCapture(
322 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
323 parser::CharBlock source);
324 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
325 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
326 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
327
328 void CheckScanModifier(const parser::OmpClause::Reduction &x);
329 void CheckLooprangeBounds(const parser::OpenMPLoopConstruct &x);
330 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
331 void CheckSIMDNest(const parser::OpenMPConstruct &x);
332 void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
333 void CheckTargetNest(const parser::OpenMPConstruct &x);
334 void CheckTargetUpdate();
335 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
336 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
337 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
338 std::optional<llvm::omp::Directive> GetCancelType(
339 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
340 const std::optional<parser::OmpClauseList> &maybeClauses);
341 void CheckCancellationNest(
342 const parser::CharBlock &source, llvm::omp::Directive type);
343 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
344 void CheckReductionObjects(
345 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
346 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
347 parser::CharBlock source, llvm::omp::Clause clauseId);
348 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
349 const parser::OmpReductionIdentifier &ident);
350 void CheckReductionModifier(const parser::OmpReductionModifier &);
351 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
352 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
353 void ChecksOnOrderedAsBlock();
354 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
355 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
356 void ChecksOnOrderedAsStandalone();
357 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
358 void CheckReductionArraySection(
359 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
360 void CheckArraySection(const parser::ArrayElement &arrayElement,
361 const parser::Name &name, const llvm::omp::Clause clause);
362 void CheckSharedBindingInOuterContext(
363 const parser::OmpObjectList &ompObjectList);
364 void CheckIfContiguous(const parser::OmpObject &object);
365 const parser::Name *GetObjectName(const parser::OmpObject &object);
366 void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj,
367 const parser::OmpClause &initClause);
368
369 void CheckAllowedRequiresClause(llvmOmpClause clause);
370 bool deviceConstructFound_{false};
371
372 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
373
374 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
375 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
376 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
377 inline void ErrIfAllocatableVariable(const parser::Variable &);
378 inline void ErrIfLHSAndRHSSymbolsMatch(
379 const parser::Variable &, const parser::Expr &);
380 inline void ErrIfNonScalarAssignmentStmt(
381 const parser::Variable &, const parser::Expr &);
382 enum directiveNestType : int {
383 SIMDNest,
384 TargetBlockOnlyTeams,
385 TargetNest,
386 DeclarativeNest,
387 ContextSelectorNest,
388 MetadirectiveNest,
389 LastType = MetadirectiveNest,
390 };
391 int directiveNest_[LastType + 1] = {0};
392
393 int allocateDirectiveLevel{0};
394 parser::CharBlock visitedAtomicSource_;
395 SymbolSourceMap deferredNonVariables_;
396
397 using LoopConstruct = std::variant<const parser::DoConstruct *,
399 std::vector<LoopConstruct> loopStack_;
400 // Scopes for scoping units.
401 std::vector<const Scope *> scopeStack_;
402
403 enum class PartKind : int {
404 // There are also other "parts", such as internal-subprogram-part, etc,
405 // but we're keeping track of these two for now.
406 SpecificationPart,
407 ExecutionPart,
408 };
409 std::vector<PartKind> partStack_;
410};
411
414template <typename LessTy, typename RangeTy, typename IterTy>
415std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
416 // Deal with iterators, since the actual elements may be rvalues (i.e.
417 // have no addresses), for example with custom-constructed ranges that
418 // are not simple c.begin()..c.end().
419 std::set<IterTy, LessTy> uniq;
420 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
421 if (!uniq.insert(it).second) {
422 return it;
423 }
424 }
425 return std::nullopt;
426}
427
428} // namespace Fortran::semantics
429#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:1884
Definition parse-tree.h:2168
Definition parse-tree.h:3000
Definition parse-tree.h:1794
Definition parse-tree.h:1833
Definition parse-tree.h:2311
Definition parse-tree.h:554
Definition parse-tree.h:1682
Definition parse-tree.h:3119
Definition parse-tree.h:2909
Definition parse-tree.h:2944
Definition parse-tree.h:587
Definition parse-tree.h:5260
Definition parse-tree.h:5054
Definition parse-tree.h:5064
Definition parse-tree.h:5023
Definition parse-tree.h:5007
Definition parse-tree.h:3474
Definition parse-tree.h:5030
Definition parse-tree.h:4454
Definition parse-tree.h:5059
Definition parse-tree.h:5401
Definition parse-tree.h:5130
Definition parse-tree.h:5092
Definition parse-tree.h:5077
Definition parse-tree.h:5086
Definition parse-tree.h:3519
Definition parse-tree.h:3507
Definition parse-tree.h:3563
Definition parse-tree.h:5286
Definition parse-tree.h:5119
Definition parse-tree.h:5291
Definition parse-tree.h:5328
Definition parse-tree.h:5432
Definition parse-tree.h:5276
Definition parse-tree.h:5107
Definition parse-tree.h:5339
Definition parse-tree.h:5353
Definition parse-tree.h:5369
Definition parse-tree.h:5215
Definition parse-tree.h:5377
Definition parse-tree.h:5450
Definition parse-tree.h:5406
Definition parse-tree.h:5221
Definition parse-tree.h:5145
Definition parse-tree.h:5227
Definition parse-tree.h:451
Definition parse-tree.h:2986
Definition parse-tree.h:3138
Definition parse-tree.h:1841
Definition parse-tree.h:3956
Definition parse-tree.h:4022
Definition parse-tree.h:4032
Definition parse-tree.h:4040
Definition parse-tree.h:4181
Definition parse-tree.h:3709
Definition parse-tree.h:3675
Definition parse-tree.h:3748
Definition parse-tree.h:3770
Definition check-omp-atomic.cpp:242