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
19#include "flang/Parser/openmp-utils.h"
20#include "flang/Parser/parse-tree.h"
21#include "flang/Semantics/openmp-directive-sets.h"
22#include "flang/Semantics/semantics.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/iterator_range.h"
25#include "llvm/Frontend/OpenMP/OMP.h"
26#include "llvm/Frontend/OpenMP/OMPDescriptors.h"
27
28#include <cstddef>
29#include <functional>
30#include <list>
31#include <map>
32#include <optional>
33#include <set>
34#include <string>
35#include <string_view>
36#include <utility>
37#include <variant>
38#include <vector>
39
40#define GEN_FLANG_DIRECTIVE_CLAUSE_SETS
41#include "llvm/Frontend/OpenMP/OMP.inc"
42
43namespace llvm::omp {
44static Clauses privateSet{
45 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate};
46static Clauses privateReductionSet{
47 Clauses{Clause::OMPC_reduction} | privateSet};
48} // namespace llvm::omp
49
50namespace Fortran::semantics {
51struct AnalyzedCondStmt;
52
53namespace omp {
54struct LoopSequence;
55}
56
57// Support classes for verifying syntactic properties.
58template <typename ElemTy, typename SetsSetTy> struct AppliedElement {
60 SetsSetTy sets;
61 llvm::omp::Version version{};
62};
63
64template <typename ElemTy, typename SetsSetTy> struct AppliedElementInfo {
65 using ElementTy = AppliedElement<ElemTy, SetsSetTy>;
67};
68
69using AppliedModifierInfo =
71using AppliedClauseInfo =
73
74// Mapping from 'Symbol' to 'Source' to keep track of the variables
75// used in multiple clauses
76using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
77// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
78using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
79 std::pair<llvm::omp::Directive, const llvm::omp::Clauses>>;
80
81using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive,
82 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clauses>;
83
84template <>
85void IterateOverMembers(
86 const llvm::omp::Clauses &set, std::function<void(llvm::omp::Clause)> func);
87
88class OmpStructureChecker : public OmpStructureCheckerBase {
89public:
90 using Base = OmpStructureCheckerBase;
91
92 OmpStructureChecker(SemanticsContext &context);
93
94 void Enter(const parser::ProgramUnit &);
95 void Leave(const parser::ProgramUnit &);
96 void Enter(const parser::MainProgram &);
97 void Leave(const parser::MainProgram &);
98 void Enter(const parser::BlockData &);
99 void Leave(const parser::BlockData &);
100 void Enter(const parser::Module &);
101 void Leave(const parser::Module &);
102 void Enter(const parser::Submodule &);
103 void Leave(const parser::Submodule &);
104 void Enter(const parser::SubroutineStmt &);
105 void Enter(const parser::EndSubroutineStmt &);
106 void Enter(const parser::FunctionStmt &);
107 void Enter(const parser::EndFunctionStmt &);
108 void Enter(const parser::MpSubprogramStmt &);
109 void Enter(const parser::EndMpSubprogramStmt &);
110 void Enter(const parser::Block &);
111 void Leave(const parser::Block &);
112 void Enter(const parser::BlockConstruct &);
113 void Leave(const parser::BlockConstruct &);
114 void Enter(const parser::InternalSubprogram &);
115 void Enter(const parser::ModuleSubprogram &);
116 void Enter(const parser::ModuleSubprogramPart &);
117 void Enter(const parser::InterfaceBody &);
118 void Leave(const parser::InterfaceBody &);
119
120 void Enter(const parser::SpecificationPart &);
121 void Leave(const parser::SpecificationPart &);
122 void Enter(const parser::ExecutionPart &);
123 void Leave(const parser::ExecutionPart &);
124
125 void Enter(const parser::OpenMPConstruct &);
126 void Leave(const parser::OpenMPConstruct &);
127 void Enter(const parser::OpenMPDeclarativeConstruct &);
128 void Leave(const parser::OpenMPDeclarativeConstruct &);
129
130 void Enter(const parser::OpenMPMisplacedEndDirective &);
131 void Leave(const parser::OpenMPMisplacedEndDirective &);
132 void Enter(const parser::OpenMPInvalidDirective &);
133 void Leave(const parser::OpenMPInvalidDirective &);
134
135 void Enter(const parser::OpenMPLoopConstruct &);
136 void Leave(const parser::OpenMPLoopConstruct &);
137
138 void Enter(const parser::OpenMPInteropConstruct &);
139 void Enter(const parser::OmpBlockConstruct &);
140 void Leave(const parser::OmpBlockConstruct &);
141 void Enter(const parser::OmpBeginDirective &);
142 void Leave(const parser::OmpBeginDirective &);
143
144 void Enter(const parser::OpenMPSectionsConstruct &);
145
146 void Enter(const parser::OmpDeclareVariantDirective &);
147 void Enter(const parser::OmpDeclareSimdDirective &);
148 void Enter(const parser::OmpAllocateDirective &);
149 void Leave(const parser::OmpAllocateDirective &);
150 void Enter(const parser::OmpDeclareMapperDirective &);
151 void Enter(const parser::OmpDeclareReductionDirective &);
152 void Enter(const parser::OmpDeclareTargetDirective &);
153 void Leave(const parser::OmpDeclareTargetDirective &);
154 void Enter(const parser::OpenMPDepobjConstruct &);
155 void Enter(const parser::OpenMPDispatchConstruct &);
156 void Enter(const parser::OpenMPAllocatorsConstruct &);
157 void Enter(const parser::OmpRequiresDirective &);
158 void Enter(const parser::OmpGroupprivateDirective &);
159 void Leave(const parser::OmpThreadprivateDirective &);
160
161 void Enter(const parser::OpenMPSimpleStandaloneConstruct &);
162 void Leave(const parser::OpenMPSimpleStandaloneConstruct &);
163 void Leave(const parser::OpenMPFlushConstruct &);
164 void Enter(const parser::OpenMPCancelConstruct &);
166 void Enter(const parser::OpenMPCriticalConstruct &);
167 void Enter(const parser::OpenMPAtomicConstruct &);
168
169 void Enter(const parser::OmpClauseList &);
170 void Leave(const parser::OmpClauseList &);
171 void Enter(const parser::OmpClause &);
172
173 void Enter(const parser::DoConstruct &);
174 void Leave(const parser::DoConstruct &);
175
176 void Enter(const parser::OmpDirectiveSpecification &);
177 void Leave(const parser::OmpDirectiveSpecification &);
178
179 void Enter(const parser::OmpErrorDirective &);
180
181 void Enter(const parser::OmpMetadirectiveDirective &);
182 void Leave(const parser::OmpMetadirectiveDirective &);
183
184 void Enter(const parser::ExecutionPartConstruct &);
185 void Leave(const parser::OmpClause::When &);
186
187 void Enter(const parser::OmpContextSelector &);
188 void Leave(const parser::OmpContextSelector &);
189
190 void Enter(const parser::OmpLoopModifier &);
191
192 void Enter(const parser::OmpClause::Apply &);
193 void Leave(const parser::OmpClause::Apply &);
194
195 template <typename A> void Enter(const parser::Statement<A> &);
196 void Leave(const parser::GotoStmt &);
197 void Leave(const parser::ComputedGotoStmt &);
198 void Leave(const parser::ArithmeticIfStmt &);
199 void Leave(const parser::AssignedGotoStmt &);
200 void Leave(const parser::AltReturnSpec &);
201 void Leave(const parser::ErrLabel &);
202 void Leave(const parser::EndLabel &);
203 void Leave(const parser::EorLabel &);
204
205 void Enter(const parser::OmpClause::Affinity &x);
206 void Enter(const parser::OmpClause::Align &x);
207 void Enter(const parser::OmpClause::Aligned &x);
208 void Enter(const parser::OmpClause::Allocate &x);
209 void Enter(const parser::OmpClause::Allocator &x);
210 void Enter(const parser::OmpClause::At &x);
211 void Enter(const parser::OmpClause::AtomicDefaultMemOrder &x);
212 void Enter(const parser::OmpClause::CancellationConstructType &x);
213 void Enter(const parser::OmpClause::Collapse &x);
214 void Enter(const parser::OmpClause::Copyin &x);
215 void Enter(const parser::OmpClause::Copyprivate &x);
216 void Enter(const parser::OmpClause::Defaultmap &x);
217 void Enter(const parser::OmpClause::Depend &x);
218 void Enter(const parser::OmpClause::Depth &x);
219 void Enter(const parser::OmpClause::Destroy &x);
220 void Enter(const parser::OmpClause::Detach &x);
221 void Enter(const parser::OmpClause::DeviceSafesync &x);
222 void Enter(const parser::OmpClause::Device &x);
223 void Enter(const parser::OmpClause::Doacross &x);
224 void Enter(const parser::OmpClause::DynamicAllocators &x);
225 void Enter(const parser::OmpClause::Firstprivate &x);
226 void Enter(const parser::OmpClause::From &x);
227 void Enter(const parser::OmpClause::HasDeviceAddr &x);
228 void Enter(const parser::OmpClause::Hint &x);
229 void Enter(const parser::OmpClause::If &x);
230 void Enter(const parser::OmpClause::InReduction &x);
231 void Enter(const parser::OmpClause::IsDevicePtr &x);
232 void Enter(const parser::OmpClause::Lastprivate &x);
233 void Enter(const parser::OmpClause::Linear &x);
234 void Enter(const parser::OmpClause::Looprange &x);
235 void Enter(const parser::OmpClause::Map &x);
236 void Enter(const parser::OmpClause::Message &x);
237 void Enter(const parser::OmpClause::NumTeams &x);
238 void Enter(const parser::OmpClause::NumThreads &x);
239 void Enter(const parser::OmpClause::OmpxBare &x);
240 void Enter(const parser::OmpClause::OmpxDynCgroupMem &x);
241 void Enter(const parser::OmpClause::Ordered &x);
242 void Enter(const parser::OmpClause::Permutation &x);
243 void Enter(const parser::OmpClause::Priority &x);
244 void Enter(const parser::OmpClause::Private &x);
245 void Enter(const parser::OmpClause::Reduction &x);
246 void Enter(const parser::OmpClause::ReverseOffload &x);
247 void Enter(const parser::OmpClause::Safelen &x);
248 void Enter(const parser::OmpClause::Schedule &x);
249 void Enter(const parser::OmpClause::SelfMaps &x);
250 void Enter(const parser::OmpClause::Shared &x);
251 void Enter(const parser::OmpClause::Simdlen &x);
252 void Enter(const parser::OmpClause::Sizes &x);
253 void Enter(const parser::OmpClause::TaskReduction &x);
254 void Enter(const parser::OmpClause::ThreadLimit &x);
255 void Enter(const parser::OmpClause::To &x);
256 void Enter(const parser::OmpClause::UnifiedAddress &x);
257 void Enter(const parser::OmpClause::UnifiedSharedMemory &x);
258 void Enter(const parser::OmpClause::UpdateDependObjects &x);
259 void Enter(const parser::OmpClause::UseDeviceAddr &x);
260 void Enter(const parser::OmpClause::UseDevicePtr &x);
261 void Enter(const parser::OmpClause::UsesAllocators &x);
262 void Enter(const parser::OmpClause::When &x);
263
264private:
265 using LoopOrConstruct = std::variant<const parser::DoConstruct *,
267
268 // Most of these functions are defined in check-omp-structure.cpp, but
269 // some groups have their own files.
270
271 // check-omp-atomic.cpp
272 void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
274 bool isError = false);
275 void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
276 void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
277 std::string_view what, std::string_view name,
278 bool checkTypeOnPointer = true);
279 void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
280 parser::CharBlock, bool checkTypeOnPointer = true,
281 bool isCapture = false);
282 std::pair<const parser::ExecutionPartConstruct *,
284 CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
286 void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture,
287 const SomeExpr &atom, parser::CharBlock source);
288 void CheckAtomicReadAssignment(
289 const evaluate::Assignment &read, parser::CharBlock source);
290 void CheckAtomicWriteAssignment(
291 const evaluate::Assignment &write, parser::CharBlock source);
292 std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment(
293 const evaluate::Assignment &update, parser::CharBlock source);
294 std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom,
295 const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics);
296 void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond,
297 parser::CharBlock condSource, const evaluate::Assignment &assign,
298 parser::CharBlock assignSource);
299 void CheckAtomicConditionalUpdateStmt(
300 const AnalyzedCondStmt &update, parser::CharBlock source);
301 void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x,
302 const parser::Block &body, parser::CharBlock source);
303 void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x,
304 const parser::Block &body, parser::CharBlock source);
305 void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x,
306 const parser::Block &body, parser::CharBlock source);
307 void CheckAtomicConditionalUpdateCapture(
308 const parser::OpenMPAtomicConstruct &x, const parser::Block &body,
309 parser::CharBlock source);
310 void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x);
311 void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x);
312 void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x);
313
314 // check-omp-loop.cpp
315 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
316 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
317 void CheckSIMDNest(const parser::OpenMPConstruct &x);
318 void CheckRectangularNest(const parser::OmpDirectiveSpecification &spec,
319 const omp::LoopSequence &nest);
320 void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
321 const parser::Name GetLoopIndex(const parser::DoConstruct *x);
322 void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
323 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
324 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
325 void CheckScanModifier(const parser::OmpClause::Reduction &x);
326 void CheckDoacross(
327 const parser::OmpDoacross &doa, llvm::omp::Clause clauseId);
328 void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
329 void CheckUnrollFullTripCount(const parser::OpenMPLoopConstruct &x);
330
331 void BeginMetadirectiveVariantScope();
332 void EndMetadirectiveVariantScope();
333
334 // check-omp-variant.cpp
335 void CheckMetadirectiveVariantsWithoutLoop(std::size_t firstVariant = 0);
336 void CheckOmpDeclareVariantDirective(
338 void CheckDeclareVariantUserConditions(const parser::OmpContextSelector &);
339 const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
341 std::optional<llvm::omp::Clause> GetClauseFromProperty(
343
344 void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &);
345 void CheckContextSelectorSpecification(const parser::OmpContextSelector &);
346 void CheckTraitSetSelector(const parser::OmpTraitSetSelector &);
347 void CheckTraitScore(const parser::OmpTraitScore &);
348 bool VerifyTraitPropertyLists(
350 void CheckTraitSelector(
352 void CheckTraitADMO(
354 void CheckTraitCondition(
356 void CheckTraitDeviceNum(
358 void CheckTraitRequires(
360 void CheckTraitSimd(
362
363 // check-omp-syntax.cpp
364 bool VerifyClauseVersion(
365 parser::OmpDirectiveName dirName, const AppliedClauseInfo &info);
366 bool VerifyClauseRequired(parser::OmpDirectiveName dirName,
367 const AppliedClauseInfo &info, llvm::omp::Version version);
368 bool VerifyClauseUnique(parser::OmpDirectiveName dirName,
369 const AppliedClauseInfo &info, llvm::omp::Version version);
370 bool VerifyClauseExclusive(parser::OmpDirectiveName dirName,
371 const AppliedClauseInfo &info, llvm::omp::Version version);
372 bool VerifyClauseUltimate(parser::OmpDirectiveName dirName,
373 const AppliedClauseInfo &info, llvm::omp::Version version);
374 bool VerifyClauseSyntax(parser::OmpDirectiveName dirName,
375 const AppliedClauseInfo &info, llvm::omp::Version version);
376 void VerifyClauseSyntax(const parser::OmpDirectiveSpecification *beginSpec,
378
379 bool VerifyModifierVersion(parser::omp::WithSource<llvm::omp::Clause> clause,
380 const AppliedModifierInfo &info);
381 bool VerifyModifierRequired(parser::omp::WithSource<llvm::omp::Clause> clause,
382 const AppliedModifierInfo &info, llvm::omp::Version version);
383 bool VerifyModifierUnique(parser::omp::WithSource<llvm::omp::Clause> clause,
384 const AppliedModifierInfo &info, llvm::omp::Version version);
385 bool VerifyModifierExclusive(
387 const AppliedModifierInfo &info, llvm::omp::Version version);
388 bool VerifyModifierUltimate(parser::omp::WithSource<llvm::omp::Clause> clause,
389 const AppliedModifierInfo &info, llvm::omp::Version version);
390 bool VerifyModifierSyntax(parser::omp::WithSource<llvm::omp::Clause> clause,
391 const AppliedModifierInfo &info, llvm::omp::Version version);
392 void VerifyModifierSyntax(const parser::OmpClause &x);
393
394 void SetAllowedClauseOverride(llvm::omp::Clause clauseId,
395 llvm::omp::Directive dirId,
396 llvm::omp::Version since = llvm::omp::Version());
397
398 // check-omp-structure.cpp
399 using ClauseIterator =
400 decltype(std::declval<const parser::OmpClauseList>().v.begin());
401 bool IsAllowedClause(llvm::omp::Clause clauseId);
402 void CheckArgumentObjectKind(const parser::OmpClause &x);
403 void CheckDirectiveSpelling(
404 parser::CharBlock spelling, llvm::omp::Directive id);
405 void CheckCompoundDirective(
406 const parser::OmpDirectiveSpecification *beginSpec,
407 const parser::OmpDirectiveSpecification *endSpec);
408 void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x);
409 void CheckDirectivePureSince(parser::CharBlock source,
410 llvm::omp::Directive id, const char *where,
412 void CheckDirectiveInPureProcedure(parser::CharBlock source,
413 llvm::omp::Directive id, const parser::OmpDirectiveSpecification &spec);
414 void CheckDirectiveInDoConcurrent(parser::CharBlock source,
415 llvm::omp::Directive id, const parser::OmpDirectiveSpecification &spec);
416 void AddClauses(llvm::iterator_range<ClauseIterator> beginClauses,
417 llvm::iterator_range<ClauseIterator> endClauses);
418 void AnalyzeObject(const parser::OmpObject &object);
419 void AnalyzeSubstring(const parser::OmpObject &object);
420
421 const parser::OpenMPConstruct *GetCurrentConstruct() const;
422 void CheckSourceLabel(const parser::Label &);
423 void CheckLabelContext(const parser::CharBlock, const parser::CharBlock,
425 void ClearLabels();
426 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
427 const std::list<parser::Name> &nameList, const parser::CharBlock &item,
428 const std::string &clauseName);
429 void CheckMultListItems();
430 void CheckStructureComponent(
431 const parser::OmpObject &object, llvm::omp::Clause clauseId);
432 void CheckStructureComponent(
433 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
434 bool HasInvalidWorksharingNesting(
435 const parser::OmpDirectiveName &name, const llvm::omp::Directives &);
436
437 bool IsCloselyNestedRegion(const llvm::omp::Directives &set);
438 bool IsNestedInDirective(llvm::omp::Directive directive);
439 bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const;
440 bool InTargetRegion();
441 void HasInvalidTeamsNesting(
442 const llvm::omp::Directive &dir, const parser::CharBlock &source);
443 bool HasRequires(llvm::omp::Clause req);
444 void CheckAllowedMapTypes(
445 parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
446 void CheckCloseModifierOnMapMembers();
447
448 llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
449 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
450
451 template < //
452 typename LessTy, typename RangeTy,
453 typename IterTy = decltype(std::declval<RangeTy>().begin())>
454 std::optional<IterTy> FindDuplicate(RangeTy &&);
455
456 void CheckDependList(const parser::DataRef &);
457 void CheckDimsModifier(parser::CharBlock source, size_t numValues,
458 const parser::OmpDimsModifier &x);
459 void CheckTypeParamInquiry(const parser::CharBlock &source,
460 const parser::OmpObject &object, llvm::omp::Directive dirId);
461 void CheckTypeParamInquiry(const parser::CharBlock &source,
462 const parser::OmpObject &object, llvm::omp::Clause clauseId);
463 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
464 const parser::OmpObject &object, llvm::StringRef clause = "",
465 bool checkSubstrings = true);
466 void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source,
467 const parser::OmpObjectList &objList, llvm::StringRef clause = "",
468 bool checkSubstrings = true);
469 void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &);
470 void CheckThreadprivateOrDeclareTargetVar(const parser::Name &);
471 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &);
472 void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &);
473 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause);
474 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause);
475 void CheckCrayPointee(const parser::OmpObjectList &objectList,
476 llvm::StringRef clause, bool suggestToUseCrayPointer = true);
477 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
478 void CheckDefaultNoneInAssociatedLoop(
480 UnorderedSymbolSet &diagnosed);
481 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause);
482 void CheckCopyingPolymorphicAllocatable(
483 SymbolSourceMap &, const llvm::omp::Clause);
484 void CheckPrivateSymbolsInOuterCxt(
485 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
486 bool CheckTargetBlockOnlyTeams(const parser::Block &);
487 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
488 void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
489 void CheckIndividualAllocateDirective(
490 const parser::OmpAllocateDirective &x, bool isExecutable);
491 void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x);
492 void CheckDeclareReduction(const parser::OmpDirectiveSpecification &x);
493
494 void CheckUsesAllocatorsSpec(
496 void CheckUsesAllocatorsTraits(
497 const parser::OmpTraitsArray &traits, parser::CharBlock source);
498
499 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
500 void CheckIteratorModifier(const parser::OmpIterator &x);
501
502 void CheckTargetNest(const parser::OpenMPConstruct &x);
503 void CheckTargetUpdate();
504 void CheckTaskgraph(const parser::OmpBlockConstruct &x);
505 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x);
506 std::optional<llvm::omp::Directive> GetCancelType(
507 llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource,
508 const std::optional<parser::OmpClauseList> &maybeClauses);
509 void CheckCancellationNest(
510 const parser::CharBlock &source, llvm::omp::Directive type);
511 void CheckSubstring(
512 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
513 void CheckReductionObjects(
514 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);
515 bool CheckReductionIntrinsicOperator(
516 parser::DefinedOperator::IntrinsicOperator op, parser::CharBlock source);
517 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident,
518 parser::CharBlock source, llvm::omp::Clause clauseId);
519 void CheckReductionObjectTypes(const parser::OmpObjectList &objects,
520 const parser::OmpReductionIdentifier &ident);
521 void CheckReductionModifier(const parser::OmpReductionModifier &);
522 void CheckLastprivateModifier(const parser::OmpLastprivateModifier &);
523 void CheckSingleConstruct(const parser::OmpBlockConstruct &x);
524 void CheckMasterNesting(const parser::OmpBlockConstruct &x);
525 void ChecksOnOrderedAsBlock();
526 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
527 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
528 void ChecksOnOrderedAsStandalone();
529 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
530 void CheckReductionArraySection(
531 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
532 void CheckArraySection(const parser::ArrayElement &arrayElement,
533 const parser::Name &name, const llvm::omp::Clause clause);
534 void CheckArraySectionStrides(const parser::DataRef &, llvm::omp::Clause);
535 void CheckLastPartRefForArraySection(
536 const parser::Designator &designator, llvm::omp::Clause clauseId);
537 void CheckSharedBindingInOuterContext(
538 const parser::OmpObjectList &ompObjectList);
539 void CheckIfContiguous(const parser::OmpObject &object);
540 const parser::Name *GetObjectName(const parser::OmpObject &object);
541 void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj,
542 const parser::OmpClause &initClause);
543 void CheckAllowedRequiresClause(llvm::omp::Clause clause);
544 void AddEndDirectiveClauses(const parser::OmpClauseList &clauses);
545 void CheckTempDescriptorMappings();
546
547 void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
548 void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
549 int GetDirectiveNest(const int index) { return directiveNest_[index]; }
550
551 bool deviceConstructFound_{false};
552 enum directiveNestType : int {
553 ApplyNest,
554 SIMDNest,
555 TargetBlockOnlyTeams,
556 TargetNest,
557 DeclarativeNest,
558 ContextSelectorNest,
559 MetadirectiveNest,
560 LastType = MetadirectiveNest,
561 };
562 int directiveNest_[LastType + 1] = {0};
563
564 std::set<std::pair<const Symbol *, const Symbol *>> declareVariantPairs_;
565 // For each variant procedure: its construct-selector-set as an ordered list
566 // of elements (a leaf construct directive plus a normalized rendering of any
567 // properties), and the source of the DECLARE VARIANT directive that first
568 // established the set.
569 std::map<const Symbol *,
570 std::pair<
573 declareVariantConstructSets_;
574 // Tracks the procedures that appear as a base in DECLARE VARIANT.
575 std::set<const Symbol *> declareVariantBases_;
576
577 int allocateDirectiveLevel_{0};
578 parser::CharBlock visitedAtomicSource_;
579
580 // Mapping of directive-name-modifier constituents to the sources of the
581 // IF clauses that referenced them. If there was no modifier, the entire
582 // directive is assumed to be listed.
583 std::map<llvm::omp::Directive, parser::CharBlock> ifLeafs_;
584
585 // Track symbols with temporary stack descriptors mapped in TARGET ENTER DATA
586 // and symbols mapped in TARGET EXIT DATA within the current function scope.
587 // Used to warn about potential issues with mapping temporary descriptors.
588 std::multimap<const Symbol *, parser::CharBlock> tempDescriptorEnterMaps_;
589 std::set<const Symbol *> tempDescriptorExitMaps_;
590
591 // Stack of nested DO loops and OpenMP constructs.
592 // This is used to verify DO loop nest for DOACROSS, and branches into
593 // and out of OpenMP constructs.
594 std::vector<LoopOrConstruct> constructStack_;
595 // Scopes for scoping units.
596 std::vector<const Scope *> scopeStack_;
597 // Stack of directive specifications (except for SECTION).
598 // This is to allow visitor functions to see all specified clauses, since
599 // they are only recorded in DirectiveContext as they are processed.
600 std::vector<const parser::OmpDirectiveSpecification *> dirStack_;
601
602 enum class PartKind : int {
603 // There are also other "parts", such as internal-subprogram-part, etc,
604 // but we're keeping track of these two for now.
605 SpecificationPart,
606 ExecutionPart,
607 };
608 std::vector<PartKind> partStack_;
609
610 struct MetadirectiveLoopVariant {
613 bool checkDefaultNoneInAssociatedLoop;
614 };
615 std::vector<MetadirectiveLoopVariant> metadirectiveLoopVariants_;
616 std::vector<std::size_t> metadirectiveVariantScopeStarts_;
617 const parser::traits::OmpContextSelectorSpecification *currentWhenSelector_{
618 nullptr};
619
620 std::multimap<const parser::Label,
621 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
622 sourceLabels_;
623 std::map<const parser::Label,
624 std::pair<parser::CharBlock, const parser::OpenMPConstruct *>>
625 targetLabels_;
626 parser::CharBlock currentStatementSource_;
627};
628
629template <typename A>
630void OmpStructureChecker::Enter(const parser::Statement<A> &statement) {
631 currentStatementSource_ = statement.source;
632 // Keep track of the labels in all the labelled statements
633 if (statement.label) {
634 auto label{statement.label.value()};
635 // Get the context to check if the labelled statement is in an
636 // enclosing OpenMP construct
637 auto *thisConstruct{GetCurrentConstruct()};
638 targetLabels_.emplace(
639 label, std::make_pair(currentStatementSource_, thisConstruct));
640 // Check if a statement that causes a jump to the 'label'
641 // has already been encountered
642 auto range{sourceLabels_.equal_range(label)};
643 for (auto it{range.first}; it != range.second; ++it) {
644 // Check if both the statement with 'label' and the statement that
645 // causes a jump to the 'label' are in the same scope
646 CheckLabelContext(it->second.first, currentStatementSource_,
647 it->second.second, thisConstruct);
648 }
649 }
650}
651
654template <typename LessTy, typename RangeTy, typename IterTy>
655std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) {
656 // Deal with iterators, since the actual elements may be rvalues (i.e.
657 // have no addresses), for example with custom-constructed ranges that
658 // are not simple c.begin()..c.end().
659 std::set<IterTy, LessTy> uniq;
660 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) {
661 if (!uniq.insert(it).second) {
662 return it;
663 }
664 }
665 return std::nullopt;
666}
667} // namespace Fortran::semantics
668#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
Definition expression.h:960
Definition common.h:222
Definition char-block.h:27
Definition check-directive-structure.h:212
Definition semantics.h:71
Definition symbol.h:918
Definition FIRType.h:106
Definition OpenACC.h:20
Definition parse-tree.h:3555
Definition parse-tree.h:1952
Definition parse-tree.h:3565
Definition parse-tree.h:2236
Definition parse-tree.h:3075
Definition parse-tree.h:2564
Definition parse-tree.h:1862
Definition parse-tree.h:1901
Definition parse-tree.h:2379
Definition parse-tree.h:559
Definition parse-tree.h:3195
Definition parse-tree.h:3227
Definition parse-tree.h:468
Definition parse-tree.h:2983
Definition parse-tree.h:3008
Definition parse-tree.h:2997
Definition parse-tree.h:3019
Definition parse-tree.h:592
Definition parse-tree.h:5530
Definition parse-tree.h:5319
Definition parse-tree.h:5329
Definition parse-tree.h:5288
Definition parse-tree.h:5272
Definition parse-tree.h:5457
Definition parse-tree.h:5474
Definition parse-tree.h:5449
Definition parse-tree.h:3591
Definition parse-tree.h:5295
Definition parse-tree.h:4682
Definition parse-tree.h:5362
Definition parse-tree.h:5483
Definition parse-tree.h:5342
Definition parse-tree.h:3646
Definition parse-tree.h:3634
Definition parse-tree.h:3690
Definition parse-tree.h:5490
Definition parse-tree.h:5496
Definition parse-tree.h:5556
Definition parse-tree.h:5561
Definition parse-tree.h:5598
Definition parse-tree.h:5682
Definition parse-tree.h:5546
Definition parse-tree.h:5609
Definition parse-tree.h:5623
Definition parse-tree.h:5639
Definition parse-tree.h:5647
Definition parse-tree.h:5706
Definition parse-tree.h:5668
Definition parse-tree.h:5414
Definition parse-tree.h:576
Definition parse-tree.h:456
Definition parse-tree.h:362
Definition parse-tree.h:3061
Definition parse-tree.h:3214
Definition parse-tree.h:4101
Definition parse-tree.h:4168
Definition parse-tree.h:4178
Definition parse-tree.h:4187
Definition parse-tree.h:4222
Definition parse-tree.h:4385
Definition parse-tree.h:4447
Definition openmp-utils.h:114
Definition parse-tree.h:3828
Definition parse-tree.h:3794
Definition parse-tree.h:3867
Definition parse-tree.h:3889
Definition check-omp-atomic.cpp:242
Definition check-omp-structure.h:64
Definition check-omp-structure.h:58
Definition openmp-utils.h:494