[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / flang / lib / Semantics / check-omp-structure.h
blobdf21ebac0f6d76a758767d3d58ac489c4210020e
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 //===----------------------------------------------------------------------===//
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
14 #ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
15 #define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
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"
24 using OmpClauseSet =
25 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
27 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
28 #include "llvm/Frontend/OpenMP/OMP.inc"
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,
47 } // namespace omp
48 } // namespace llvm
50 namespace Fortran::semantics {
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>>;
59 class OmpStructureChecker
60 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
61 parser::OmpClause, llvm::omp::Clause_enumSize> {
62 public:
63 using Base = DirectiveStructureChecker<llvm::omp::Directive,
64 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>;
66 OmpStructureChecker(SemanticsContext &context)
67 : DirectiveStructureChecker(context,
68 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
69 #include "llvm/Frontend/OpenMP/OMP.inc"
70 ) {
72 using llvmOmpClause = const llvm::omp::Clause;
73 using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
75 void Enter(const parser::OpenMPConstruct &);
76 void Leave(const parser::OpenMPConstruct &);
77 void Enter(const parser::OpenMPLoopConstruct &);
78 void Leave(const parser::OpenMPLoopConstruct &);
79 void Enter(const parser::OmpEndLoopDirective &);
80 void Leave(const parser::OmpEndLoopDirective &);
82 void Enter(const parser::OpenMPBlockConstruct &);
83 void Leave(const parser::OpenMPBlockConstruct &);
84 void Leave(const parser::OmpBeginBlockDirective &);
85 void Enter(const parser::OmpEndBlockDirective &);
86 void Leave(const parser::OmpEndBlockDirective &);
88 void Enter(const parser::OpenMPSectionsConstruct &);
89 void Leave(const parser::OpenMPSectionsConstruct &);
90 void Enter(const parser::OmpEndSectionsDirective &);
91 void Leave(const parser::OmpEndSectionsDirective &);
93 void Enter(const parser::OpenMPDeclareSimdConstruct &);
94 void Leave(const parser::OpenMPDeclareSimdConstruct &);
95 void Enter(const parser::OpenMPDeclarativeAllocate &);
96 void Leave(const parser::OpenMPDeclarativeAllocate &);
97 void Enter(const parser::OpenMPDeclareMapperConstruct &);
98 void Leave(const parser::OpenMPDeclareMapperConstruct &);
99 void Enter(const parser::OpenMPDeclareTargetConstruct &);
100 void Leave(const parser::OpenMPDeclareTargetConstruct &);
101 void Enter(const parser::OpenMPDepobjConstruct &);
102 void Leave(const parser::OpenMPDepobjConstruct &);
103 void Enter(const parser::OmpDeclareTargetWithList &);
104 void Enter(const parser::OmpDeclareTargetWithClause &);
105 void Leave(const parser::OmpDeclareTargetWithClause &);
106 void Enter(const parser::OpenMPExecutableAllocate &);
107 void Leave(const parser::OpenMPExecutableAllocate &);
108 void Enter(const parser::OpenMPAllocatorsConstruct &);
109 void Leave(const parser::OpenMPAllocatorsConstruct &);
110 void Enter(const parser::OpenMPRequiresConstruct &);
111 void Leave(const parser::OpenMPRequiresConstruct &);
112 void Enter(const parser::OpenMPThreadprivate &);
113 void Leave(const parser::OpenMPThreadprivate &);
115 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
116 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
117 void Enter(const parser::OpenMPFlushConstruct &);
118 void Leave(const parser::OpenMPFlushConstruct &);
119 void Enter(const parser::OpenMPCancelConstruct &);
120 void Leave(const parser::OpenMPCancelConstruct &);
121 void Enter(const parser::OpenMPCancellationPointConstruct &);
122 void Leave(const parser::OpenMPCancellationPointConstruct &);
123 void Enter(const parser::OpenMPCriticalConstruct &);
124 void Leave(const parser::OpenMPCriticalConstruct &);
125 void Enter(const parser::OpenMPAtomicConstruct &);
126 void Leave(const parser::OpenMPAtomicConstruct &);
128 void Leave(const parser::OmpClauseList &);
129 void Enter(const parser::OmpClause &);
131 void Enter(const parser::OmpAtomicRead &);
132 void Leave(const parser::OmpAtomicRead &);
133 void Enter(const parser::OmpAtomicWrite &);
134 void Leave(const parser::OmpAtomicWrite &);
135 void Enter(const parser::OmpAtomicUpdate &);
136 void Leave(const parser::OmpAtomicUpdate &);
137 void Enter(const parser::OmpAtomicCapture &);
138 void Leave(const parser::OmpAtomic &);
140 void Enter(const parser::DoConstruct &);
141 void Leave(const parser::DoConstruct &);
143 #define GEN_FLANG_CLAUSE_CHECK_ENTER
144 #include "llvm/Frontend/OpenMP/OMP.inc"
146 private:
147 bool CheckAllowedClause(llvmOmpClause clause);
148 bool IsVariableListItem(const Symbol &sym);
149 bool IsExtendedListItem(const Symbol &sym);
150 std::optional<bool> IsContiguous(const parser::OmpObject &object);
151 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
152 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
153 const std::string &clauseName);
154 void CheckMultListItems();
155 void CheckStructureElement(const parser::OmpObjectList &ompObjectList,
156 const llvm::omp::Clause clause);
157 bool HasInvalidWorksharingNesting(
158 const parser::CharBlock &, const OmpDirectiveSet &);
159 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
160 void HasInvalidTeamsNesting(
161 const llvm::omp::Directive &dir, const parser::CharBlock &source);
162 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
163 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
164 // specific clause related
165 bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
166 const parser::OmpScheduleModifierType::ModType &);
167 void CheckAllowedMapTypes(const parser::OmpMapClause::Type &,
168 const std::list<parser::OmpMapClause::Type> &);
169 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
170 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
172 template <typename T> struct DefaultLess {
173 bool operator()(const T *a, const T *b) const { return *a < *b; }
175 template <typename T, typename Less = DefaultLess<T>>
176 const T *FindDuplicateEntry(const std::list<T> &);
178 void CheckDependList(const parser::DataRef &);
179 void CheckDependArraySection(
180 const common::Indirection<parser::ArrayElement> &, const parser::Name &);
181 void CheckDoacross(const parser::OmpDoacross &doa);
182 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
183 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
184 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
185 void CheckThreadprivateOrDeclareTargetVar(
186 const parser::OmpObjectList &objList);
187 void CheckSymbolNames(
188 const parser::CharBlock &source, const parser::OmpObjectList &objList);
189 void CheckIntentInPointer(
190 const parser::OmpObjectList &, const llvm::omp::Clause);
191 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
192 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
193 void CheckCopyingPolymorphicAllocatable(
194 SymbolSourceMap &, const llvm::omp::Clause);
195 void CheckPrivateSymbolsInOuterCxt(
196 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
197 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
198 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
199 void CheckIsLoopIvPartOfClause(
200 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
201 bool CheckTargetBlockOnlyTeams(const parser::Block &);
202 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
204 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
205 void CheckIteratorModifier(const parser::OmpIterator &x);
206 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
207 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
208 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
209 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
210 void CheckAtomicMemoryOrderClause(
211 const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
212 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
213 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
214 void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
215 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
216 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
217 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
218 void CheckSIMDNest(const parser::OpenMPConstruct &x);
219 void CheckTargetNest(const parser::OpenMPConstruct &x);
220 void CheckTargetUpdate();
221 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
222 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
223 void CheckCancellationNest(
224 const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
225 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
226 bool CheckReductionOperators(const parser::OmpClause::Reduction &);
227 bool CheckIntrinsicOperator(
228 const parser::DefinedOperator::IntrinsicOperator &);
229 void CheckReductionTypeList(const parser::OmpClause::Reduction &);
230 void CheckReductionModifier(const ReductionModifier &);
231 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
232 void ChecksOnOrderedAsBlock();
233 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
234 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
235 void ChecksOnOrderedAsStandalone();
236 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
237 void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
238 void CheckIntentInPointerAndDefinable(
239 const parser::OmpObjectList &, const llvm::omp::Clause);
240 void CheckArraySection(const parser::ArrayElement &arrayElement,
241 const parser::Name &name, const llvm::omp::Clause clause);
242 void CheckSharedBindingInOuterContext(
243 const parser::OmpObjectList &ompObjectList);
244 void CheckIfContiguous(const parser::OmpObject &object);
245 const parser::Name *GetObjectName(const parser::OmpObject &object);
246 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
247 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
248 const parser::OmpObjectList &ompObjectList);
249 void CheckPredefinedAllocatorRestriction(
250 const parser::CharBlock &source, const parser::Name &name);
251 bool isPredefinedAllocator{false};
253 void CheckAllowedRequiresClause(llvmOmpClause clause);
254 bool deviceConstructFound_{false};
256 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
257 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
258 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
259 template <typename D> void CheckHintClause(D *, D *);
260 inline void ErrIfAllocatableVariable(const parser::Variable &);
261 inline void ErrIfLHSAndRHSSymbolsMatch(
262 const parser::Variable &, const parser::Expr &);
263 inline void ErrIfNonScalarAssignmentStmt(
264 const parser::Variable &, const parser::Expr &);
265 enum directiveNestType {
266 SIMDNest,
267 TargetBlockOnlyTeams,
268 TargetNest,
269 LastType
271 int directiveNest_[LastType + 1] = {0};
273 SymbolSourceMap deferredNonVariables_;
275 using LoopConstruct = std::variant<const parser::DoConstruct *,
276 const parser::OpenMPLoopConstruct *>;
277 std::vector<LoopConstruct> loopStack_;
280 template <typename T, typename Less>
281 const T *OmpStructureChecker::FindDuplicateEntry(const std::list<T> &list) {
282 // Add elements of the list to a set. If the insertion fails, return
283 // the address of the failing element.
285 // The objects of type T may not be copyable, so add their addresses
286 // to the set. The set will need to compare the actual objects, so
287 // the custom comparator is provided.
288 std::set<const T *, Less> uniq;
290 for (const T &item : list) {
291 if (!uniq.insert(&item).second) {
292 return &item;
295 return nullptr;
298 } // namespace Fortran::semantics
299 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_