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 void CheckVariableListItem(const SymbolSourceMap &symbols);
166 void CheckDirectiveSpelling(
167 parser::CharBlock spelling, llvm::omp::Directive id);
168 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
169 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
170 const std::string &clauseName);
171 void CheckMultListItems();
172 void CheckStructureComponent(
173 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
174 bool HasInvalidWorksharingNesting(
175 const parser::CharBlock &, const OmpDirectiveSet &);
176 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
177 void HasInvalidTeamsNesting(
178 const llvm::omp::Directive &dir, const parser::CharBlock &source);
179 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
180 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
181 // specific clause related
182 void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
183 const std::list<parser::OmpMapType::Value> &);
184
185 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
186 const parser::OmpTraitSelector &);
187 std::optional<llvm::omp::Clause> GetClauseFromProperty(
188 const parser::OmpTraitProperty &);
189
190 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
191 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
192 void CheckTraitScore(const parser::OmpTraitScore &);
193 bool VerifyTraitPropertyLists(
194 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
195 void CheckTraitSelector(
196 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
197 void CheckTraitADMO(
198 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
199 void CheckTraitCondition(
200 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
201 void CheckTraitDeviceNum(
202 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
203 void CheckTraitRequires(
204 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
205 void CheckTraitSimd(
206 const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &);
207
208 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
209 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
210
211 template < //
212 typename LessTy, typename RangeTy,
213 typename IterTy = decltype(std::declval<RangeTy>().begin())>
214 std::optional<IterTy> FindDuplicate(RangeTy &&);
215
216 void CheckDependList(const parser::DataRef &);
217 void CheckDependArraySection(
218 const common::Indirection<parser::ArrayElement> &, const parser::Name &);
219 void CheckDoacross(const parser::OmpDoacross &doa);
220 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
221 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
222 const parser::OmpObject &obj, llvm::StringRef clause = "");
223 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
224 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
225 void CheckThreadprivateOrDeclareTargetVar(
226 const parser::OmpObjectList &objList);
227 void CheckSymbolNames(
228 const parser::CharBlock &source, const parser::OmpObjectList &objList);
229 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
230 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
231 void CheckCrayPointee(const parser::OmpObjectList &objectList,
232 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
233 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
234 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
235 void CheckCopyingPolymorphicAllocatable(
236 SymbolSourceMap &, const llvm::omp::Clause);
237 void CheckPrivateSymbolsInOuterCxt(
238 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
239 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
240 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
241 void CheckIsLoopIvPartOfClause(
242 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
243 bool CheckTargetBlockOnlyTeams(const parser::Block &);
244 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
245
246 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
247 void CheckIteratorModifier(const parser::OmpIterator &x);
248 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
249 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
250 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
251 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
252
253 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
254 llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock);
255 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
256 void CheckAtomicType(
257 SymbolRef sym, parser::CharBlock source, std::string_view name);
258 void CheckAtomicVariable(
259 const evaluate::Expr<evaluate::SomeType> &, parser::CharBlock);
260 std::pair<const parser::ExecutionPartConstruct *,
261 const parser::ExecutionPartConstruct *>
262 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
263 const parser::ExecutionPartConstruct *ec2, parser::CharBlock source);
264 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
265 const SomeExpr &atom, parser::CharBlock source);
266 void CheckAtomicReadAssignment(
267 const evaluate::Assignment &read, parser::CharBlock source);
268 void CheckAtomicWriteAssignment(
269 const evaluate::Assignment &write, parser::CharBlock source);
270 void CheckAtomicUpdateAssignment(
271 const evaluate::Assignment &update, parser::CharBlock source);
272 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
273 parser::CharBlock condSource, const evaluate::Assignment &assign,
274 parser::CharBlock assignSource);
275 void CheckAtomicConditionalUpdateStmt(
276 const AnalyzedCondStmt &update, parser::CharBlock source);
277 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
278 const parser::Block &body, parser::CharBlock source);
279 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
280 const parser::Block &body, parser::CharBlock source);
281 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
282 const parser::Block &body, parser::CharBlock source);
283 void CheckAtomicConditionalUpdateCapture(
284 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
285 parser::CharBlock source);
286 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
287 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
288 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
289
290 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
291 void CheckSIMDNest(const parser::OpenMPConstruct &x);
292 void CheckTargetNest(const parser::OpenMPConstruct &x);
293 void CheckTargetUpdate();
294 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
295 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
296 std::optional<llvm::omp::Directive> GetCancelType(
297 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
298 const std::optional<parser::OmpClauseList> &maybeClauses);
299 void CheckCancellationNest(
300 const parser::CharBlock &source, llvm::omp::Directive type);
301 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
302 void CheckReductionObjects(
303 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
304 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
305 parser::CharBlock source, llvm::omp::Clause clauseId);
306 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
307 const parser::OmpReductionIdentifier &ident);
308 void CheckReductionModifier(const parser::OmpReductionModifier &);
309 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
310 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
311 void ChecksOnOrderedAsBlock();
312 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
313 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
314 void ChecksOnOrderedAsStandalone();
315 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
316 void CheckReductionArraySection(
317 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
318 void CheckArraySection(const parser::ArrayElement &arrayElement,
319 const parser::Name &name, const llvm::omp::Clause clause);
320 void CheckSharedBindingInOuterContext(
321 const parser::OmpObjectList &ompObjectList);
322 void CheckIfContiguous(const parser::OmpObject &object);
323 const parser::Name *GetObjectName(const parser::OmpObject &object);
324 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
325 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
326 const parser::OmpObjectList &ompObjectList);
327 void CheckPredefinedAllocatorRestriction(
328 const parser::CharBlock &source, const parser::Name &name);
329 bool isPredefinedAllocator{false};
330
331 void CheckAllowedRequiresClause(llvmOmpClause clause);
332 bool deviceConstructFound_{false};
333
334 void CheckAlignValue(const parser::OmpClause &);
335
336 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
337
338 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
339 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
340 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
341 inline void ErrIfAllocatableVariable(const parser::Variable &);
342 inline void ErrIfLHSAndRHSSymbolsMatch(
343 const parser::Variable &, const parser::Expr &);
344 inline void ErrIfNonScalarAssignmentStmt(
345 const parser::Variable &, const parser::Expr &);
346 enum directiveNestType : int {
347 SIMDNest,
348 TargetBlockOnlyTeams,
349 TargetNest,
350 DeclarativeNest,
351 ContextSelectorNest,
352 MetadirectiveNest,
353 LastType = MetadirectiveNest,
354 };
355 int directiveNest_[LastType + 1] = {0};
356
357 parser::CharBlock visitedAtomicSource_;
358 SymbolSourceMap deferredNonVariables_;
359
360 using LoopConstruct = std::variant<const parser::DoConstruct *,
361 const parser::OpenMPLoopConstruct *>;
362 std::vector<LoopConstruct> loopStack_;
363};
364
365/// Find a duplicate entry in the range, and return an iterator to it.
366/// If there are no duplicate entries, return nullopt.
367template <typename LessTy, typename RangeTy, typename IterTy>
368std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
369 // Deal with iterators, since the actual elements may be rvalues (i.e.
370 // have no addresses), for example with custom-constructed ranges that
371 // are not simple c.begin()..c.end().
372 std::set<IterTy, LessTy> uniq;
373 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
374 if (!uniq.insert(it).second) {
375 return it;
376 }
377 }
378 return std::nullopt;
379}
380
381} // namespace Fortran::semantics
382#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
383

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