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#include "llvm/Frontend/OpenMP/OMPConstants.h"
23
24using OmpClauseSet =
26
27#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
28#include "llvm/Frontend/OpenMP/OMP.inc"
29
30namespace llvm {
31namespace omp {
32static OmpClauseSet privateSet{
33 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
34static OmpClauseSet privateReductionSet{
35 OmpClauseSet{Clause::OMPC_reduction} | privateSet};
36// omp.td cannot differentiate allowed/not allowed clause list for few
37// directives for fortran. nowait is not allowed on begin directive clause list
38// for below list of directives. Directives with conflicting list of clauses are
39// included in below list.
40static const OmpDirectiveSet noWaitClauseNotAllowedSet{
41 Directive::OMPD_do,
42 Directive::OMPD_do_simd,
43 Directive::OMPD_sections,
44 Directive::OMPD_single,
45 Directive::OMPD_workshare,
46};
47} // namespace omp
48} // namespace llvm
49
50namespace Fortran::semantics {
51struct AnalyzedCondStmt;
52
53// Mapping from 'Symbol' to 'Source' to keep track of the variables
54// used in multiple clauses
55using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
56// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
57using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
58 std::pair<llvm::omp::Directive, const OmpClauseSet>>;
59
60class OmpStructureChecker
61 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
62 parser::OmpClause, llvm::omp::Clause_enumSize> {
63public:
64 using Base = DirectiveStructureChecker<llvm::omp::Directive,
65 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
66
67 OmpStructureChecker(SemanticsContext &context)
68 : DirectiveStructureChecker(context,
69#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
70#include "llvm/Frontend/OpenMP/OMP.inc"
71 ) {
72 }
73 using llvmOmpClause = const llvm::omp::Clause;
74
75 void Enter(const parser::OpenMPConstruct &);
76 void Leave(const parser::OpenMPConstruct &);
77 void Enter(const parser::OpenMPInteropConstruct &);
78 void Leave(const parser::OpenMPInteropConstruct &);
79 void Enter(const parser::OpenMPDeclarativeConstruct &);
80 void Leave(const parser::OpenMPDeclarativeConstruct &);
81
82 void Enter(const parser::OpenMPLoopConstruct &);
83 void Leave(const parser::OpenMPLoopConstruct &);
84 void Enter(const parser::OmpEndLoopDirective &);
85 void Leave(const parser::OmpEndLoopDirective &);
86
87 void Enter(const parser::OpenMPAssumeConstruct &);
88 void Leave(const parser::OpenMPAssumeConstruct &);
89 void Enter(const parser::OpenMPDeclarativeAssumes &);
90 void Leave(const parser::OpenMPDeclarativeAssumes &);
91 void Enter(const parser::OmpBlockConstruct &);
92 void Leave(const parser::OmpBlockConstruct &);
93 void Leave(const parser::OmpBeginDirective &);
94 void Enter(const parser::OmpEndDirective &);
95 void Leave(const parser::OmpEndDirective &);
96
97 void Enter(const parser::OpenMPSectionsConstruct &);
98 void Leave(const parser::OpenMPSectionsConstruct &);
99 void Enter(const parser::OmpEndSectionsDirective &);
100 void Leave(const parser::OmpEndSectionsDirective &);
101
102 void Enter(const parser::OmpDeclareVariantDirective &);
103 void Leave(const parser::OmpDeclareVariantDirective &);
104 void Enter(const parser::OpenMPDeclareSimdConstruct &);
105 void Leave(const parser::OpenMPDeclareSimdConstruct &);
106 void Enter(const parser::OpenMPDeclarativeAllocate &);
107 void Leave(const parser::OpenMPDeclarativeAllocate &);
108 void Enter(const parser::OpenMPDeclareMapperConstruct &);
109 void Leave(const parser::OpenMPDeclareMapperConstruct &);
110 void Enter(const parser::OpenMPDeclareReductionConstruct &);
111 void Leave(const parser::OpenMPDeclareReductionConstruct &);
112 void Enter(const parser::OpenMPDeclareTargetConstruct &);
113 void Leave(const parser::OpenMPDeclareTargetConstruct &);
114 void Enter(const parser::OpenMPDepobjConstruct &);
115 void Leave(const parser::OpenMPDepobjConstruct &);
116 void Enter(const parser::OmpDeclareTargetWithList &);
117 void Enter(const parser::OmpDeclareTargetWithClause &);
118 void Leave(const parser::OmpDeclareTargetWithClause &);
119 void Enter(const parser::OpenMPDispatchConstruct &);
120 void Leave(const parser::OpenMPDispatchConstruct &);
121 void Enter(const parser::OmpErrorDirective &);
122 void Leave(const parser::OmpErrorDirective &);
123 void Enter(const parser::OpenMPExecutableAllocate &);
124 void Leave(const parser::OpenMPExecutableAllocate &);
125 void Enter(const parser::OpenMPAllocatorsConstruct &);
126 void Leave(const parser::OpenMPAllocatorsConstruct &);
127 void Enter(const parser::OpenMPRequiresConstruct &);
128 void Leave(const parser::OpenMPRequiresConstruct &);
129 void Enter(const parser::OpenMPGroupprivate &);
130 void Leave(const parser::OpenMPGroupprivate &);
131 void Enter(const parser::OpenMPThreadprivate &);
132 void Leave(const parser::OpenMPThreadprivate &);
133
134 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
135 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
136 void Enter(const parser::OpenMPFlushConstruct &);
137 void Leave(const parser::OpenMPFlushConstruct &);
138 void Enter(const parser::OpenMPCancelConstruct &);
139 void Leave(const parser::OpenMPCancelConstruct &);
142 void Enter(const parser::OpenMPCriticalConstruct &);
143 void Leave(const parser::OpenMPCriticalConstruct &);
144 void Enter(const parser::OpenMPAtomicConstruct &);
145 void Leave(const parser::OpenMPAtomicConstruct &);
146
147 void Leave(const parser::OmpClauseList &);
148 void Enter(const parser::OmpClause &);
149
150 void Enter(const parser::DoConstruct &);
151 void Leave(const parser::DoConstruct &);
152
153 void Enter(const parser::OmpDirectiveSpecification &);
154 void Leave(const parser::OmpDirectiveSpecification &);
155
156 void Enter(const parser::OmpMetadirectiveDirective &);
157 void Leave(const parser::OmpMetadirectiveDirective &);
158
159 void Enter(const parser::OmpContextSelector &);
160 void Leave(const parser::OmpContextSelector &);
161
162#define GEN_FLANG_CLAUSE_CHECK_ENTER
163#include "llvm/Frontend/OpenMP/OMP.inc"
164
165private:
166 bool CheckAllowedClause(llvmOmpClause clause);
167 void CheckVariableListItem(const SymbolSourceMap &symbols);
168 void CheckDirectiveSpelling(
169 parser::CharBlock spelling, llvm::omp::Directive id);
170 void AnalyzeObject(const parser::OmpObject &object);
171 void AnalyzeObjects(const parser::OmpObjectList &objects);
172 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
173 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
174 const std::string &clauseName);
175 void CheckMultListItems();
176 void CheckStructureComponent(
177 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
178 bool HasInvalidWorksharingNesting(
179 const parser::CharBlock &, const OmpDirectiveSet &);
180 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
181 void HasInvalidTeamsNesting(
182 const llvm::omp::Directive &dir, const parser::CharBlock &source);
183 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
184 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
185 // specific clause related
186 void CheckAllowedMapTypes(
187 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
188
189 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
191 std::optional<llvm::omp::Clause> GetClauseFromProperty(
193
194 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
195 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
196 void CheckTraitScore(const parser::OmpTraitScore &);
197 bool VerifyTraitPropertyLists(
199 void CheckTraitSelector(
201 void CheckTraitADMO(
203 void CheckTraitCondition(
205 void CheckTraitDeviceNum(
207 void CheckTraitRequires(
209 void CheckTraitSimd(
211
212 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
213 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
214
215 template < //
216 typename LessTy, typename RangeTy,
217 typename IterTy = decltype(std::declval<RangeTy>().begin())>
218 std::optional<IterTy> FindDuplicate(RangeTy &&);
219
220 void CheckDependList(const parser::DataRef &);
221 void CheckDependArraySection(
223 void CheckDoacross(const parser::OmpDoacross &doa);
224 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
225 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
226 const parser::OmpObject &obj, llvm::StringRef clause = "");
227 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
228 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
229 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
230 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
231 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
232 void CheckSymbolNames(
233 const parser::CharBlock &source, const parser::OmpObjectList &objList);
234 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
235 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
236 void CheckCrayPointee(const parser::OmpObjectList &objectList,
237 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
238 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
239 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
240 void CheckCopyingPolymorphicAllocatable(
241 SymbolSourceMap &, const llvm::omp::Clause);
242 void CheckPrivateSymbolsInOuterCxt(
243 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
244 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
245 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
246 void CheckIsLoopIvPartOfClause(
247 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
248 bool CheckTargetBlockOnlyTeams(const parser::Block &);
249 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
250 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
251
252 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
253 void CheckIteratorModifier(const parser::OmpIterator &x);
254 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
255 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
256 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
257 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
258
259 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
261 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
262 void CheckAtomicType(
263 SymbolRef sym, parser::CharBlock source, std::string_view name);
264 void CheckAtomicVariable(
266 std::pair<const parser::ExecutionPartConstruct *,
268 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
270 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
271 const SomeExpr &atom, parser::CharBlock source);
272 void CheckAtomicReadAssignment(
273 const evaluate::Assignment &read, parser::CharBlock source);
274 void CheckAtomicWriteAssignment(
275 const evaluate::Assignment &write, parser::CharBlock source);
276 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
277 const evaluate::Assignment &update, parser::CharBlock source);
278 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
279 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
280 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
281 parser::CharBlock condSource, const evaluate::Assignment &assign,
282 parser::CharBlock assignSource);
283 void CheckAtomicConditionalUpdateStmt(
284 const AnalyzedCondStmt &update, parser::CharBlock source);
285 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
286 const parser::Block &body, parser::CharBlock source);
287 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
288 const parser::Block &body, parser::CharBlock source);
289 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
290 const parser::Block &body, parser::CharBlock source);
291 void CheckAtomicConditionalUpdateCapture(
292 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
293 parser::CharBlock source);
294 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
295 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
296 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
297
298 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
299 void CheckSIMDNest(const parser::OpenMPConstruct &x);
300 void CheckTargetNest(const parser::OpenMPConstruct &x);
301 void CheckTargetUpdate();
302 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
303 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
304 std::optional<llvm::omp::Directive> GetCancelType(
305 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
306 const std::optional<parser::OmpClauseList> &maybeClauses);
307 void CheckCancellationNest(
308 const parser::CharBlock &source, llvm::omp::Directive type);
309 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
310 void CheckReductionObjects(
311 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
312 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
313 parser::CharBlock source, llvm::omp::Clause clauseId);
314 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
315 const parser::OmpReductionIdentifier &ident);
316 void CheckReductionModifier(const parser::OmpReductionModifier &);
317 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
318 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
319 void ChecksOnOrderedAsBlock();
320 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
321 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
322 void ChecksOnOrderedAsStandalone();
323 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
324 void CheckReductionArraySection(
325 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
326 void CheckArraySection(const parser::ArrayElement &arrayElement,
327 const parser::Name &name, const llvm::omp::Clause clause);
328 void CheckSharedBindingInOuterContext(
329 const parser::OmpObjectList &ompObjectList);
330 void CheckIfContiguous(const parser::OmpObject &object);
331 const parser::Name *GetObjectName(const parser::OmpObject &object);
332 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
333 const parser::OmpObjectList &ompObjectList);
334 void CheckPredefinedAllocatorRestriction(
335 const parser::CharBlock &source, const parser::Name &name);
336 bool isPredefinedAllocator{false};
337
338 void CheckAllowedRequiresClause(llvmOmpClause clause);
339 bool deviceConstructFound_{false};
340
341 void CheckAlignValue(const parser::OmpClause &);
342
343 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
344
345 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
346 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
347 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
348 inline void ErrIfAllocatableVariable(const parser::Variable &);
349 inline void ErrIfLHSAndRHSSymbolsMatch(
350 const parser::Variable &, const parser::Expr &);
351 inline void ErrIfNonScalarAssignmentStmt(
352 const parser::Variable &, const parser::Expr &);
353 enum directiveNestType : int {
354 SIMDNest,
355 TargetBlockOnlyTeams,
356 TargetNest,
357 DeclarativeNest,
358 ContextSelectorNest,
359 MetadirectiveNest,
360 LastType = MetadirectiveNest,
361 };
362 int directiveNest_[LastType + 1] = {0};
363
364 parser::CharBlock visitedAtomicSource_;
365 SymbolSourceMap deferredNonVariables_;
366
367 using LoopConstruct = std::variant<const parser::DoConstruct *,
369 std::vector<LoopConstruct> loopStack_;
370};
371
374template <typename LessTy, typename RangeTy, typename IterTy>
375std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
376 // Deal with iterators, since the actual elements may be rvalues (i.e.
377 // have no addresses), for example with custom-constructed ranges that
378 // are not simple c.begin()..c.end().
379 std::set<IterTy, LessTy> uniq;
380 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
381 if (!uniq.insert(it).second) {
382 return it;
383 }
384 }
385 return std::nullopt;
386}
387
388} // namespace Fortran::semantics
389#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 semantics.h:67
Definition FIRType.h:89
Definition parse-tree.h:1911
Definition parse-tree.h:1818
Definition parse-tree.h:1857
Definition parse-tree.h:2338
Definition parse-tree.h:547
Definition parse-tree.h:1700
Definition parse-tree.h:580
Definition parse-tree.h:4806
Definition parse-tree.h:4816
Definition parse-tree.h:4777
Definition parse-tree.h:4761
Definition parse-tree.h:4931
Definition parse-tree.h:4784
Definition parse-tree.h:4313
Definition parse-tree.h:4811
Definition parse-tree.h:5167
Definition parse-tree.h:4892
Definition parse-tree.h:4847
Definition parse-tree.h:4829
Definition parse-tree.h:3507
Definition parse-tree.h:3521
Definition parse-tree.h:5044
Definition parse-tree.h:4876
Definition parse-tree.h:5049
Definition parse-tree.h:5092
Definition parse-tree.h:5192
Definition parse-tree.h:5021
Definition parse-tree.h:5003
Definition parse-tree.h:4864
Definition parse-tree.h:5103
Definition parse-tree.h:5117
Definition parse-tree.h:5029
Definition parse-tree.h:5133
Definition parse-tree.h:4983
Definition parse-tree.h:5141
Definition parse-tree.h:5176
Definition parse-tree.h:4989
Definition parse-tree.h:4909
Definition parse-tree.h:4996
Definition parse-tree.h:1865
Definition parse-tree.h:3932
Definition parse-tree.h:3942
Definition parse-tree.h:3950
Definition parse-tree.h:4050
Definition parse-tree.h:3646
Definition parse-tree.h:3612
Definition parse-tree.h:3685
Definition parse-tree.h:3707
Definition check-omp-atomic.cpp:240