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::OpenMPDispatchConstruct &);
117 void Leave(const parser::OpenMPDispatchConstruct &);
118 void Enter(const parser::OmpErrorDirective &);
119 void Leave(const parser::OmpErrorDirective &);
120 void Enter(const parser::OmpNothingDirective &);
121 void Leave(const parser::OmpNothingDirective &);
122 void Enter(const parser::OpenMPExecutableAllocate &);
123 void Leave(const parser::OpenMPExecutableAllocate &);
124 void Enter(const parser::OpenMPAllocatorsConstruct &);
125 void Leave(const parser::OpenMPAllocatorsConstruct &);
126 void Enter(const parser::OpenMPRequiresConstruct &);
127 void Leave(const parser::OpenMPRequiresConstruct &);
128 void Enter(const parser::OpenMPGroupprivate &);
129 void Leave(const parser::OpenMPGroupprivate &);
130 void Enter(const parser::OpenMPThreadprivate &);
131 void Leave(const parser::OpenMPThreadprivate &);
132
133 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
134 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
135 void Enter(const parser::OpenMPFlushConstruct &);
136 void Leave(const parser::OpenMPFlushConstruct &);
137 void Enter(const parser::OpenMPCancelConstruct &);
138 void Leave(const parser::OpenMPCancelConstruct &);
141 void Enter(const parser::OpenMPCriticalConstruct &);
142 void Leave(const parser::OpenMPCriticalConstruct &);
143 void Enter(const parser::OpenMPAtomicConstruct &);
144 void Leave(const parser::OpenMPAtomicConstruct &);
145
146 void Leave(const parser::OmpClauseList &);
147 void Enter(const parser::OmpClause &);
148
149 void Enter(const parser::DoConstruct &);
150 void Leave(const parser::DoConstruct &);
151
152 void Enter(const parser::OmpDirectiveSpecification &);
153 void Leave(const parser::OmpDirectiveSpecification &);
154
155 void Enter(const parser::OmpMetadirectiveDirective &);
156 void Leave(const parser::OmpMetadirectiveDirective &);
157
158 void Enter(const parser::OmpContextSelector &);
159 void Leave(const parser::OmpContextSelector &);
160
161#define GEN_FLANG_CLAUSE_CHECK_ENTER
162#include "llvm/Frontend/OpenMP/OMP.inc"
163
164private:
165 bool CheckAllowedClause(llvmOmpClause clause);
166 void CheckVariableListItem(const SymbolSourceMap &symbols);
167 void CheckDirectiveSpelling(
168 parser::CharBlock spelling, llvm::omp::Directive id);
169 void AnalyzeObject(const parser::OmpObject &object);
170 void AnalyzeObjects(const parser::OmpObjectList &objects);
171 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
172 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
173 const std::string &clauseName);
174 void CheckMultListItems();
175 void CheckStructureComponent(
176 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
177 bool HasInvalidWorksharingNesting(
178 const parser::CharBlock &, const OmpDirectiveSet &);
179 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
180 bool IsNestedInDirective(llvm::omp::Directive directive);
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::OmpObject &);
232 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
233 void CheckSymbolName(
234 const parser::CharBlock &source, const parser::OmpObject &object);
235 void CheckSymbolNames(
236 const parser::CharBlock &source, const parser::OmpObjectList &objList);
237 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
238 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
239 void CheckCrayPointee(const parser::OmpObjectList &objectList,
240 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
241 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
242 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
243 void CheckCopyingPolymorphicAllocatable(
244 SymbolSourceMap &, const llvm::omp::Clause);
245 void CheckPrivateSymbolsInOuterCxt(
246 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
247 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
248 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
249 void CheckIsLoopIvPartOfClause(
250 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
251 bool CheckTargetBlockOnlyTeams(const parser::Block &);
252 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
253 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
254
255 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
256 void CheckIteratorModifier(const parser::OmpIterator &x);
257 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
258 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
259 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
260 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
261
262 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
264 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
265 void CheckAtomicType(
266 SymbolRef sym, parser::CharBlock source, std::string_view name);
267 void CheckAtomicVariable(
269 std::pair<const parser::ExecutionPartConstruct *,
271 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
273 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
274 const SomeExpr &atom, parser::CharBlock source);
275 void CheckAtomicReadAssignment(
276 const evaluate::Assignment &read, parser::CharBlock source);
277 void CheckAtomicWriteAssignment(
278 const evaluate::Assignment &write, parser::CharBlock source);
279 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
280 const evaluate::Assignment &update, parser::CharBlock source);
281 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
282 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
283 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
284 parser::CharBlock condSource, const evaluate::Assignment &assign,
285 parser::CharBlock assignSource);
286 void CheckAtomicConditionalUpdateStmt(
287 const AnalyzedCondStmt &update, parser::CharBlock source);
288 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
289 const parser::Block &body, parser::CharBlock source);
290 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
291 const parser::Block &body, parser::CharBlock source);
292 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
293 const parser::Block &body, parser::CharBlock source);
294 void CheckAtomicConditionalUpdateCapture(
295 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
296 parser::CharBlock source);
297 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
298 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
299 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
300
301 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
302 void CheckSIMDNest(const parser::OpenMPConstruct &x);
303 void CheckTargetNest(const parser::OpenMPConstruct &x);
304 void CheckTargetUpdate();
305 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
306 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
307 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
308 std::optional<llvm::omp::Directive> GetCancelType(
309 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
310 const std::optional<parser::OmpClauseList> &maybeClauses);
311 void CheckCancellationNest(
312 const parser::CharBlock &source, llvm::omp::Directive type);
313 void CheckAllNamesInAllocateStmt(const parser::CharBlock &source,
314 const parser::OmpObjectList &ompObjectList,
315 const parser::AllocateStmt &allocate);
316 void CheckNameInAllocateStmt(const parser::CharBlock &source,
317 const parser::Name &ompObject, const parser::AllocateStmt &allocate);
318 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
319 void CheckReductionObjects(
320 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
321 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
322 parser::CharBlock source, llvm::omp::Clause clauseId);
323 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
324 const parser::OmpReductionIdentifier &ident);
325 void CheckReductionModifier(const parser::OmpReductionModifier &);
326 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
327 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
328 void ChecksOnOrderedAsBlock();
329 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
330 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
331 void ChecksOnOrderedAsStandalone();
332 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
333 void CheckReductionArraySection(
334 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
335 void CheckArraySection(const parser::ArrayElement &arrayElement,
336 const parser::Name &name, const llvm::omp::Clause clause);
337 void CheckSharedBindingInOuterContext(
338 const parser::OmpObjectList &ompObjectList);
339 void CheckIfContiguous(const parser::OmpObject &object);
340 const parser::Name *GetObjectName(const parser::OmpObject &object);
341 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
342 const parser::OmpObjectList &ompObjectList);
343 void CheckPredefinedAllocatorRestriction(
344 const parser::CharBlock &source, const parser::Name &name);
345 bool isPredefinedAllocator{false};
346
347 void CheckAllowedRequiresClause(llvmOmpClause clause);
348 bool deviceConstructFound_{false};
349
350 void CheckAlignValue(const parser::OmpClause &);
351
352 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
353
354 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
355 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
356 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
357 inline void ErrIfAllocatableVariable(const parser::Variable &);
358 inline void ErrIfLHSAndRHSSymbolsMatch(
359 const parser::Variable &, const parser::Expr &);
360 inline void ErrIfNonScalarAssignmentStmt(
361 const parser::Variable &, const parser::Expr &);
362 enum directiveNestType : int {
363 SIMDNest,
364 TargetBlockOnlyTeams,
365 TargetNest,
366 DeclarativeNest,
367 ContextSelectorNest,
368 MetadirectiveNest,
369 LastType = MetadirectiveNest,
370 };
371 int directiveNest_[LastType + 1] = {0};
372
373 parser::CharBlock visitedAtomicSource_;
374 SymbolSourceMap deferredNonVariables_;
375
376 using LoopConstruct = std::variant<const parser::DoConstruct *,
378 std::vector<LoopConstruct> loopStack_;
379};
380
383template <typename LessTy, typename RangeTy, typename IterTy>
384std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
385 // Deal with iterators, since the actual elements may be rvalues (i.e.
386 // have no addresses), for example with custom-constructed ranges that
387 // are not simple c.begin()..c.end().
388 std::set<IterTy, LessTy> uniq;
389 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
390 if (!uniq.insert(it).second) {
391 return it;
392 }
393 }
394 return std::nullopt;
395}
396
397} // namespace Fortran::semantics
398#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:1991
Definition parse-tree.h:1912
Definition parse-tree.h:1819
Definition parse-tree.h:1858
Definition parse-tree.h:2339
Definition parse-tree.h:547
Definition parse-tree.h:1701
Definition parse-tree.h:580
Definition parse-tree.h:4836
Definition parse-tree.h:4846
Definition parse-tree.h:4807
Definition parse-tree.h:4791
Definition parse-tree.h:4814
Definition parse-tree.h:4334
Definition parse-tree.h:4841
Definition parse-tree.h:5171
Definition parse-tree.h:4912
Definition parse-tree.h:4874
Definition parse-tree.h:4859
Definition parse-tree.h:4868
Definition parse-tree.h:3508
Definition parse-tree.h:3529
Definition parse-tree.h:5056
Definition parse-tree.h:4901
Definition parse-tree.h:5061
Definition parse-tree.h:5098
Definition parse-tree.h:5201
Definition parse-tree.h:5033
Definition parse-tree.h:5015
Definition parse-tree.h:4889
Definition parse-tree.h:5109
Definition parse-tree.h:5123
Definition parse-tree.h:5041
Definition parse-tree.h:5139
Definition parse-tree.h:4997
Definition parse-tree.h:5147
Definition parse-tree.h:5178
Definition parse-tree.h:5003
Definition parse-tree.h:4927
Definition parse-tree.h:5009
Definition parse-tree.h:1866
Definition parse-tree.h:3953
Definition parse-tree.h:3963
Definition parse-tree.h:3971
Definition parse-tree.h:4071
Definition parse-tree.h:3667
Definition parse-tree.h:3633
Definition parse-tree.h:3706
Definition parse-tree.h:3728
Definition check-omp-atomic.cpp:240