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 | |
24 | using 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 | |
30 | namespace llvm { |
31 | namespace omp { |
32 | static OmpClauseSet privateSet{ |
33 | Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; |
34 | static 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. |
40 | static 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 | |
50 | namespace Fortran::semantics { |
51 | |
52 | // Mapping from 'Symbol' to 'Source' to keep track of the variables |
53 | // used in multiple clauses |
54 | using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>; |
55 | // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause> |
56 | using DirectivesClauseTriple = std::multimap<llvm::omp::Directive, |
57 | std::pair<llvm::omp::Directive, const OmpClauseSet>>; |
58 | |
59 | class OmpStructureChecker |
60 | : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause, |
61 | parser::OmpClause, llvm::omp::Clause_enumSize> { |
62 | public: |
63 | OmpStructureChecker(SemanticsContext &context) |
64 | : DirectiveStructureChecker(context, |
65 | #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP |
66 | #include "llvm/Frontend/OpenMP/OMP.inc" |
67 | ) { |
68 | } |
69 | using llvmOmpClause = const llvm::omp::Clause; |
70 | |
71 | void Enter(const parser::OpenMPConstruct &); |
72 | void Enter(const parser::OpenMPLoopConstruct &); |
73 | void Leave(const parser::OpenMPLoopConstruct &); |
74 | void Enter(const parser::OmpEndLoopDirective &); |
75 | void Leave(const parser::OmpEndLoopDirective &); |
76 | |
77 | void Enter(const parser::OpenMPBlockConstruct &); |
78 | void Leave(const parser::OpenMPBlockConstruct &); |
79 | void Leave(const parser::OmpBeginBlockDirective &); |
80 | void Enter(const parser::OmpEndBlockDirective &); |
81 | void Leave(const parser::OmpEndBlockDirective &); |
82 | |
83 | void Enter(const parser::OpenMPSectionsConstruct &); |
84 | void Leave(const parser::OpenMPSectionsConstruct &); |
85 | void Enter(const parser::OmpEndSectionsDirective &); |
86 | void Leave(const parser::OmpEndSectionsDirective &); |
87 | |
88 | void Enter(const parser::OpenMPDeclareSimdConstruct &); |
89 | void Leave(const parser::OpenMPDeclareSimdConstruct &); |
90 | void Enter(const parser::OpenMPDeclarativeAllocate &); |
91 | void Leave(const parser::OpenMPDeclarativeAllocate &); |
92 | void Enter(const parser::OpenMPDeclareTargetConstruct &); |
93 | void Leave(const parser::OpenMPDeclareTargetConstruct &); |
94 | void Enter(const parser::OmpDeclareTargetWithList &); |
95 | void Enter(const parser::OmpDeclareTargetWithClause &); |
96 | void Leave(const parser::OmpDeclareTargetWithClause &); |
97 | void Enter(const parser::OpenMPExecutableAllocate &); |
98 | void Leave(const parser::OpenMPExecutableAllocate &); |
99 | void Enter(const parser::OpenMPAllocatorsConstruct &); |
100 | void Leave(const parser::OpenMPAllocatorsConstruct &); |
101 | void Enter(const parser::OpenMPRequiresConstruct &); |
102 | void Leave(const parser::OpenMPRequiresConstruct &); |
103 | void Enter(const parser::OpenMPThreadprivate &); |
104 | void Leave(const parser::OpenMPThreadprivate &); |
105 | |
106 | void Enter(const parser::OpenMPSimpleStandaloneConstruct &); |
107 | void Leave(const parser::OpenMPSimpleStandaloneConstruct &); |
108 | void Enter(const parser::OpenMPFlushConstruct &); |
109 | void Leave(const parser::OpenMPFlushConstruct &); |
110 | void Enter(const parser::OpenMPCancelConstruct &); |
111 | void Leave(const parser::OpenMPCancelConstruct &); |
112 | void Enter(const parser::OpenMPCancellationPointConstruct &); |
113 | void Leave(const parser::OpenMPCancellationPointConstruct &); |
114 | void Enter(const parser::OpenMPCriticalConstruct &); |
115 | void Leave(const parser::OpenMPCriticalConstruct &); |
116 | void Enter(const parser::OpenMPAtomicConstruct &); |
117 | void Leave(const parser::OpenMPAtomicConstruct &); |
118 | |
119 | void Leave(const parser::OmpClauseList &); |
120 | void Enter(const parser::OmpClause &); |
121 | |
122 | void Enter(const parser::OmpAtomicRead &); |
123 | void Leave(const parser::OmpAtomicRead &); |
124 | void Enter(const parser::OmpAtomicWrite &); |
125 | void Leave(const parser::OmpAtomicWrite &); |
126 | void Enter(const parser::OmpAtomicUpdate &); |
127 | void Leave(const parser::OmpAtomicUpdate &); |
128 | void Enter(const parser::OmpAtomicCapture &); |
129 | void Leave(const parser::OmpAtomic &); |
130 | |
131 | #define GEN_FLANG_CLAUSE_CHECK_ENTER |
132 | #include "llvm/Frontend/OpenMP/OMP.inc" |
133 | |
134 | // Get the OpenMP Clause Kind for the corresponding Parser class |
135 | template <typename A> |
136 | llvm::omp::Clause GetClauseKindForParserClass(const A &) { |
137 | #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP |
138 | #include "llvm/Frontend/OpenMP/OMP.inc" |
139 | } |
140 | |
141 | private: |
142 | void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars, |
143 | const std::list<parser::Name> &nameList, const parser::CharBlock &item, |
144 | const std::string &clauseName); |
145 | void CheckMultListItems(); |
146 | void CheckStructureElement(const parser::OmpObjectList &ompObjectList, |
147 | const llvm::omp::Clause clause); |
148 | bool HasInvalidWorksharingNesting( |
149 | const parser::CharBlock &, const OmpDirectiveSet &); |
150 | bool IsCloselyNestedRegion(const OmpDirectiveSet &set); |
151 | void HasInvalidTeamsNesting( |
152 | const llvm::omp::Directive &dir, const parser::CharBlock &source); |
153 | void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); |
154 | // specific clause related |
155 | bool ScheduleModifierHasType(const parser::OmpScheduleClause &, |
156 | const parser::OmpScheduleModifierType::ModType &); |
157 | void CheckAllowedMapTypes(const parser::OmpMapType::Type &, |
158 | const std::list<parser::OmpMapType::Type> &); |
159 | llvm::StringRef getClauseName(llvm::omp::Clause clause) override; |
160 | llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; |
161 | |
162 | void CheckDependList(const parser::DataRef &); |
163 | void CheckDependArraySection( |
164 | const common::Indirection<parser::ArrayElement> &, const parser::Name &); |
165 | bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); |
166 | void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source, |
167 | const parser::OmpObjectList &objList, llvm::StringRef clause = "" ); |
168 | void CheckThreadprivateOrDeclareTargetVar( |
169 | const parser::OmpObjectList &objList); |
170 | void CheckSymbolNames( |
171 | const parser::CharBlock &source, const parser::OmpObjectList &objList); |
172 | void CheckIntentInPointer( |
173 | const parser::OmpObjectList &, const llvm::omp::Clause); |
174 | void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); |
175 | void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); |
176 | void CheckCopyingPolymorphicAllocatable( |
177 | SymbolSourceMap &, const llvm::omp::Clause); |
178 | void CheckPrivateSymbolsInOuterCxt( |
179 | SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); |
180 | const parser::Name GetLoopIndex(const parser::DoConstruct *x); |
181 | void SetLoopInfo(const parser::OpenMPLoopConstruct &x); |
182 | void CheckIsLoopIvPartOfClause( |
183 | llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); |
184 | bool CheckTargetBlockOnlyTeams(const parser::Block &); |
185 | void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); |
186 | |
187 | void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); |
188 | void CheckDoWhile(const parser::OpenMPLoopConstruct &x); |
189 | void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); |
190 | template <typename T, typename D> bool IsOperatorValid(const T &, const D &); |
191 | void CheckAtomicMemoryOrderClause( |
192 | const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); |
193 | void CheckAtomicUpdateStmt(const parser::AssignmentStmt &); |
194 | void CheckAtomicCaptureStmt(const parser::AssignmentStmt &); |
195 | void CheckAtomicWriteStmt(const parser::AssignmentStmt &); |
196 | void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); |
197 | void CheckDistLinear(const parser::OpenMPLoopConstruct &x); |
198 | void CheckSIMDNest(const parser::OpenMPConstruct &x); |
199 | void CheckTargetNest(const parser::OpenMPConstruct &x); |
200 | void CheckTargetUpdate(); |
201 | void CheckCancellationNest( |
202 | const parser::CharBlock &source, const parser::OmpCancelType::Type &type); |
203 | std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); |
204 | bool CheckReductionOperators(const parser::OmpClause::Reduction &); |
205 | bool CheckIntrinsicOperator( |
206 | const parser::DefinedOperator::IntrinsicOperator &); |
207 | void CheckReductionTypeList(const parser::OmpClause::Reduction &); |
208 | void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); |
209 | void ChecksOnOrderedAsBlock(); |
210 | void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); |
211 | void ChecksOnOrderedAsStandalone(); |
212 | void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue); |
213 | void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); |
214 | void CheckIntentInPointerAndDefinable( |
215 | const parser::OmpObjectList &, const llvm::omp::Clause); |
216 | void CheckArraySection(const parser::ArrayElement &arrayElement, |
217 | const parser::Name &name, const llvm::omp::Clause clause); |
218 | void CheckSharedBindingInOuterContext( |
219 | const parser::OmpObjectList &ompObjectList); |
220 | const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &); |
221 | void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source, |
222 | const parser::OmpObjectList &ompObjectList); |
223 | void CheckPredefinedAllocatorRestriction( |
224 | const parser::CharBlock &source, const parser::Name &name); |
225 | bool isPredefinedAllocator{false}; |
226 | |
227 | void CheckAllowedRequiresClause(llvmOmpClause clause); |
228 | bool deviceConstructFound_{false}; |
229 | |
230 | void EnterDirectiveNest(const int index) { directiveNest_[index]++; } |
231 | void ExitDirectiveNest(const int index) { directiveNest_[index]--; } |
232 | int GetDirectiveNest(const int index) { return directiveNest_[index]; } |
233 | template <typename D> void CheckHintClause(D *, D *); |
234 | inline void ErrIfAllocatableVariable(const parser::Variable &); |
235 | inline void ErrIfLHSAndRHSSymbolsMatch( |
236 | const parser::Variable &, const parser::Expr &); |
237 | inline void ErrIfNonScalarAssignmentStmt( |
238 | const parser::Variable &, const parser::Expr &); |
239 | enum directiveNestType { |
240 | SIMDNest, |
241 | TargetBlockOnlyTeams, |
242 | TargetNest, |
243 | LastType |
244 | }; |
245 | int directiveNest_[LastType + 1] = {0}; |
246 | }; |
247 | } // namespace Fortran::semantics |
248 | #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ |
249 | |