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::OmpErrorDirective &);
109 void Leave(const parser::OmpErrorDirective &);
110 void Enter(const parser::OpenMPExecutableAllocate &);
111 void Leave(const parser::OpenMPExecutableAllocate &);
112 void Enter(const parser::OpenMPAllocatorsConstruct &);
113 void Leave(const parser::OpenMPAllocatorsConstruct &);
114 void Enter(const parser::OpenMPRequiresConstruct &);
115 void Leave(const parser::OpenMPRequiresConstruct &);
116 void Enter(const parser::OpenMPThreadprivate &);
117 void Leave(const parser::OpenMPThreadprivate &);
118
119 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
120 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
121 void Enter(const parser::OpenMPFlushConstruct &);
122 void Leave(const parser::OpenMPFlushConstruct &);
123 void Enter(const parser::OpenMPCancelConstruct &);
124 void Leave(const parser::OpenMPCancelConstruct &);
127 void Enter(const parser::OpenMPCriticalConstruct &);
128 void Leave(const parser::OpenMPCriticalConstruct &);
129 void Enter(const parser::OpenMPAtomicConstruct &);
130 void Leave(const parser::OpenMPAtomicConstruct &);
131
132 void Leave(const parser::OmpClauseList &);
133 void Enter(const parser::OmpClause &);
134
135 void Enter(const parser::OmpAtomicRead &);
136 void Leave(const parser::OmpAtomicRead &);
137 void Enter(const parser::OmpAtomicWrite &);
138 void Leave(const parser::OmpAtomicWrite &);
139 void Enter(const parser::OmpAtomicUpdate &);
140 void Leave(const parser::OmpAtomicUpdate &);
141 void Enter(const parser::OmpAtomicCapture &);
142 void Leave(const parser::OmpAtomic &);
143
144 void Enter(const parser::DoConstruct &);
145 void Leave(const parser::DoConstruct &);
146
147#define GEN_FLANG_CLAUSE_CHECK_ENTER
148#include "llvm/Frontend/OpenMP/OMP.inc"
149
150 void Leave(const parser::OmpClause::Fail &);
151 void Enter(const parser::OmpFailClause &);
152 void Leave(const parser::OmpFailClause &);
153
154private:
155 bool CheckAllowedClause(llvmOmpClause clause);
156 bool IsVariableListItem(const Symbol &sym);
157 bool IsExtendedListItem(const Symbol &sym);
158 bool IsCommonBlock(const Symbol &sym);
159 std::optional<bool> IsContiguous(const parser::OmpObject &object);
160 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
161 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
162 const std::string &clauseName);
163 void CheckMultListItems();
164 void CheckStructureComponent(
165 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
166 bool HasInvalidWorksharingNesting(
167 const parser::CharBlock &, const OmpDirectiveSet &);
168 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
169 void HasInvalidTeamsNesting(
170 const llvm::omp::Directive &dir, const parser::CharBlock &source);
171 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
172 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
173 // specific clause related
174 void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
175 const std::list<parser::OmpMapType::Value> &);
176 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
177 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
178
179 template < //
180 typename LessTy, typename RangeTy,
181 typename IterTy = decltype(std::declval<RangeTy>().begin())>
182 std::optional<IterTy> FindDuplicate(RangeTy &&);
183
184 const Symbol *GetObjectSymbol(const parser::OmpObject &object);
185 std::optional<parser::CharBlock> GetObjectSource(
186 const parser::OmpObject &object);
187 void CheckDependList(const parser::DataRef &);
188 void CheckDependArraySection(
190 void CheckDoacross(const parser::OmpDoacross &doa);
191 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
192 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
193 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
194 void CheckThreadprivateOrDeclareTargetVar(
195 const parser::OmpObjectList &objList);
196 void CheckSymbolNames(
197 const parser::CharBlock &source, const parser::OmpObjectList &objList);
198 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
199 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
200 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
201 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
202 void CheckCopyingPolymorphicAllocatable(
203 SymbolSourceMap &, const llvm::omp::Clause);
204 void CheckPrivateSymbolsInOuterCxt(
205 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
206 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
207 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
208 void CheckIsLoopIvPartOfClause(
209 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
210 bool CheckTargetBlockOnlyTeams(const parser::Block &);
211 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
212
213 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
214 void CheckIteratorModifier(const parser::OmpIterator &x);
215 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
216 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
217 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
218 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
219 void CheckAtomicMemoryOrderClause(
221 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
222 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
223 void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
224 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
225 void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
226 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
227 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
228 void CheckSIMDNest(const parser::OpenMPConstruct &x);
229 void CheckTargetNest(const parser::OpenMPConstruct &x);
230 void CheckTargetUpdate();
231 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
232 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
233 void CheckCancellationNest(
234 const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
235 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
236 void CheckReductionObjects(
237 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
238 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
239 parser::CharBlock source, llvm::omp::Clause clauseId);
240 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
241 const parser::OmpReductionIdentifier &ident);
242 void CheckReductionModifier(const parser::OmpReductionModifier &);
243 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
244 void ChecksOnOrderedAsBlock();
245 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
246 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
247 void ChecksOnOrderedAsStandalone();
248 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
249 void CheckReductionArraySection(
250 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
251 void CheckArraySection(const parser::ArrayElement &arrayElement,
252 const parser::Name &name, const llvm::omp::Clause clause);
253 void CheckSharedBindingInOuterContext(
254 const parser::OmpObjectList &ompObjectList);
255 void CheckIfContiguous(const parser::OmpObject &object);
256 const parser::Name *GetObjectName(const parser::OmpObject &object);
257 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
258 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
259 const parser::OmpObjectList &ompObjectList);
260 void CheckPredefinedAllocatorRestriction(
261 const parser::CharBlock &source, const parser::Name &name);
262 bool isPredefinedAllocator{false};
263
264 void CheckAllowedRequiresClause(llvmOmpClause clause);
265 bool deviceConstructFound_{false};
266
267 void CheckAlignValue(const parser::OmpClause &);
268
269 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
270 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
271 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
272 template <typename D> void CheckHintClause(D *, D *);
273 inline void ErrIfAllocatableVariable(const parser::Variable &);
274 inline void ErrIfLHSAndRHSSymbolsMatch(
275 const parser::Variable &, const parser::Expr &);
276 inline void ErrIfNonScalarAssignmentStmt(
277 const parser::Variable &, const parser::Expr &);
278 enum directiveNestType : int {
279 SIMDNest,
280 TargetBlockOnlyTeams,
281 TargetNest,
282 DeclarativeNest,
283 LastType = DeclarativeNest,
284 };
285 int directiveNest_[LastType + 1] = {0};
286
287 SymbolSourceMap deferredNonVariables_;
288
289 using LoopConstruct = std::variant<const parser::DoConstruct *,
291 std::vector<LoopConstruct> loopStack_;
292 bool isFailClause{false};
293};
294
297template <typename LessTy, typename RangeTy, typename IterTy>
298std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
299 // Deal with iterators, since the actual elements may be rvalues (i.e.
300 // have no addresses), for example with custom-constructed ranges that
301 // are not simple c.begin()..c.end().
302 std::set<IterTy, LessTy> uniq;
303 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
304 if (!uniq.insert(it).second) {
305 return it;
306 }
307 }
308 return std::nullopt;
309}
310
311} // namespace Fortran::semantics
312#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:4729
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:4735
Definition: parse-tree.h:4723
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:4741
Definition: parse-tree.h:4669
Definition: parse-tree.h:4756
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:4524
Definition: parse-tree.h:4689
Definition: parse-tree.h:4747
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