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 #include "flang/Common/enum-set.h" 19 #include "flang/Parser/parse-tree.h" 20 #include "flang/Semantics/semantics.h" 21 #include "llvm/Frontend/OpenMP/OMPConstants.h" 22 23 using OmpDirectiveSet = Fortran::common::EnumSet<llvm::omp::Directive, 24 llvm::omp::Directive_enumSize>; 25 26 using OmpClauseSet = 27 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>; 28 29 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS 30 #include "llvm/Frontend/OpenMP/OMP.inc" 31 32 namespace llvm { 33 namespace omp { 34 static OmpDirectiveSet parallelSet{Directive::OMPD_distribute_parallel_do, 35 Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel, 36 Directive::OMPD_parallel_do, Directive::OMPD_parallel_do_simd, 37 Directive::OMPD_parallel_sections, Directive::OMPD_parallel_workshare, 38 Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do, 39 Directive::OMPD_target_parallel_do_simd, 40 Directive::OMPD_target_teams_distribute_parallel_do, 41 Directive::OMPD_target_teams_distribute_parallel_do_simd, 42 Directive::OMPD_teams_distribute_parallel_do, 43 Directive::OMPD_teams_distribute_parallel_do_simd}; 44 static OmpDirectiveSet doSet{Directive::OMPD_distribute_parallel_do, 45 Directive::OMPD_distribute_parallel_do_simd, Directive::OMPD_parallel_do, 46 Directive::OMPD_parallel_do_simd, Directive::OMPD_do, 47 Directive::OMPD_do_simd, Directive::OMPD_target_parallel_do, 48 Directive::OMPD_target_parallel_do_simd, 49 Directive::OMPD_target_teams_distribute_parallel_do, 50 Directive::OMPD_target_teams_distribute_parallel_do_simd, 51 Directive::OMPD_teams_distribute_parallel_do, 52 Directive::OMPD_teams_distribute_parallel_do_simd}; 53 static OmpDirectiveSet doSimdSet{Directive::OMPD_distribute_parallel_do_simd, 54 Directive::OMPD_parallel_do_simd, Directive::OMPD_do_simd, 55 Directive::OMPD_target_parallel_do_simd, 56 Directive::OMPD_target_teams_distribute_parallel_do_simd, 57 Directive::OMPD_teams_distribute_parallel_do_simd}; 58 static OmpDirectiveSet workShareSet{ 59 OmpDirectiveSet{Directive::OMPD_workshare, 60 Directive::OMPD_parallel_workshare, Directive::OMPD_parallel_sections, 61 Directive::OMPD_sections, Directive::OMPD_single} | 62 doSet}; 63 static OmpDirectiveSet taskloopSet{ 64 Directive::OMPD_taskloop, Directive::OMPD_taskloop_simd}; 65 static OmpDirectiveSet targetSet{Directive::OMPD_target, 66 Directive::OMPD_target_parallel, Directive::OMPD_target_parallel_do, 67 Directive::OMPD_target_parallel_do_simd, Directive::OMPD_target_simd, 68 Directive::OMPD_target_teams, Directive::OMPD_target_teams_distribute, 69 Directive::OMPD_target_teams_distribute_simd}; 70 static OmpDirectiveSet simdSet{Directive::OMPD_distribute_parallel_do_simd, 71 Directive::OMPD_distribute_simd, Directive::OMPD_parallel_do_simd, 72 Directive::OMPD_do_simd, Directive::OMPD_simd, 73 Directive::OMPD_target_parallel_do_simd, 74 Directive::OMPD_target_teams_distribute_parallel_do_simd, 75 Directive::OMPD_target_teams_distribute_simd, Directive::OMPD_target_simd, 76 Directive::OMPD_taskloop_simd, 77 Directive::OMPD_teams_distribute_parallel_do_simd, 78 Directive::OMPD_teams_distribute_simd}; 79 static OmpDirectiveSet teamSet{Directive::OMPD_teams, 80 Directive::OMPD_teams_distribute, 81 Directive::OMPD_teams_distribute_parallel_do, 82 Directive::OMPD_teams_distribute_parallel_do_simd, 83 Directive::OMPD_teams_distribute_parallel_for, 84 Directive::OMPD_teams_distribute_parallel_for_simd, 85 Directive::OMPD_teams_distribute_simd}; 86 static OmpDirectiveSet taskGeneratingSet{ 87 OmpDirectiveSet{Directive::OMPD_task} | taskloopSet}; 88 static OmpDirectiveSet nestedOrderedErrSet{Directive::OMPD_critical, 89 Directive::OMPD_ordered, Directive::OMPD_atomic, Directive::OMPD_task, 90 Directive::OMPD_taskloop}; 91 static OmpDirectiveSet nestedWorkshareErrSet{ 92 OmpDirectiveSet{Directive::OMPD_task, Directive::OMPD_taskloop, 93 Directive::OMPD_critical, Directive::OMPD_ordered, 94 Directive::OMPD_atomic, Directive::OMPD_master} | 95 workShareSet}; 96 static OmpDirectiveSet nestedMasterErrSet{ 97 OmpDirectiveSet{llvm::omp::Directive::OMPD_atomic} | taskGeneratingSet | 98 workShareSet}; 99 static OmpDirectiveSet nestedBarrierErrSet{ 100 OmpDirectiveSet{Directive::OMPD_critical, Directive::OMPD_ordered, 101 Directive::OMPD_atomic, Directive::OMPD_master} | 102 taskGeneratingSet | workShareSet}; 103 static OmpClauseSet privateSet{ 104 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; 105 static OmpClauseSet privateReductionSet{ 106 OmpClauseSet{Clause::OMPC_reduction} | privateSet}; 107 } // namespace omp 108 } // namespace llvm 109 110 namespace Fortran::semantics { 111 112 // Mapping from 'Symbol' to 'Source' to keep track of the variables 113 // used in multiple clauses 114 using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>; 115 // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause> 116 using DirectivesClauseTriple = std::multimap<llvm::omp::Directive, 117 std::pair<llvm::omp::Directive, const OmpClauseSet>>; 118 119 class OmpStructureChecker 120 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause, 121 parser::OmpClause, llvm::omp::Clause_enumSize> { 122 public: OmpStructureChecker(SemanticsContext & context)123 OmpStructureChecker(SemanticsContext &context) 124 : DirectiveStructureChecker(context, 125 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP 126 #include "llvm/Frontend/OpenMP/OMP.inc" 127 ) { 128 } 129 using llvmOmpClause = const llvm::omp::Clause; 130 131 void Enter(const parser::OpenMPConstruct &); 132 void Enter(const parser::OpenMPLoopConstruct &); 133 void Leave(const parser::OpenMPLoopConstruct &); 134 void Enter(const parser::OmpEndLoopDirective &); 135 136 void Enter(const parser::OpenMPBlockConstruct &); 137 void Leave(const parser::OpenMPBlockConstruct &); 138 void Enter(const parser::OmpEndBlockDirective &); 139 void Leave(const parser::OmpEndBlockDirective &); 140 141 void Enter(const parser::OpenMPSectionsConstruct &); 142 void Leave(const parser::OpenMPSectionsConstruct &); 143 void Enter(const parser::OmpEndSectionsDirective &); 144 void Leave(const parser::OmpEndSectionsDirective &); 145 146 void Enter(const parser::OpenMPDeclareSimdConstruct &); 147 void Leave(const parser::OpenMPDeclareSimdConstruct &); 148 void Enter(const parser::OpenMPDeclarativeAllocate &); 149 void Leave(const parser::OpenMPDeclarativeAllocate &); 150 void Enter(const parser::OpenMPDeclareTargetConstruct &); 151 void Leave(const parser::OpenMPDeclareTargetConstruct &); 152 void Enter(const parser::OpenMPExecutableAllocate &); 153 void Leave(const parser::OpenMPExecutableAllocate &); 154 155 void Enter(const parser::OpenMPSimpleStandaloneConstruct &); 156 void Leave(const parser::OpenMPSimpleStandaloneConstruct &); 157 void Enter(const parser::OpenMPFlushConstruct &); 158 void Leave(const parser::OpenMPFlushConstruct &); 159 void Enter(const parser::OpenMPCancelConstruct &); 160 void Leave(const parser::OpenMPCancelConstruct &); 161 void Enter(const parser::OpenMPCancellationPointConstruct &); 162 void Leave(const parser::OpenMPCancellationPointConstruct &); 163 void Enter(const parser::OpenMPCriticalConstruct &); 164 void Leave(const parser::OpenMPCriticalConstruct &); 165 void Enter(const parser::OpenMPAtomicConstruct &); 166 void Leave(const parser::OpenMPAtomicConstruct &); 167 168 void Leave(const parser::OmpClauseList &); 169 void Enter(const parser::OmpClause &); 170 171 void Enter(const parser::OmpAtomicRead &); 172 void Leave(const parser::OmpAtomicRead &); 173 void Enter(const parser::OmpAtomicWrite &); 174 void Leave(const parser::OmpAtomicWrite &); 175 void Enter(const parser::OmpAtomicUpdate &); 176 void Leave(const parser::OmpAtomicUpdate &); 177 void Enter(const parser::OmpAtomicCapture &); 178 void Leave(const parser::OmpAtomic &); 179 180 #define GEN_FLANG_CLAUSE_CHECK_ENTER 181 #include "llvm/Frontend/OpenMP/OMP.inc" 182 183 // Get the OpenMP Clause Kind for the corresponding Parser class 184 template <typename A> GetClauseKindForParserClass(const A &)185 llvm::omp::Clause GetClauseKindForParserClass(const A &) { 186 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP 187 #include "llvm/Frontend/OpenMP/OMP.inc" 188 } 189 190 private: 191 bool HasInvalidWorksharingNesting( 192 const parser::CharBlock &, const OmpDirectiveSet &); 193 bool IsCloselyNestedRegion(const OmpDirectiveSet &set); 194 void HasInvalidTeamsNesting( 195 const llvm::omp::Directive &dir, const parser::CharBlock &source); 196 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); 197 // specific clause related 198 bool ScheduleModifierHasType(const parser::OmpScheduleClause &, 199 const parser::OmpScheduleModifierType::ModType &); 200 void CheckAllowedMapTypes(const parser::OmpMapType::Type &, 201 const std::list<parser::OmpMapType::Type> &); 202 llvm::StringRef getClauseName(llvm::omp::Clause clause) override; 203 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; 204 205 void CheckDependList(const parser::DataRef &); 206 void CheckDependArraySection( 207 const common::Indirection<parser::ArrayElement> &, const parser::Name &); 208 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); 209 void CheckIsVarPartOfAnotherVar( 210 const parser::CharBlock &source, const parser::OmpObjectList &objList); 211 void CheckIntentInPointer( 212 const parser::OmpObjectList &, const llvm::omp::Clause); 213 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); 214 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); 215 void CheckPrivateSymbolsInOuterCxt( 216 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); 217 const parser::Name GetLoopIndex(const parser::DoConstruct *x); 218 void SetLoopInfo(const parser::OpenMPLoopConstruct &x); 219 void CheckIsLoopIvPartOfClause( 220 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); 221 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); 222 223 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); 224 void CheckDoWhile(const parser::OpenMPLoopConstruct &x); 225 void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); 226 void CheckDistLinear(const parser::OpenMPLoopConstruct &x); 227 void CheckSIMDNest(const parser::OpenMPConstruct &x); 228 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); 229 void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); 230 bool CheckReductionOperators(const parser::OmpClause::Reduction &); 231 bool CheckIntrinsicOperator( 232 const parser::DefinedOperator::IntrinsicOperator &); 233 void CheckReductionTypeList(const parser::OmpClause::Reduction &); 234 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); 235 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); 236 void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); 237 void CheckIntentInPointerAndDefinable( 238 const parser::OmpObjectList &, const llvm::omp::Clause); 239 void CheckArraySection(const parser::ArrayElement &arrayElement, 240 const parser::Name &name, const llvm::omp::Clause clause); 241 void CheckMultipleAppearanceAcrossContext( 242 const parser::OmpObjectList &ompObjectList); 243 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &); 244 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source, 245 const parser::OmpObjectList &ompObjectList); 246 void CheckPredefinedAllocatorRestriction( 247 const parser::CharBlock &source, const parser::Name &name); 248 bool isPredefinedAllocator{false}; 249 }; 250 } // namespace Fortran::semantics 251 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ 252