//===-- 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/Frontend/OpenMP/OMPConstants.h" using OmpClauseSet = Fortran::common::EnumSet; #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS #include "llvm/Frontend/OpenMP/OMP.inc" namespace llvm { namespace omp { static OmpClauseSet privateSet{ Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; static OmpClauseSet privateReductionSet{ OmpClauseSet{Clause::OMPC_reduction} | privateSet}; // omp.td cannot differentiate allowed/not allowed clause list for few // directives for fortran. nowait is not allowed on begin directive clause list // for below list of directives. Directives with conflicting list of clauses are // included in below list. static const OmpDirectiveSet noWaitClauseNotAllowedSet{ Directive::OMPD_do, Directive::OMPD_do_simd, Directive::OMPD_sections, Directive::OMPD_single, Directive::OMPD_workshare, }; } // namespace omp } // namespace llvm namespace Fortran::semantics { // Mapping from 'Symbol' to 'Source' to keep track of the variables // used in multiple clauses using SymbolSourceMap = std::multimap; // Multimap to check the triple using DirectivesClauseTriple = std::multimap>; class OmpStructureChecker : public DirectiveStructureChecker { public: using Base = DirectiveStructureChecker; OmpStructureChecker(SemanticsContext &context) : DirectiveStructureChecker(context, #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP #include "llvm/Frontend/OpenMP/OMP.inc" ) { } using llvmOmpClause = const llvm::omp::Clause; void Enter(const parser::OpenMPConstruct &); void Leave(const parser::OpenMPConstruct &); void Enter(const parser::OpenMPLoopConstruct &); void Leave(const parser::OpenMPLoopConstruct &); void Enter(const parser::OmpEndLoopDirective &); void Leave(const parser::OmpEndLoopDirective &); void Enter(const parser::OpenMPBlockConstruct &); void Leave(const parser::OpenMPBlockConstruct &); void Leave(const parser::OmpBeginBlockDirective &); void Enter(const parser::OmpEndBlockDirective &); void Leave(const parser::OmpEndBlockDirective &); void Enter(const parser::OpenMPSectionsConstruct &); void Leave(const parser::OpenMPSectionsConstruct &); void Enter(const parser::OmpEndSectionsDirective &); void Leave(const parser::OmpEndSectionsDirective &); void Enter(const parser::OpenMPDeclareSimdConstruct &); void Leave(const parser::OpenMPDeclareSimdConstruct &); void Enter(const parser::OpenMPDeclarativeAllocate &); void Leave(const parser::OpenMPDeclarativeAllocate &); void Enter(const parser::OpenMPDeclareMapperConstruct &); void Leave(const parser::OpenMPDeclareMapperConstruct &); void Enter(const parser::OpenMPDeclareTargetConstruct &); void Leave(const parser::OpenMPDeclareTargetConstruct &); void Enter(const parser::OpenMPDepobjConstruct &); void Leave(const parser::OpenMPDepobjConstruct &); void Enter(const parser::OmpDeclareTargetWithList &); void Enter(const parser::OmpDeclareTargetWithClause &); void Leave(const parser::OmpDeclareTargetWithClause &); void Enter(const parser::OpenMPExecutableAllocate &); void Leave(const parser::OpenMPExecutableAllocate &); void Enter(const parser::OpenMPAllocatorsConstruct &); void Leave(const parser::OpenMPAllocatorsConstruct &); void Enter(const parser::OpenMPRequiresConstruct &); void Leave(const parser::OpenMPRequiresConstruct &); void Enter(const parser::OpenMPThreadprivate &); void Leave(const parser::OpenMPThreadprivate &); void Enter(const parser::OpenMPSimpleStandaloneConstruct &); void Leave(const parser::OpenMPSimpleStandaloneConstruct &); void Enter(const parser::OpenMPFlushConstruct &); void Leave(const parser::OpenMPFlushConstruct &); void Enter(const parser::OpenMPCancelConstruct &); void Leave(const parser::OpenMPCancelConstruct &); void Enter(const parser::OpenMPCancellationPointConstruct &); void Leave(const parser::OpenMPCancellationPointConstruct &); void Enter(const parser::OpenMPCriticalConstruct &); void Leave(const parser::OpenMPCriticalConstruct &); void Enter(const parser::OpenMPAtomicConstruct &); void Leave(const parser::OpenMPAtomicConstruct &); void Leave(const parser::OmpClauseList &); void Enter(const parser::OmpClause &); void Enter(const parser::OmpAtomicRead &); void Leave(const parser::OmpAtomicRead &); void Enter(const parser::OmpAtomicWrite &); void Leave(const parser::OmpAtomicWrite &); void Enter(const parser::OmpAtomicUpdate &); void Leave(const parser::OmpAtomicUpdate &); void Enter(const parser::OmpAtomicCapture &); void Leave(const parser::OmpAtomic &); void Enter(const parser::DoConstruct &); void Leave(const parser::DoConstruct &); #define GEN_FLANG_CLAUSE_CHECK_ENTER #include "llvm/Frontend/OpenMP/OMP.inc" void Leave(const parser::OmpClause::Fail &); void Enter(const parser::OmpFailClause &); void Leave(const parser::OmpFailClause &); private: bool CheckAllowedClause(llvmOmpClause clause); bool IsVariableListItem(const Symbol &sym); bool IsExtendedListItem(const Symbol &sym); bool IsCommonBlock(const Symbol &sym); std::optional IsContiguous(const parser::OmpObject &object); void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars, const std::list &nameList, const parser::CharBlock &item, const std::string &clauseName); void CheckMultListItems(); void CheckStructureComponent( const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); bool HasInvalidWorksharingNesting( const parser::CharBlock &, const OmpDirectiveSet &); bool IsCloselyNestedRegion(const OmpDirectiveSet &set); void HasInvalidTeamsNesting( const llvm::omp::Directive &dir, const parser::CharBlock &source); void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x); // specific clause related void CheckAllowedMapTypes(const parser::OmpMapType::Value &, const std::list &); 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().begin())> std::optional FindDuplicate(RangeTy &&); const Symbol *GetObjectSymbol(const parser::OmpObject &object); std::optional GetObjectSource( const parser::OmpObject &object); void CheckDependList(const parser::DataRef &); void CheckDependArraySection( const common::Indirection &, const parser::Name &); void CheckDoacross(const parser::OmpDoacross &doa); bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source, const parser::OmpObjectList &objList, llvm::StringRef clause = ""); void CheckThreadprivateOrDeclareTargetVar( const parser::OmpObjectList &objList); void CheckSymbolNames( const parser::CharBlock &source, const parser::OmpObjectList &objList); void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause); void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); void CheckCopyingPolymorphicAllocatable( SymbolSourceMap &, const llvm::omp::Clause); void CheckPrivateSymbolsInOuterCxt( SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); const parser::Name GetLoopIndex(const parser::DoConstruct *x); void SetLoopInfo(const parser::OpenMPLoopConstruct &x); void CheckIsLoopIvPartOfClause( llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); bool CheckTargetBlockOnlyTeams(const parser::Block &); void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); void CheckIteratorRange(const parser::OmpIteratorSpecifier &x); void CheckIteratorModifier(const parser::OmpIterator &x); void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x); template bool IsOperatorValid(const T &, const D &); void CheckAtomicMemoryOrderClause( const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); void CheckAtomicUpdateStmt(const parser::AssignmentStmt &); void CheckAtomicCaptureStmt(const parser::AssignmentStmt &); void CheckAtomicWriteStmt(const parser::AssignmentStmt &); void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &); void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &); void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); void CheckTargetNest(const parser::OpenMPConstruct &x); void CheckTargetUpdate(); void CheckDependenceType(const parser::OmpDependenceType::Value &x); void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x); void CheckCancellationNest( const parser::CharBlock &source, const parser::OmpCancelType::Type &type); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckReductionObjects( const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); bool CheckReductionOperators(const parser::OmpClause::Reduction &); bool CheckIntrinsicOperator( const parser::DefinedOperator::IntrinsicOperator &); void CheckReductionTypeList(const parser::OmpClause::Reduction &); void CheckReductionModifier(const parser::OmpReductionModifier &); void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); void ChecksOnOrderedAsBlock(); void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x); void ChecksOnOrderedAsStandalone(); void CheckOrderedDependClause(std::optional orderedValue); void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); void CheckArraySection(const parser::ArrayElement &arrayElement, const parser::Name &name, const llvm::omp::Clause clause); void CheckSharedBindingInOuterContext( const parser::OmpObjectList &ompObjectList); void CheckIfContiguous(const parser::OmpObject &object); const parser::Name *GetObjectName(const parser::OmpObject &object); const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &); void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList); void CheckPredefinedAllocatorRestriction( const parser::CharBlock &source, const parser::Name &name); bool isPredefinedAllocator{false}; void CheckAllowedRequiresClause(llvmOmpClause clause); bool deviceConstructFound_{false}; void EnterDirectiveNest(const int index) { directiveNest_[index]++; } void ExitDirectiveNest(const int index) { directiveNest_[index]--; } int GetDirectiveNest(const int index) { return directiveNest_[index]; } template void CheckHintClause(D *, D *); inline void ErrIfAllocatableVariable(const parser::Variable &); inline void ErrIfLHSAndRHSSymbolsMatch( const parser::Variable &, const parser::Expr &); inline void ErrIfNonScalarAssignmentStmt( const parser::Variable &, const parser::Expr &); enum directiveNestType { SIMDNest, TargetBlockOnlyTeams, TargetNest, LastType }; int directiveNest_[LastType + 1] = {0}; SymbolSourceMap deferredNonVariables_; using LoopConstruct = std::variant; std::vector loopStack_; bool isFailClause{false}; }; /// Find a duplicate entry in the range, and return an iterator to it. /// If there are no duplicate entries, return nullopt. template std::optional 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 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_