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 Leave(const parser::OmpBeginBlockDirective &); 139 void Enter(const parser::OmpEndBlockDirective &); 140 void Leave(const parser::OmpEndBlockDirective &); 141 142 void Enter(const parser::OpenMPSectionsConstruct &); 143 void Leave(const parser::OpenMPSectionsConstruct &); 144 void Enter(const parser::OmpEndSectionsDirective &); 145 void Leave(const parser::OmpEndSectionsDirective &); 146 147 void Enter(const parser::OpenMPDeclareSimdConstruct &); 148 void Leave(const parser::OpenMPDeclareSimdConstruct &); 149 void Enter(const parser::OpenMPDeclarativeAllocate &); 150 void Leave(const parser::OpenMPDeclarativeAllocate &); 151 void Enter(const parser::OpenMPDeclareTargetConstruct &); 152 void Leave(const parser::OpenMPDeclareTargetConstruct &); 153 void Enter(const parser::OpenMPExecutableAllocate &); 154 void Leave(const parser::OpenMPExecutableAllocate &); 155 void Enter(const parser::OpenMPThreadprivate &); 156 void Leave(const parser::OpenMPThreadprivate &); 157 158 void Enter(const parser::OpenMPSimpleStandaloneConstruct &); 159 void Leave(const parser::OpenMPSimpleStandaloneConstruct &); 160 void Enter(const parser::OpenMPFlushConstruct &); 161 void Leave(const parser::OpenMPFlushConstruct &); 162 void Enter(const parser::OpenMPCancelConstruct &); 163 void Leave(const parser::OpenMPCancelConstruct &); 164 void Enter(const parser::OpenMPCancellationPointConstruct &); 165 void Leave(const parser::OpenMPCancellationPointConstruct &); 166 void Enter(const parser::OpenMPCriticalConstruct &); 167 void Leave(const parser::OpenMPCriticalConstruct &); 168 void Enter(const parser::OpenMPAtomicConstruct &); 169 void Leave(const parser::OpenMPAtomicConstruct &); 170 171 void Leave(const parser::OmpClauseList &); 172 void Enter(const parser::OmpClause &); 173 174 void Enter(const parser::OmpAtomicRead &); 175 void Leave(const parser::OmpAtomicRead &); 176 void Enter(const parser::OmpAtomicWrite &); 177 void Leave(const parser::OmpAtomicWrite &); 178 void Enter(const parser::OmpAtomicUpdate &); 179 void Leave(const parser::OmpAtomicUpdate &); 180 void Enter(const parser::OmpAtomicCapture &); 181 void Leave(const parser::OmpAtomic &); 182 183 #define GEN_FLANG_CLAUSE_CHECK_ENTER 184 #include "llvm/Frontend/OpenMP/OMP.inc" 185 186 // Get the OpenMP Clause Kind for the corresponding Parser class 187 template <typename A> GetClauseKindForParserClass(const A &)188 llvm::omp::Clause GetClauseKindForParserClass(const A &) { 189 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP 190 #include "llvm/Frontend/OpenMP/OMP.inc" 191 } 192 193 private: 194 void CheckMultListItems(); 195 bool HasInvalidWorksharingNesting( 196 const parser::CharBlock &, const OmpDirectiveSet &); 197 bool IsCloselyNestedRegion(const OmpDirectiveSet &set); 198 void HasInvalidTeamsNesting( 199 const llvm::omp::Directive &dir, const parser::CharBlock &source); 200 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); 201 // specific clause related 202 bool ScheduleModifierHasType(const parser::OmpScheduleClause &, 203 const parser::OmpScheduleModifierType::ModType &); 204 void CheckAllowedMapTypes(const parser::OmpMapType::Type &, 205 const std::list<parser::OmpMapType::Type> &); 206 llvm::StringRef getClauseName(llvm::omp::Clause clause) override; 207 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; 208 209 void CheckDependList(const parser::DataRef &); 210 void CheckDependArraySection( 211 const common::Indirection<parser::ArrayElement> &, const parser::Name &); 212 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); 213 void CheckIsVarPartOfAnotherVar( 214 const parser::CharBlock &source, const parser::OmpObjectList &objList); 215 void CheckThreadprivateOrDeclareTargetVar( 216 const parser::OmpObjectList &objList); 217 void CheckIntentInPointer( 218 const parser::OmpObjectList &, const llvm::omp::Clause); 219 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); 220 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); 221 void CheckCopyingPolymorphicAllocatable( 222 SymbolSourceMap &, const llvm::omp::Clause); 223 void CheckPrivateSymbolsInOuterCxt( 224 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); 225 const parser::Name GetLoopIndex(const parser::DoConstruct *x); 226 void SetLoopInfo(const parser::OpenMPLoopConstruct &x); 227 void CheckIsLoopIvPartOfClause( 228 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); 229 bool CheckTargetBlockOnlyTeams(const parser::Block &); 230 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); 231 232 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); 233 void CheckDoWhile(const parser::OpenMPLoopConstruct &x); 234 void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); 235 template <typename T, typename D> bool IsOperatorValid(const T &, const D &); 236 void CheckAtomicMemoryOrderClause( 237 const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); 238 void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &); 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 CheckCancellationNest( 244 const parser::CharBlock &source, const parser::OmpCancelType::Type &type); 245 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); 246 bool CheckReductionOperators(const parser::OmpClause::Reduction &); 247 bool CheckIntrinsicOperator( 248 const parser::DefinedOperator::IntrinsicOperator &); 249 void CheckReductionTypeList(const parser::OmpClause::Reduction &); 250 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); 251 void ChecksOnOrderedAsBlock(); 252 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); 253 void ChecksOnOrderedAsStandalone(); 254 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue); 255 void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); 256 void CheckIntentInPointerAndDefinable( 257 const parser::OmpObjectList &, const llvm::omp::Clause); 258 void CheckArraySection(const parser::ArrayElement &arrayElement, 259 const parser::Name &name, const llvm::omp::Clause clause); 260 void CheckMultipleAppearanceAcrossContext( 261 const parser::OmpObjectList &ompObjectList); 262 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &); 263 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source, 264 const parser::OmpObjectList &ompObjectList); 265 void CheckPredefinedAllocatorRestriction( 266 const parser::CharBlock &source, const parser::Name &name); 267 bool isPredefinedAllocator{false}; EnterDirectiveNest(const int index)268 void EnterDirectiveNest(const int index) { directiveNest_[index]++; } ExitDirectiveNest(const int index)269 void ExitDirectiveNest(const int index) { directiveNest_[index]--; } GetDirectiveNest(const int index)270 int GetDirectiveNest(const int index) { return directiveNest_[index]; } 271 template <typename D> void CheckHintClause(D *, D *); 272 273 enum directiveNestType { 274 SIMDNest, 275 TargetBlockOnlyTeams, 276 TargetNest, 277 LastType 278 }; 279 int directiveNest_[LastType + 1] = {0}; 280 }; 281 } // namespace Fortran::semantics 282 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ 283