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 =
25 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
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::OpenMPBlockConstruct &);
92 void Leave(const parser::OpenMPBlockConstruct &);
93 void Leave(const parser::OmpBeginBlockDirective &);
94 void Enter(const parser::OmpEndBlockDirective &);
95 void Leave(const parser::OmpEndBlockDirective &);
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::OpenMPThreadprivate &);
130 void Leave(const parser::OpenMPThreadprivate &);
131
132 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
133 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
134 void Enter(const parser::OpenMPFlushConstruct &);
135 void Leave(const parser::OpenMPFlushConstruct &);
136 void Enter(const parser::OpenMPCancelConstruct &);
137 void Leave(const parser::OpenMPCancelConstruct &);
138 void Enter(const parser::OpenMPCancellationPointConstruct &);
139 void Leave(const parser::OpenMPCancellationPointConstruct &);
140 void Enter(const parser::OpenMPCriticalConstruct &);
141 void Leave(const parser::OpenMPCriticalConstruct &);
142 void Enter(const parser::OpenMPAtomicConstruct &);
143 void Leave(const parser::OpenMPAtomicConstruct &);
144
145 void Leave(const parser::OmpClauseList &);
146 void Enter(const parser::OmpClause &);
147
148 void Enter(const parser::DoConstruct &);
149 void Leave(const parser::DoConstruct &);
150
151 void Enter(const parser::OmpDirectiveSpecification &);
152 void Leave(const parser::OmpDirectiveSpecification &);
153
154 void Enter(const parser::OmpMetadirectiveDirective &);
155 void Leave(const parser::OmpMetadirectiveDirective &);
156
157 void Enter(const parser::OmpContextSelector &);
158 void Leave(const parser::OmpContextSelector &);
159
160#define GEN_FLANG_CLAUSE_CHECK_ENTER
161#include "llvm/Frontend/OpenMP/OMP.inc"
162
163private:
164 bool CheckAllowedClause(llvmOmpClause clause);
165 bool IsVariableListItem(const Symbol &sym);
166 bool IsExtendedListItem(const Symbol &sym);
167 bool IsCommonBlock(const Symbol &sym);
168 std::optional<bool> IsContiguous(const parser::OmpObject &object);
169 void CheckVariableListItem(const SymbolSourceMap &symbols);
170 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
171 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
172 const std::string &clauseName);
173 void CheckMultListItems();
174 void CheckStructureComponent(
175 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
176 bool HasInvalidWorksharingNesting(
177 const parser::CharBlock &, const OmpDirectiveSet &);
178 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
179 void HasInvalidTeamsNesting(
180 const llvm::omp::Directive &dir, const parser::CharBlock &source);
181 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
182 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
183 // specific clause related
184 void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
185 const std::list<parser::OmpMapType::Value> &);
186
187 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
188 const parser::OmpTraitSelector &);
189 std::optional<llvm::omp::Clause> GetClauseFromProperty(
190 const parser::OmpTraitProperty &);
191
192 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
193 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
194 void CheckTraitScore(const parser::OmpTraitScore &);
195 bool VerifyTraitPropertyLists(
196 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
197 void CheckTraitSelector(
198 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
199 void CheckTraitADMO(
200 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
201 void CheckTraitCondition(
202 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
203 void CheckTraitDeviceNum(
204 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
205 void CheckTraitRequires(
206 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
207 void CheckTraitSimd(
208 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
209
210 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
211 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
212
213 template < //
214 typename LessTy, typename RangeTy,
215 typename IterTy = decltype(std::declval<RangeTy>().begin())>
216 std::optional<IterTy> FindDuplicate(RangeTy &&);
217
218 const Symbol *GetObjectSymbol(const parser::OmpObject &object);
219 const Symbol *GetArgumentSymbol(const parser::OmpArgument &argument);
220 std::optional<parser::CharBlock> GetObjectSource(
221 const parser::OmpObject &object);
222 void CheckDependList(const parser::DataRef &);
223 void CheckDependArraySection(
224 const common::Indirection<parser::ArrayElement> &, const parser::Name &);
225 void CheckDoacross(const parser::OmpDoacross &doa);
226 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
227 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
228 const parser::OmpObject &obj, llvm::StringRef clause = "");
229 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
230 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
231 void CheckThreadprivateOrDeclareTargetVar(
232 const parser::OmpObjectList &objList);
233 void CheckSymbolNames(
234 const parser::CharBlock &source, const parser::OmpObjectList &objList);
235 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
236 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
237 void CheckCrayPointee(const parser::OmpObjectList &objectList,
238 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
239 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
240 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
241 void CheckCopyingPolymorphicAllocatable(
242 SymbolSourceMap &, const llvm::omp::Clause);
243 void CheckPrivateSymbolsInOuterCxt(
244 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
245 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
246 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
247 void CheckIsLoopIvPartOfClause(
248 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
249 bool CheckTargetBlockOnlyTeams(const parser::Block &);
250 void CheckWorkshareBlockStmts(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> &,
260 llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock);
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(
265 const evaluate::Expr<evaluate::SomeType> &, parser::CharBlock);
266 std::pair<const parser::ExecutionPartConstruct *,
267 const parser::ExecutionPartConstruct *>
268 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
269 const parser::ExecutionPartConstruct *ec2, parser::CharBlock source);
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 void CheckAtomicUpdateAssignment(
277 const evaluate::Assignment &update, parser::CharBlock source);
278 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
279 parser::CharBlock condSource, const evaluate::Assignment &assign,
280 parser::CharBlock assignSource);
281 void CheckAtomicConditionalUpdateStmt(
282 const AnalyzedCondStmt &update, parser::CharBlock source);
283 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
284 const parser::Block &body, parser::CharBlock source);
285 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
286 const parser::Block &body, parser::CharBlock source);
287 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
288 const parser::Block &body, parser::CharBlock source);
289 void CheckAtomicConditionalUpdateCapture(
290 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
291 parser::CharBlock source);
292 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
293 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
294 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
295
296 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
297 void CheckSIMDNest(const parser::OpenMPConstruct &x);
298 void CheckTargetNest(const parser::OpenMPConstruct &x);
299 void CheckTargetUpdate();
300 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
301 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
302 std::optional<llvm::omp::Directive> GetCancelType(
303 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
304 const std::optional<parser::OmpClauseList> &maybeClauses);
305 void CheckCancellationNest(
306 const parser::CharBlock &source, llvm::omp::Directive type);
307 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
308 void CheckReductionObjects(
309 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
310 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
311 parser::CharBlock source, llvm::omp::Clause clauseId);
312 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
313 const parser::OmpReductionIdentifier &ident);
314 void CheckReductionModifier(const parser::OmpReductionModifier &);
315 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
316 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
317 void ChecksOnOrderedAsBlock();
318 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
319 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
320 void ChecksOnOrderedAsStandalone();
321 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
322 void CheckReductionArraySection(
323 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
324 void CheckArraySection(const parser::ArrayElement &arrayElement,
325 const parser::Name &name, const llvm::omp::Clause clause);
326 void CheckSharedBindingInOuterContext(
327 const parser::OmpObjectList &ompObjectList);
328 void CheckIfContiguous(const parser::OmpObject &object);
329 const parser::Name *GetObjectName(const parser::OmpObject &object);
330 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
331 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
332 const parser::OmpObjectList &ompObjectList);
333 void CheckPredefinedAllocatorRestriction(
334 const parser::CharBlock &source, const parser::Name &name);
335 bool isPredefinedAllocator{false};
336
337 void CheckAllowedRequiresClause(llvmOmpClause clause);
338 bool deviceConstructFound_{false};
339
340 void CheckAlignValue(const parser::OmpClause &);
341
342 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
343
344 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
345 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
346 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
347 inline void ErrIfAllocatableVariable(const parser::Variable &);
348 inline void ErrIfLHSAndRHSSymbolsMatch(
349 const parser::Variable &, const parser::Expr &);
350 inline void ErrIfNonScalarAssignmentStmt(
351 const parser::Variable &, const parser::Expr &);
352 enum directiveNestType : int {
353 SIMDNest,
354 TargetBlockOnlyTeams,
355 TargetNest,
356 DeclarativeNest,
357 ContextSelectorNest,
358 MetadirectiveNest,
359 LastType = MetadirectiveNest,
360 };
361 int directiveNest_[LastType + 1] = {0};
362
363 SymbolSourceMap deferredNonVariables_;
364
365 using LoopConstruct = std::variant<const parser::DoConstruct *,
366 const parser::OpenMPLoopConstruct *>;
367 std::vector<LoopConstruct> loopStack_;
368};
369
370/// Find a duplicate entry in the range, and return an iterator to it.
371/// If there are no duplicate entries, return nullopt.
372template <typename LessTy, typename RangeTy, typename IterTy>
373std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
374 // Deal with iterators, since the actual elements may be rvalues (i.e.
375 // have no addresses), for example with custom-constructed ranges that
376 // are not simple c.begin()..c.end().
377 std::set<IterTy, LessTy> uniq;
378 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
379 if (!uniq.insert(it).second) {
380 return it;
381 }
382 }
383 return std::nullopt;
384}
385
386} // namespace Fortran::semantics
387#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
388

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of flang/lib/Semantics/check-omp-structure.h