[flang] Refine "same type" testing for intrinsic arguments (#125133)
[llvm-project.git] / flang / lib / Semantics / check-omp-structure.h
blob7412a2071d492fec85895a20c16bbeac7353c783
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;
74 void Enter(const parser::OpenMPConstruct &);
75 void Leave(const parser::OpenMPConstruct &);
76 void Enter(const parser::OpenMPDeclarativeConstruct &);
77 void Leave(const parser::OpenMPDeclarativeConstruct &);
79 void Enter(const parser::OpenMPLoopConstruct &);
80 void Leave(const parser::OpenMPLoopConstruct &);
81 void Enter(const parser::OmpEndLoopDirective &);
82 void Leave(const parser::OmpEndLoopDirective &);
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 &);
90 void Enter(const parser::OpenMPSectionsConstruct &);
91 void Leave(const parser::OpenMPSectionsConstruct &);
92 void Enter(const parser::OmpEndSectionsDirective &);
93 void Leave(const parser::OmpEndSectionsDirective &);
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 &);
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 &);
127 void Enter(const parser::OpenMPCancellationPointConstruct &);
128 void Leave(const parser::OpenMPCancellationPointConstruct &);
129 void Enter(const parser::OpenMPCriticalConstruct &);
130 void Leave(const parser::OpenMPCriticalConstruct &);
131 void Enter(const parser::OpenMPAtomicConstruct &);
132 void Leave(const parser::OpenMPAtomicConstruct &);
134 void Leave(const parser::OmpClauseList &);
135 void Enter(const parser::OmpClause &);
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 &);
146 void Enter(const parser::DoConstruct &);
147 void Leave(const parser::DoConstruct &);
149 void Enter(const parser::OmpDirectiveSpecification &);
150 void Leave(const parser::OmpDirectiveSpecification &);
152 void Enter(const parser::OmpMetadirectiveDirective &);
153 void Leave(const parser::OmpMetadirectiveDirective &);
155 void Enter(const parser::OmpContextSelector &);
156 void Leave(const parser::OmpContextSelector &);
158 #define GEN_FLANG_CLAUSE_CHECK_ENTER
159 #include "llvm/Frontend/OpenMP/OMP.inc"
161 void Leave(const parser::OmpClause::Fail &);
162 void Enter(const parser::OmpFailClause &);
163 void Leave(const parser::OmpFailClause &);
165 private:
166 bool CheckAllowedClause(llvmOmpClause clause);
167 bool IsVariableListItem(const Symbol &sym);
168 bool IsExtendedListItem(const Symbol &sym);
169 bool IsCommonBlock(const Symbol &sym);
170 std::optional<bool> IsContiguous(const parser::OmpObject &object);
171 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
172 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
173 const std::string &clauseName);
174 void CheckMultListItems();
175 void CheckStructureComponent(
176 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
177 bool HasInvalidWorksharingNesting(
178 const parser::CharBlock &, const OmpDirectiveSet &);
179 bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
180 void HasInvalidTeamsNesting(
181 const llvm::omp::Directive &dir, const parser::CharBlock &source);
182 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
183 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
184 // specific clause related
185 void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
186 const std::list<parser::OmpMapType::Value> &);
187 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
188 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
190 template < //
191 typename LessTy, typename RangeTy,
192 typename IterTy = decltype(std::declval<RangeTy>().begin())>
193 std::optional<IterTy> FindDuplicate(RangeTy &&);
195 const Symbol *GetObjectSymbol(const parser::OmpObject &object);
196 std::optional<parser::CharBlock> GetObjectSource(
197 const parser::OmpObject &object);
198 void CheckDependList(const parser::DataRef &);
199 void CheckDependArraySection(
200 const common::Indirection<parser::ArrayElement> &, const parser::Name &);
201 void CheckDoacross(const parser::OmpDoacross &doa);
202 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
203 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
204 const parser::OmpObjectList &objList, llvm::StringRef clause = "");
205 void CheckThreadprivateOrDeclareTargetVar(
206 const parser::OmpObjectList &objList);
207 void CheckSymbolNames(
208 const parser::CharBlock &source, const parser::OmpObjectList &objList);
209 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
210 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
211 void CheckCrayPointee(const parser::OmpObjectList &objectList,
212 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
213 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
214 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
215 void CheckCopyingPolymorphicAllocatable(
216 SymbolSourceMap &, const llvm::omp::Clause);
217 void CheckPrivateSymbolsInOuterCxt(
218 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
219 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
220 void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
221 void CheckIsLoopIvPartOfClause(
222 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
223 bool CheckTargetBlockOnlyTeams(const parser::Block &);
224 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
226 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
227 void CheckIteratorModifier(const parser::OmpIterator &x);
228 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
229 void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
230 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
231 template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
232 void CheckAtomicMemoryOrderClause(
233 const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
234 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
235 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
236 void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
237 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
238 void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
239 void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
240 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
241 void CheckSIMDNest(const parser::OpenMPConstruct &x);
242 void CheckTargetNest(const parser::OpenMPConstruct &x);
243 void CheckTargetUpdate();
244 void CheckDependenceType(const parser::OmpDependenceType::Value &x);
245 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
246 void CheckCancellationNest(
247 const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
248 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
249 void CheckReductionObjects(
250 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
251 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
252 parser::CharBlock source, llvm::omp::Clause clauseId);
253 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
254 const parser::OmpReductionIdentifier &ident);
255 void CheckReductionModifier(const parser::OmpReductionModifier &);
256 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
257 void ChecksOnOrderedAsBlock();
258 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
259 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
260 void ChecksOnOrderedAsStandalone();
261 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
262 void CheckReductionArraySection(
263 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
264 void CheckArraySection(const parser::ArrayElement &arrayElement,
265 const parser::Name &name, const llvm::omp::Clause clause);
266 void CheckSharedBindingInOuterContext(
267 const parser::OmpObjectList &ompObjectList);
268 void CheckIfContiguous(const parser::OmpObject &object);
269 const parser::Name *GetObjectName(const parser::OmpObject &object);
270 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
271 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
272 const parser::OmpObjectList &ompObjectList);
273 void CheckPredefinedAllocatorRestriction(
274 const parser::CharBlock &source, const parser::Name &name);
275 bool isPredefinedAllocator{false};
277 void CheckAllowedRequiresClause(llvmOmpClause clause);
278 bool deviceConstructFound_{false};
280 void CheckAlignValue(const parser::OmpClause &);
282 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
283 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
284 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
285 template <typename D> void CheckHintClause(D *, D *);
286 inline void ErrIfAllocatableVariable(const parser::Variable &);
287 inline void ErrIfLHSAndRHSSymbolsMatch(
288 const parser::Variable &, const parser::Expr &);
289 inline void ErrIfNonScalarAssignmentStmt(
290 const parser::Variable &, const parser::Expr &);
291 enum directiveNestType : int {
292 SIMDNest,
293 TargetBlockOnlyTeams,
294 TargetNest,
295 DeclarativeNest,
296 ContextSelectorNest,
297 LastType = ContextSelectorNest,
299 int directiveNest_[LastType + 1] = {0};
301 SymbolSourceMap deferredNonVariables_;
303 using LoopConstruct = std::variant<const parser::DoConstruct *,
304 const parser::OpenMPLoopConstruct *>;
305 std::vector<LoopConstruct> loopStack_;
306 bool isFailClause{false};
309 /// Find a duplicate entry in the range, and return an iterator to it.
310 /// If there are no duplicate entries, return nullopt.
311 template <typename LessTy, typename RangeTy, typename IterTy>
312 std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
313 // Deal with iterators, since the actual elements may be rvalues (i.e.
314 // have no addresses), for example with custom-constructed ranges that
315 // are not simple c.begin()..c.end().
316 std::set<IterTy, LessTy> uniq;
317 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
318 if (!uniq.insert(it).second) {
319 return it;
322 return std::nullopt;
325 } // namespace Fortran::semantics
326 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_