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 {
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
60 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
61 parser::OmpClause, llvm::omp::Clause_enumSize> {
62public:
63 using Base = DirectiveStructureChecker<llvm::omp::Directive,
64 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
65
68#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
69#include "llvm/Frontend/OpenMP/OMP.inc"
70 ) {
71 }
72 using llvmOmpClause = const llvm::omp::Clause;
73
74 void Enter(const parser::OpenMPConstruct &);
75 void Leave(const parser::OpenMPConstruct &);
76 void Enter(const parser::OpenMPDeclarativeConstruct &);
77 void Leave(const parser::OpenMPDeclarativeConstruct &);
78
79 void Enter(const parser::OpenMPLoopConstruct &);
80 void Leave(const parser::OpenMPLoopConstruct &);
81 void Enter(const parser::OmpEndLoopDirective &);
82 void Leave(const parser::OmpEndLoopDirective &);
83
84 void Enter(const parser::OpenMPBlockConstruct &);
85 void Leave(const parser::OpenMPBlockConstruct &);
86 void Leave(const parser::OmpBeginBlockDirective &);
87 void Enter(const parser::OmpEndBlockDirective &);
88 void Leave(const parser::OmpEndBlockDirective &);
89
90 void Enter(const parser::OpenMPSectionsConstruct &);
91 void Leave(const parser::OpenMPSectionsConstruct &);
92 void Enter(const parser::OmpEndSectionsDirective &);
93 void Leave(const parser::OmpEndSectionsDirective &);
94
95 void Enter(const parser::OpenMPDeclareSimdConstruct &);
96 void Leave(const parser::OpenMPDeclareSimdConstruct &);
97 void Enter(const parser::OpenMPDeclarativeAllocate &);
98 void Leave(const parser::OpenMPDeclarativeAllocate &);
99 void Enter(const parser::OpenMPDeclareMapperConstruct &);
100 void Leave(const parser::OpenMPDeclareMapperConstruct &);
101 void Enter(const parser::OpenMPDeclareTargetConstruct &);
102 void Leave(const parser::OpenMPDeclareTargetConstruct &);
103 void Enter(const parser::OpenMPDepobjConstruct &);
104 void Leave(const parser::OpenMPDepobjConstruct &);
105 void Enter(const parser::OmpDeclareTargetWithList &);
106 void Enter(const parser::OmpDeclareTargetWithClause &);
107 void Leave(const parser::OmpDeclareTargetWithClause &);
108 void Enter(const parser::OpenMPDispatchConstruct &);
109 void Leave(const parser::OpenMPDispatchConstruct &);
110 void Enter(const parser::OmpErrorDirective &);
111 void Leave(const parser::OmpErrorDirective &);
112 void Enter(const parser::OpenMPExecutableAllocate &);
113 void Leave(const parser::OpenMPExecutableAllocate &);
114 void Enter(const parser::OpenMPAllocatorsConstruct &);
115 void Leave(const parser::OpenMPAllocatorsConstruct &);
116 void Enter(const parser::OpenMPRequiresConstruct &);
117 void Leave(const parser::OpenMPRequiresConstruct &);
118 void Enter(const parser::OpenMPThreadprivate &);
119 void Leave(const parser::OpenMPThreadprivate &);
120
121 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
122 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
123 void Enter(const parser::OpenMPFlushConstruct &);
124 void Leave(const parser::OpenMPFlushConstruct &);
125 void Enter(const parser::OpenMPCancelConstruct &);
126 void Leave(const parser::OpenMPCancelConstruct &);
129 void Enter(const parser::OpenMPCriticalConstruct &);
130 void Leave(const parser::OpenMPCriticalConstruct &);
131 void Enter(const parser::OpenMPAtomicConstruct &);
132 void Leave(const parser::OpenMPAtomicConstruct &);
133
134 void Leave(const parser::OmpClauseList &);
135 void Enter(const parser::OmpClause &);
136
137 void Enter(const parser::OmpAtomicRead &);
138 void Leave(const parser::OmpAtomicRead &);
139 void Enter(const parser::OmpAtomicWrite &);
140 void Leave(const parser::OmpAtomicWrite &);
141 void Enter(const parser::OmpAtomicUpdate &);
142 void Leave(const parser::OmpAtomicUpdate &);
143 void Enter(const parser::OmpAtomicCapture &);
144 void Leave(const parser::OmpAtomic &);
145
146 void Enter(const parser::DoConstruct &);
147 void Leave(const parser::DoConstruct &);
148
149#define GEN_FLANG_CLAUSE_CHECK_ENTER
150#include "llvm/Frontend/OpenMP/OMP.inc"
151
152 void Leave(const parser::OmpClause::Fail &);
153 void Enter(const parser::OmpFailClause &);
154 void Leave(const parser::OmpFailClause &);
155
156private:
157 bool CheckAllowedClause(llvmOmpClause clause);
158 bool IsVariableListItem(const Symbol &sym);
159 bool IsExtendedListItem(const Symbol &sym);
160 bool IsCommonBlock(const Symbol &sym);
161 std::optional<bool> IsContiguous(const parser::OmpObject &object);
162 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
163 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
164 const std::string &clauseName);
165 void CheckMultListItems();
166 void CheckStructureComponent(
167 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
168 bool HasInvalidWorksharingNesting(
169 const parser::CharBlock &, const OmpDirectiveSet &);
170 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
171 void HasInvalidTeamsNesting(
172 const llvm::omp::Directive &dir, const parser::CharBlock &source);
173 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
174 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
175 // specific clause related
176 void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
177 const std::list<parser::OmpMapType::Value> &);
178 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
179 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
180
181 template < //
182 typename LessTy, typename RangeTy,
183 typename IterTy = decltype(std::declval<RangeTy>().begin())>
184 std::optional<IterTy> FindDuplicate(RangeTy &&);
185
186 const Symbol *GetObjectSymbol(const parser::OmpObject &object);
187 std::optional<parser::CharBlock> GetObjectSource(
188 const parser::OmpObject &object);
189 void CheckDependList(const parser::DataRef &);
190 void CheckDependArraySection(
192 void CheckDoacross(const parser::OmpDoacross &doa);
193 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
194 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
195 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
196 void CheckThreadprivateOrDeclareTargetVar(
197 const parser::OmpObjectList &objList);
198 void CheckSymbolNames(
199 const parser::CharBlock &source, const parser::OmpObjectList &objList);
200 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
201 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
202 void CheckCrayPointee(const parser::OmpObjectList &objectList,
203 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
204 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
205 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
206 void CheckCopyingPolymorphicAllocatable(
207 SymbolSourceMap &, const llvm::omp::Clause);
208 void CheckPrivateSymbolsInOuterCxt(
209 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
210 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
211 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
212 void CheckIsLoopIvPartOfClause(
213 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
214 bool CheckTargetBlockOnlyTeams(const parser::Block &);
215 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
216
217 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
218 void CheckIteratorModifier(const parser::OmpIterator &x);
219 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
220 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
221 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
222 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
223 void CheckAtomicMemoryOrderClause(
225 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
226 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
227 void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
228 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
229 void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
230 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
231 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
232 void CheckSIMDNest(const parser::OpenMPConstruct &x);
233 void CheckTargetNest(const parser::OpenMPConstruct &x);
234 void CheckTargetUpdate();
235 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
236 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
237 void CheckCancellationNest(
238 const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
239 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
240 void CheckReductionObjects(
241 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
242 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
243 parser::CharBlock source, llvm::omp::Clause clauseId);
244 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
245 const parser::OmpReductionIdentifier &ident);
246 void CheckReductionModifier(const parser::OmpReductionModifier &);
247 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
248 void ChecksOnOrderedAsBlock();
249 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
250 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
251 void ChecksOnOrderedAsStandalone();
252 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
253 void CheckReductionArraySection(
254 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
255 void CheckArraySection(const parser::ArrayElement &arrayElement,
256 const parser::Name &name, const llvm::omp::Clause clause);
257 void CheckSharedBindingInOuterContext(
258 const parser::OmpObjectList &ompObjectList);
259 void CheckIfContiguous(const parser::OmpObject &object);
260 const parser::Name *GetObjectName(const parser::OmpObject &object);
261 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
262 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
263 const parser::OmpObjectList &ompObjectList);
264 void CheckPredefinedAllocatorRestriction(
265 const parser::CharBlock &source, const parser::Name &name);
266 bool isPredefinedAllocator{false};
267
268 void CheckAllowedRequiresClause(llvmOmpClause clause);
269 bool deviceConstructFound_{false};
270
271 void CheckAlignValue(const parser::OmpClause &);
272
273 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
274 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
275 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
276 template <typename D> void CheckHintClause(D *, D *);
277 inline void ErrIfAllocatableVariable(const parser::Variable &);
278 inline void ErrIfLHSAndRHSSymbolsMatch(
279 const parser::Variable &, const parser::Expr &);
280 inline void ErrIfNonScalarAssignmentStmt(
281 const parser::Variable &, const parser::Expr &);
282 enum directiveNestType : int {
283 SIMDNest,
284 TargetBlockOnlyTeams,
285 TargetNest,
286 DeclarativeNest,
287 LastType = DeclarativeNest,
288 };
289 int directiveNest_[LastType + 1] = {0};
290
291 SymbolSourceMap deferredNonVariables_;
292
293 using LoopConstruct = std::variant<const parser::DoConstruct *,
295 std::vector<LoopConstruct> loopStack_;
296 bool isFailClause{false};
297};
298
301template <typename LessTy, typename RangeTy, typename IterTy>
302std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
303 // Deal with iterators, since the actual elements may be rvalues (i.e.
304 // have no addresses), for example with custom-constructed ranges that
305 // are not simple c.begin()..c.end().
306 std::set<IterTy, LessTy> uniq;
307 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
308 if (!uniq.insert(it).second) {
309 return it;
310 }
311 }
312 return std::nullopt;
313}
314
315} // namespace Fortran::semantics
316#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Definition: enum-set.h:28
Definition: indirection.h:31
Definition: char-block.h:28
Definition: check-directive-structure.h:181
Definition: check-omp-structure.h:61
Definition: semantics.h:67
Definition: symbol.h:712
Definition: parse-tree.h:1911
Definition: parse-tree.h:2016
Definition: parse-tree.h:1818
Definition: parse-tree.h:2338
Definition: parse-tree.h:1700
Definition: parse-tree.h:580
Definition: parse-tree.h:4604
Definition: parse-tree.h:4568
Definition: parse-tree.h:4620
Definition: parse-tree.h:4577
Definition: parse-tree.h:4595
Definition: parse-tree.h:4586
Definition: parse-tree.h:4629
Definition: parse-tree.h:4754
Definition: parse-tree.h:4333
Definition: parse-tree.h:4317
Definition: parse-tree.h:4418
Definition: parse-tree.h:4413
Definition: parse-tree.h:4033
Definition: parse-tree.h:4760
Definition: parse-tree.h:4748
Definition: parse-tree.h:4376
Definition: parse-tree.h:4352
Definition: parse-tree.h:4106
Definition: parse-tree.h:3463
Definition: parse-tree.h:4539
Definition: parse-tree.h:4641
Definition: parse-tree.h:4766
Definition: parse-tree.h:4669
Definition: parse-tree.h:4781
Definition: parse-tree.h:4515
Definition: parse-tree.h:4488
Definition: parse-tree.h:4494
Definition: parse-tree.h:4467
Definition: parse-tree.h:4682
Definition: parse-tree.h:4705
Definition: parse-tree.h:4524
Definition: parse-tree.h:4714
Definition: parse-tree.h:4772
Definition: parse-tree.h:4474
Definition: parse-tree.h:4397
Definition: parse-tree.h:4481
Definition: parse-tree.h:1865
Definition: parse-tree.h:3681
Definition: parse-tree.h:3753
Definition: parse-tree.h:3843
Definition: parse-tree.h:3852