| //===-- lib/Semantics/check-omp-structure.h ---------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // OpenMP structure validity check list |
| // 1. invalid clauses on directive |
| // 2. invalid repeated clauses on directive |
| // 3. TODO: invalid nesting of regions |
| |
| #ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ |
| #define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ |
| |
| #include "check-directive-structure.h" |
| #include "flang/Common/enum-set.h" |
| #include "flang/Parser/parse-tree.h" |
| #include "flang/Semantics/openmp-directive-sets.h" |
| #include "flang/Semantics/semantics.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/iterator_range.h" |
| #include "llvm/Frontend/OpenMP/OMP.h" |
| |
| #include <cstddef> |
| #include <functional> |
| #include <list> |
| #include <map> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| #include <variant> |
| #include <vector> |
| |
| #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS |
| #include "llvm/Frontend/OpenMP/OMP.inc" |
| |
| namespace llvm::omp { |
| static ClauseSet privateSet{ |
| Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; |
| static ClauseSet privateReductionSet{ |
| ClauseSet{Clause::OMPC_reduction} | privateSet}; |
| } // namespace llvm::omp |
| |
| namespace Fortran::semantics { |
| struct AnalyzedCondStmt; |
| |
| namespace omp { |
| struct LoopSequence; |
| } |
| |
| // Mapping from 'Symbol' to 'Source' to keep track of the variables |
| // used in multiple clauses |
| using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>; |
| // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause> |
| using DirectivesClauseTriple = std::multimap<llvm::omp::Directive, |
| std::pair<llvm::omp::Directive, const llvm::omp::ClauseSet>>; |
| |
| using OmpStructureCheckerBase = DirectiveStructureChecker<llvm::omp::Directive, |
| llvm::omp::Clause, parser::OmpClause, llvm::omp::ClauseSet>; |
| |
| template <> |
| void IterateOverMembers(const llvm::omp::ClauseSet &set, |
| std::function<void(llvm::omp::Clause)> func); |
| |
| class OmpStructureChecker : public OmpStructureCheckerBase { |
| public: |
| using Base = OmpStructureCheckerBase; |
| |
| OmpStructureChecker(SemanticsContext &context); |
| |
| void Enter(const parser::ProgramUnit &); |
| void Leave(const parser::ProgramUnit &); |
| void Enter(const parser::MainProgram &); |
| void Leave(const parser::MainProgram &); |
| void Enter(const parser::BlockData &); |
| void Leave(const parser::BlockData &); |
| void Enter(const parser::Module &); |
| void Leave(const parser::Module &); |
| void Enter(const parser::Submodule &); |
| void Leave(const parser::Submodule &); |
| void Enter(const parser::SubroutineStmt &); |
| void Enter(const parser::EndSubroutineStmt &); |
| void Enter(const parser::FunctionStmt &); |
| void Enter(const parser::EndFunctionStmt &); |
| void Enter(const parser::MpSubprogramStmt &); |
| void Enter(const parser::EndMpSubprogramStmt &); |
| void Enter(const parser::Block &); |
| void Leave(const parser::Block &); |
| void Enter(const parser::BlockConstruct &); |
| void Leave(const parser::BlockConstruct &); |
| void Enter(const parser::InternalSubprogram &); |
| void Enter(const parser::ModuleSubprogram &); |
| void Enter(const parser::ModuleSubprogramPart &); |
| void Enter(const parser::InterfaceBody &); |
| void Leave(const parser::InterfaceBody &); |
| |
| void Enter(const parser::SpecificationPart &); |
| void Leave(const parser::SpecificationPart &); |
| void Enter(const parser::ExecutionPart &); |
| void Leave(const parser::ExecutionPart &); |
| |
| void Enter(const parser::OpenMPConstruct &); |
| void Leave(const parser::OpenMPConstruct &); |
| void Enter(const parser::OpenMPDeclarativeConstruct &); |
| void Leave(const parser::OpenMPDeclarativeConstruct &); |
| |
| void Enter(const parser::OpenMPMisplacedEndDirective &); |
| void Leave(const parser::OpenMPMisplacedEndDirective &); |
| void Enter(const parser::OpenMPInvalidDirective &); |
| void Leave(const parser::OpenMPInvalidDirective &); |
| |
| void Enter(const parser::OpenMPLoopConstruct &); |
| void Leave(const parser::OpenMPLoopConstruct &); |
| |
| void Enter(const parser::OpenMPInteropConstruct &); |
| void Enter(const parser::OmpBlockConstruct &); |
| void Leave(const parser::OmpBlockConstruct &); |
| void Enter(const parser::OmpBeginDirective &); |
| void Leave(const parser::OmpBeginDirective &); |
| |
| void Enter(const parser::OpenMPSectionsConstruct &); |
| |
| void Enter(const parser::OmpDeclareVariantDirective &); |
| void Enter(const parser::OmpDeclareSimdDirective &); |
| void Enter(const parser::OmpAllocateDirective &); |
| void Leave(const parser::OmpAllocateDirective &); |
| void Enter(const parser::OmpDeclareMapperDirective &); |
| void Enter(const parser::OmpDeclareReductionDirective &); |
| void Enter(const parser::OmpDeclareTargetDirective &); |
| void Leave(const parser::OmpDeclareTargetDirective &); |
| void Enter(const parser::OpenMPDepobjConstruct &); |
| void Enter(const parser::OpenMPDispatchConstruct &); |
| void Enter(const parser::OpenMPAllocatorsConstruct &); |
| void Enter(const parser::OmpRequiresDirective &); |
| void Enter(const parser::OmpGroupprivateDirective &); |
| void Leave(const parser::OmpThreadprivateDirective &); |
| |
| void Enter(const parser::OpenMPSimpleStandaloneConstruct &); |
| void Leave(const parser::OpenMPSimpleStandaloneConstruct &); |
| void Leave(const parser::OpenMPFlushConstruct &); |
| void Enter(const parser::OpenMPCancelConstruct &); |
| void Enter(const parser::OpenMPCancellationPointConstruct &); |
| void Enter(const parser::OpenMPCriticalConstruct &); |
| void Enter(const parser::OpenMPAtomicConstruct &); |
| |
| void Enter(const parser::OmpClauseList &); |
| void Leave(const parser::OmpClauseList &); |
| void Enter(const parser::OmpClause &); |
| |
| void Enter(const parser::DoConstruct &); |
| void Leave(const parser::DoConstruct &); |
| |
| void Enter(const parser::OmpDirectiveSpecification &); |
| void Leave(const parser::OmpDirectiveSpecification &); |
| |
| void Enter(const parser::OmpErrorDirective &); |
| |
| void Enter(const parser::OmpMetadirectiveDirective &); |
| void Leave(const parser::OmpMetadirectiveDirective &); |
| |
| void Enter(const parser::ExecutionPartConstruct &); |
| void Leave(const parser::OmpClause::When &); |
| |
| void Enter(const parser::OmpContextSelector &); |
| void Leave(const parser::OmpContextSelector &); |
| |
| void Enter(const parser::OmpLoopModifier &); |
| |
| void Enter(const parser::OmpClause::Apply &); |
| void Leave(const parser::OmpClause::Apply &); |
| |
| template <typename A> void Enter(const parser::Statement<A> &); |
| void Leave(const parser::GotoStmt &); |
| void Leave(const parser::ComputedGotoStmt &); |
| void Leave(const parser::ArithmeticIfStmt &); |
| void Leave(const parser::AssignedGotoStmt &); |
| void Leave(const parser::AltReturnSpec &); |
| void Leave(const parser::ErrLabel &); |
| void Leave(const parser::EndLabel &); |
| void Leave(const parser::EorLabel &); |
| |
| void Enter(const parser::OmpClause::Affinity &x); |
| void Enter(const parser::OmpClause::Align &x); |
| void Enter(const parser::OmpClause::Aligned &x); |
| void Enter(const parser::OmpClause::Allocate &x); |
| void Enter(const parser::OmpClause::Allocator &x); |
| void Enter(const parser::OmpClause::At &x); |
| void Enter(const parser::OmpClause::AtomicDefaultMemOrder &x); |
| void Enter(const parser::OmpClause::CancellationConstructType &x); |
| void Enter(const parser::OmpClause::Collapse &x); |
| void Enter(const parser::OmpClause::Copyin &x); |
| void Enter(const parser::OmpClause::Copyprivate &x); |
| void Enter(const parser::OmpClause::Defaultmap &x); |
| void Enter(const parser::OmpClause::Depend &x); |
| void Enter(const parser::OmpClause::Depth &x); |
| void Enter(const parser::OmpClause::Destroy &x); |
| void Enter(const parser::OmpClause::Detach &x); |
| void Enter(const parser::OmpClause::DeviceSafesync &x); |
| void Enter(const parser::OmpClause::Device &x); |
| void Enter(const parser::OmpClause::Doacross &x); |
| void Enter(const parser::OmpClause::DynamicAllocators &x); |
| void Enter(const parser::OmpClause::DynGroupprivate &x); |
| void Enter(const parser::OmpClause::Enter &x); |
| void Enter(const parser::OmpClause::Firstprivate &x); |
| void Enter(const parser::OmpClause::From &x); |
| void Enter(const parser::OmpClause::HasDeviceAddr &x); |
| void Enter(const parser::OmpClause::Hint &x); |
| void Enter(const parser::OmpClause::If &x); |
| void Enter(const parser::OmpClause::InReduction &x); |
| void Enter(const parser::OmpClause::IsDevicePtr &x); |
| void Enter(const parser::OmpClause::Lastprivate &x); |
| void Enter(const parser::OmpClause::Linear &x); |
| void Enter(const parser::OmpClause::Looprange &x); |
| void Enter(const parser::OmpClause::Map &x); |
| void Enter(const parser::OmpClause::Message &x); |
| void Enter(const parser::OmpClause::NumTeams &x); |
| void Enter(const parser::OmpClause::NumThreads &x); |
| void Enter(const parser::OmpClause::OmpxBare &x); |
| void Enter(const parser::OmpClause::OmpxDynCgroupMem &x); |
| void Enter(const parser::OmpClause::Ordered &x); |
| void Enter(const parser::OmpClause::Permutation &x); |
| void Enter(const parser::OmpClause::Priority &x); |
| void Enter(const parser::OmpClause::Private &x); |
| void Enter(const parser::OmpClause::Reduction &x); |
| void Enter(const parser::OmpClause::ReverseOffload &x); |
| void Enter(const parser::OmpClause::Safelen &x); |
| void Enter(const parser::OmpClause::Schedule &x); |
| void Enter(const parser::OmpClause::SelfMaps &x); |
| void Enter(const parser::OmpClause::Shared &x); |
| void Enter(const parser::OmpClause::Simdlen &x); |
| void Enter(const parser::OmpClause::Sizes &x); |
| void Enter(const parser::OmpClause::TaskReduction &x); |
| void Enter(const parser::OmpClause::ThreadLimit &x); |
| void Enter(const parser::OmpClause::To &x); |
| void Enter(const parser::OmpClause::UnifiedAddress &x); |
| void Enter(const parser::OmpClause::UnifiedSharedMemory &x); |
| void Enter(const parser::OmpClause::UpdateDependObjects &x); |
| void Enter(const parser::OmpClause::UseDeviceAddr &x); |
| void Enter(const parser::OmpClause::UseDevicePtr &x); |
| void Enter(const parser::OmpClause::UsesAllocators &x); |
| void Enter(const parser::OmpClause::When &x); |
| |
| private: |
| using LoopOrConstruct = std::variant<const parser::DoConstruct *, |
| const parser::OpenMPConstruct *>; |
| |
| // Most of these functions are defined in check-omp-structure.cpp, but |
| // some groups have their own files. |
| |
| // check-omp-atomic.cpp |
| void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &, |
| llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock); |
| void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source); |
| void CheckAtomicType(SymbolRef sym, parser::CharBlock source, |
| std::string_view name, bool checkTypeOnPointer = true); |
| void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &, |
| parser::CharBlock, bool checkTypeOnPointer = true); |
| std::pair<const parser::ExecutionPartConstruct *, |
| const parser::ExecutionPartConstruct *> |
| CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1, |
| const parser::ExecutionPartConstruct *ec2, parser::CharBlock source); |
| void CheckAtomicCaptureAssignment(const evaluate::Assignment &capture, |
| const SomeExpr &atom, parser::CharBlock source); |
| void CheckAtomicReadAssignment( |
| const evaluate::Assignment &read, parser::CharBlock source); |
| void CheckAtomicWriteAssignment( |
| const evaluate::Assignment &write, parser::CharBlock source); |
| std::optional<evaluate::Assignment> CheckAtomicUpdateAssignment( |
| const evaluate::Assignment &update, parser::CharBlock source); |
| std::pair<bool, bool> CheckAtomicUpdateAssignmentRhs(const SomeExpr &atom, |
| const SomeExpr &rhs, parser::CharBlock source, bool suppressDiagnostics); |
| void CheckAtomicConditionalUpdateAssignment(const SomeExpr &cond, |
| parser::CharBlock condSource, const evaluate::Assignment &assign, |
| parser::CharBlock assignSource); |
| void CheckAtomicConditionalUpdateStmt( |
| const AnalyzedCondStmt &update, parser::CharBlock source); |
| void CheckAtomicUpdateOnly(const parser::OpenMPAtomicConstruct &x, |
| const parser::Block &body, parser::CharBlock source); |
| void CheckAtomicConditionalUpdate(const parser::OpenMPAtomicConstruct &x, |
| const parser::Block &body, parser::CharBlock source); |
| void CheckAtomicUpdateCapture(const parser::OpenMPAtomicConstruct &x, |
| const parser::Block &body, parser::CharBlock source); |
| void CheckAtomicConditionalUpdateCapture( |
| const parser::OpenMPAtomicConstruct &x, const parser::Block &body, |
| parser::CharBlock source); |
| void CheckAtomicRead(const parser::OpenMPAtomicConstruct &x); |
| void CheckAtomicWrite(const parser::OpenMPAtomicConstruct &x); |
| void CheckAtomicUpdate(const parser::OpenMPAtomicConstruct &x); |
| |
| // check-omp-loop.cpp |
| void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); |
| void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x); |
| void CheckSIMDNest(const parser::OpenMPConstruct &x); |
| void CheckRectangularNest(const parser::OmpDirectiveSpecification &spec, |
| const omp::LoopSequence &nest); |
| void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x); |
| const parser::Name GetLoopIndex(const parser::DoConstruct *x); |
| void CheckIterationVariables(const parser::OpenMPLoopConstruct &x); |
| std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); |
| void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x); |
| void CheckScanModifier(const parser::OmpClause::Reduction &x); |
| void CheckDistLinear(const parser::OpenMPLoopConstruct &x); |
| void CheckUnrollFullTripCount(const parser::OpenMPLoopConstruct &x); |
| |
| void BeginMetadirectiveVariantScope(); |
| void EndMetadirectiveVariantScope(); |
| |
| // check-omp-variant.cpp |
| void CheckMetadirectiveVariantsWithoutLoop(std::size_t firstVariant = 0); |
| void CheckOmpDeclareVariantDirective( |
| const parser::OmpDeclareVariantDirective &); |
| void CheckDeclareVariantUserConditions(const parser::OmpContextSelector &); |
| const std::list<parser::OmpTraitProperty> &GetTraitPropertyList( |
| const parser::OmpTraitSelector &); |
| std::optional<llvm::omp::Clause> GetClauseFromProperty( |
| const parser::OmpTraitProperty &); |
| |
| void CheckTraitSelectorList(const std::list<parser::OmpTraitSelector> &); |
| void CheckContextSelectorSpecification(const parser::OmpContextSelector &); |
| void CheckTraitSetSelector(const parser::OmpTraitSetSelector &); |
| void CheckTraitScore(const parser::OmpTraitScore &); |
| bool VerifyTraitPropertyLists( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitSelector( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitADMO( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitCondition( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitDeviceNum( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitRequires( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| void CheckTraitSimd( |
| const parser::OmpTraitSetSelector &, const parser::OmpTraitSelector &); |
| |
| // check-omp-structure.cpp |
| using ClauseIterator = |
| decltype(std::declval<const parser::OmpClauseList>().v.begin()); |
| bool IsAllowedClause(llvm::omp::Clause clauseId); |
| bool CheckAllowedClause(llvm::omp::Clause clauseId, |
| parser::CharBlock clauseSource, llvm::omp::Directive dirId); |
| void CheckArgumentObjectKind(const parser::OmpClause &x); |
| void CheckDirectiveSpelling( |
| parser::CharBlock spelling, llvm::omp::Directive id); |
| void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x); |
| void CheckDirectiveInPureProcedure( |
| parser::CharBlock source, llvm::omp::Directive id); |
| void CheckClauses(parser::OmpDirectiveName dirName, |
| llvm::iterator_range<ClauseIterator> beginClauses, |
| llvm::iterator_range<ClauseIterator> endClauses); |
| void AnalyzeObject(const parser::OmpObject &object); |
| std::pair<const parser::OmpClause *, const parser::OmpClause *> |
| FindMutuallyExclusiveClauses(llvm::omp::ClauseSet exclusive, |
| const std::vector<const parser::OmpClause *> &clauses); |
| |
| const parser::OpenMPConstruct *GetCurrentConstruct() const; |
| void CheckSourceLabel(const parser::Label &); |
| void CheckLabelContext(const parser::CharBlock, const parser::CharBlock, |
| const parser::OpenMPConstruct *, const parser::OpenMPConstruct *); |
| void ClearLabels(); |
| void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars, |
| const std::list<parser::Name> &nameList, const parser::CharBlock &item, |
| const std::string &clauseName); |
| void CheckMultListItems(); |
| void CheckStructureComponent( |
| const parser::OmpObject &object, llvm::omp::Clause clauseId); |
| void CheckStructureComponent( |
| const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); |
| bool HasInvalidWorksharingNesting( |
| const parser::OmpDirectiveName &name, const llvm::omp::DirectiveSet &); |
| |
| bool IsCloselyNestedRegion(const llvm::omp::DirectiveSet &set); |
| bool IsNestedInDirective(llvm::omp::Directive directive); |
| bool IsCombinedParallelWorksharing(llvm::omp::Directive directive) const; |
| bool InTargetRegion(); |
| void HasInvalidTeamsNesting( |
| const llvm::omp::Directive &dir, const parser::CharBlock &source); |
| bool HasRequires(llvm::omp::Clause req); |
| void CheckAllowedMapTypes( |
| parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>); |
| |
| llvm::StringRef getClauseName(llvm::omp::Clause clause) override; |
| llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; |
| |
| template < // |
| typename LessTy, typename RangeTy, |
| typename IterTy = decltype(std::declval<RangeTy>().begin())> |
| std::optional<IterTy> FindDuplicate(RangeTy &&); |
| |
| void CheckDependList(const parser::DataRef &); |
| void CheckDoacross( |
| const parser::OmpDoacross &doa, llvm::omp::Clause clauseId); |
| void CheckDimsModifier(parser::CharBlock source, size_t numValues, |
| const parser::OmpDimsModifier &x); |
| void CheckTypeParamInquiry(const parser::CharBlock &source, |
| const parser::OmpObject &object, llvm::omp::Directive dirId); |
| void CheckTypeParamInquiry(const parser::CharBlock &source, |
| const parser::OmpObject &object, llvm::omp::Clause clauseId); |
| void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source, |
| const parser::OmpObject &object, llvm::StringRef clause = ""); |
| void CheckVarIsNotPartOfAnotherVar(const parser::CharBlock &source, |
| const parser::OmpObjectList &objList, llvm::StringRef clause = ""); |
| void CheckThreadprivateOrDeclareTargetVar(const parser::Designator &); |
| void CheckThreadprivateOrDeclareTargetVar(const parser::Name &); |
| void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObject &); |
| void CheckThreadprivateOrDeclareTargetVar(const parser::OmpObjectList &); |
| void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); |
| void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause); |
| void CheckCrayPointee(const parser::OmpObjectList &objectList, |
| llvm::StringRef clause, bool suggestToUseCrayPointer = true); |
| void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); |
| void CheckDefaultNoneInAssociatedLoop( |
| const parser::OmpDirectiveSpecification &, const parser::DoConstruct &, |
| UnorderedSymbolSet &diagnosed); |
| void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); |
| void CheckCopyingPolymorphicAllocatable( |
| SymbolSourceMap &, const llvm::omp::Clause); |
| void CheckPrivateSymbolsInOuterCxt( |
| SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); |
| bool CheckTargetBlockOnlyTeams(const parser::Block &); |
| void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); |
| void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock); |
| void CheckIndividualAllocateDirective( |
| const parser::OmpAllocateDirective &x, bool isExecutable); |
| void CheckExecutableAllocateDirective(const parser::OmpAllocateDirective &x); |
| |
| void CheckUsesAllocatorsSpec( |
| const parser::OmpUsesAllocatorsClause::AllocatorSpec &spec); |
| void CheckUsesAllocatorsTraits( |
| const parser::OmpTraitsArray &traits, parser::CharBlock source); |
| |
| void CheckIteratorRange(const parser::OmpIteratorSpecifier &x); |
| void CheckIteratorModifier(const parser::OmpIterator &x); |
| |
| void CheckTargetNest(const parser::OpenMPConstruct &x); |
| void CheckTargetUpdate(); |
| void CheckTaskgraph(const parser::OmpBlockConstruct &x); |
| void CheckDependenceType(const parser::OmpDependenceType::Value &x); |
| void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x); |
| std::optional<llvm::omp::Directive> GetCancelType( |
| llvm::omp::Directive cancelDir, const parser::CharBlock &cancelSource, |
| const std::optional<parser::OmpClauseList> &maybeClauses); |
| void CheckCancellationNest( |
| const parser::CharBlock &source, llvm::omp::Directive type); |
| void CheckReductionObjects( |
| const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); |
| bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident, |
| parser::CharBlock source, llvm::omp::Clause clauseId); |
| void CheckReductionObjectTypes(const parser::OmpObjectList &objects, |
| const parser::OmpReductionIdentifier &ident); |
| void CheckReductionModifier(const parser::OmpReductionModifier &); |
| void CheckLastprivateModifier(const parser::OmpLastprivateModifier &); |
| void CheckSingleConstruct(const parser::OmpBlockConstruct &x); |
| void CheckMasterNesting(const parser::OmpBlockConstruct &x); |
| void ChecksOnOrderedAsBlock(); |
| void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); |
| void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x); |
| void ChecksOnOrderedAsStandalone(); |
| void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue); |
| void CheckReductionArraySection( |
| const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId); |
| void CheckArraySection(const parser::ArrayElement &arrayElement, |
| const parser::Name &name, const llvm::omp::Clause clause); |
| void CheckLastPartRefForArraySection( |
| const parser::Designator &designator, llvm::omp::Clause clauseId); |
| void CheckSharedBindingInOuterContext( |
| const parser::OmpObjectList &ompObjectList); |
| void CheckIfContiguous(const parser::OmpObject &object); |
| const parser::Name *GetObjectName(const parser::OmpObject &object); |
| void CheckInitOnDepobj(const parser::OpenMPDepobjConstruct &depobj, |
| const parser::OmpClause &initClause); |
| void CheckAllowedRequiresClause(llvm::omp::Clause clause); |
| void AddEndDirectiveClauses(const parser::OmpClauseList &clauses); |
| void CheckTempDescriptorMappings(); |
| |
| void EnterDirectiveNest(const int index) { directiveNest_[index]++; } |
| void ExitDirectiveNest(const int index) { directiveNest_[index]--; } |
| int GetDirectiveNest(const int index) { return directiveNest_[index]; } |
| |
| bool deviceConstructFound_{false}; |
| enum directiveNestType : int { |
| ApplyNest, |
| SIMDNest, |
| TargetBlockOnlyTeams, |
| TargetNest, |
| DeclarativeNest, |
| ContextSelectorNest, |
| MetadirectiveNest, |
| LastType = MetadirectiveNest, |
| }; |
| int directiveNest_[LastType + 1] = {0}; |
| |
| std::set<std::pair<const Symbol *, const Symbol *>> declareVariantPairs_; |
| // For each variant procedure: its construct-selector-set as an ordered list |
| // of elements (a leaf construct directive plus a normalized rendering of any |
| // properties), and the source of the DECLARE VARIANT directive that first |
| // established the set. |
| std::map<const Symbol *, |
| std::pair< |
| llvm::SmallVector<std::pair<llvm::omp::Directive, std::string>, 4>, |
| parser::CharBlock>> |
| declareVariantConstructSets_; |
| // Tracks the procedures that appear as a base in DECLARE VARIANT. |
| std::set<const Symbol *> declareVariantBases_; |
| |
| int allocateDirectiveLevel_{0}; |
| parser::CharBlock visitedAtomicSource_; |
| |
| // Mapping of directive-name-modifier constituents to the sources of the |
| // IF clauses that referenced them. If there was no modifier, the entire |
| // directive is assumed to be listed. |
| std::map<llvm::omp::Directive, parser::CharBlock> ifLeafs_; |
| |
| // Track symbols with temporary stack descriptors mapped in TARGET ENTER DATA |
| // and symbols mapped in TARGET EXIT DATA within the current function scope. |
| // Used to warn about potential issues with mapping temporary descriptors. |
| std::multimap<const Symbol *, parser::CharBlock> tempDescriptorEnterMaps_; |
| std::set<const Symbol *> tempDescriptorExitMaps_; |
| |
| // Stack of nested DO loops and OpenMP constructs. |
| // This is used to verify DO loop nest for DOACROSS, and branches into |
| // and out of OpenMP constructs. |
| std::vector<LoopOrConstruct> constructStack_; |
| // Scopes for scoping units. |
| std::vector<const Scope *> scopeStack_; |
| // Stack of directive specifications (except for SECTION). |
| // This is to allow visitor functions to see all specified clauses, since |
| // they are only recorded in DirectiveContext as they are processed. |
| std::vector<const parser::OmpDirectiveSpecification *> dirStack_; |
| |
| enum class PartKind : int { |
| // There are also other "parts", such as internal-subprogram-part, etc, |
| // but we're keeping track of these two for now. |
| SpecificationPart, |
| ExecutionPart, |
| }; |
| std::vector<PartKind> partStack_; |
| |
| struct MetadirectiveLoopVariant { |
| const parser::traits::OmpContextSelectorSpecification *selector; |
| const parser::OmpDirectiveSpecification *spec; |
| bool checkDefaultNoneInAssociatedLoop; |
| }; |
| std::vector<MetadirectiveLoopVariant> metadirectiveLoopVariants_; |
| std::vector<std::size_t> metadirectiveVariantScopeStarts_; |
| const parser::traits::OmpContextSelectorSpecification *currentWhenSelector_{ |
| nullptr}; |
| |
| std::multimap<const parser::Label, |
| std::pair<parser::CharBlock, const parser::OpenMPConstruct *>> |
| sourceLabels_; |
| std::map<const parser::Label, |
| std::pair<parser::CharBlock, const parser::OpenMPConstruct *>> |
| targetLabels_; |
| parser::CharBlock currentStatementSource_; |
| }; |
| |
| template <typename A> |
| void OmpStructureChecker::Enter(const parser::Statement<A> &statement) { |
| currentStatementSource_ = statement.source; |
| // Keep track of the labels in all the labelled statements |
| if (statement.label) { |
| auto label{statement.label.value()}; |
| // Get the context to check if the labelled statement is in an |
| // enclosing OpenMP construct |
| auto *thisConstruct{GetCurrentConstruct()}; |
| targetLabels_.emplace( |
| label, std::make_pair(currentStatementSource_, thisConstruct)); |
| // Check if a statement that causes a jump to the 'label' |
| // has already been encountered |
| auto range{sourceLabels_.equal_range(label)}; |
| for (auto it{range.first}; it != range.second; ++it) { |
| // Check if both the statement with 'label' and the statement that |
| // causes a jump to the 'label' are in the same scope |
| CheckLabelContext(it->second.first, currentStatementSource_, |
| it->second.second, thisConstruct); |
| } |
| } |
| } |
| |
| /// Find a duplicate entry in the range, and return an iterator to it. |
| /// If there are no duplicate entries, return nullopt. |
| template <typename LessTy, typename RangeTy, typename IterTy> |
| std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) { |
| // Deal with iterators, since the actual elements may be rvalues (i.e. |
| // have no addresses), for example with custom-constructed ranges that |
| // are not simple c.begin()..c.end(). |
| std::set<IterTy, LessTy> uniq; |
| for (auto it{range.begin()}, end{range.end()}; it != end; ++it) { |
| if (!uniq.insert(it).second) { |
| return it; |
| } |
| } |
| return std::nullopt; |
| } |
| } // namespace Fortran::semantics |
| #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ |