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/openmp-directive-sets.h" 21 #include "flang/Semantics/semantics.h" 22 #include "llvm/Frontend/OpenMP/OMPConstants.h" 23 24 using OmpClauseSet = 25 Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>; 26 27 #define GEN_FLANG_DIRECTIVE_CLAUSE_SETS 28 #include "llvm/Frontend/OpenMP/OMP.inc" 29 30 namespace llvm { 31 namespace omp { 32 static OmpClauseSet privateSet{ 33 Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; 34 static OmpClauseSet privateReductionSet{ 35 OmpClauseSet{Clause::OMPC_reduction} | privateSet}; 36 // omp.td cannot differentiate allowed/not allowed clause list for few 37 // directives for fortran. nowait is not allowed on begin directive clause list 38 // for below list of directives. Directives with conflicting list of clauses are 39 // included in below list. 40 static const OmpDirectiveSet noWaitClauseNotAllowedSet{ 41 Directive::OMPD_do, 42 Directive::OMPD_do_simd, 43 Directive::OMPD_sections, 44 Directive::OMPD_single, 45 Directive::OMPD_workshare, 46 }; 47 } // namespace omp 48 } // namespace llvm 49 50 namespace Fortran::semantics { 51 52 // Mapping from 'Symbol' to 'Source' to keep track of the variables 53 // used in multiple clauses 54 using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>; 55 // Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause> 56 using DirectivesClauseTriple = std::multimap<llvm::omp::Directive, 57 std::pair<llvm::omp::Directive, const OmpClauseSet>>; 58 59 class OmpStructureChecker 60 : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause, 61 parser::OmpClause, llvm::omp::Clause_enumSize> { 62 public: 63 using Base = DirectiveStructureChecker<llvm::omp::Directive, 64 llvm::omp::Clause, parser::OmpClause, llvm::omp::Clause_enumSize>; 65 66 OmpStructureChecker(SemanticsContext &context) 67 : DirectiveStructureChecker(context, 68 #define GEN_FLANG_DIRECTIVE_CLAUSE_MAP 69 #include "llvm/Frontend/OpenMP/OMP.inc" 70 ) { 71 } 72 using llvmOmpClause = const llvm::omp::Clause; 73 74 void Enter(const parser::OpenMPConstruct &); 75 void Leave(const parser::OpenMPConstruct &); 76 void Enter(const parser::OpenMPDeclarativeConstruct &); 77 void Leave(const parser::OpenMPDeclarativeConstruct &); 78 79 void Enter(const parser::OpenMPLoopConstruct &); 80 void Leave(const parser::OpenMPLoopConstruct &); 81 void Enter(const parser::OmpEndLoopDirective &); 82 void Leave(const parser::OmpEndLoopDirective &); 83 84 void Enter(const parser::OpenMPBlockConstruct &); 85 void Leave(const parser::OpenMPBlockConstruct &); 86 void Leave(const parser::OmpBeginBlockDirective &); 87 void Enter(const parser::OmpEndBlockDirective &); 88 void Leave(const parser::OmpEndBlockDirective &); 89 90 void Enter(const parser::OpenMPSectionsConstruct &); 91 void Leave(const parser::OpenMPSectionsConstruct &); 92 void Enter(const parser::OmpEndSectionsDirective &); 93 void Leave(const parser::OmpEndSectionsDirective &); 94 95 void Enter(const parser::OpenMPDeclareSimdConstruct &); 96 void Leave(const parser::OpenMPDeclareSimdConstruct &); 97 void Enter(const parser::OpenMPDeclarativeAllocate &); 98 void Leave(const parser::OpenMPDeclarativeAllocate &); 99 void Enter(const parser::OpenMPDeclareMapperConstruct &); 100 void Leave(const parser::OpenMPDeclareMapperConstruct &); 101 void Enter(const parser::OpenMPDeclareTargetConstruct &); 102 void Leave(const parser::OpenMPDeclareTargetConstruct &); 103 void Enter(const parser::OpenMPDepobjConstruct &); 104 void Leave(const parser::OpenMPDepobjConstruct &); 105 void Enter(const parser::OmpDeclareTargetWithList &); 106 void Enter(const parser::OmpDeclareTargetWithClause &); 107 void Leave(const parser::OmpDeclareTargetWithClause &); 108 void Enter(const parser::OpenMPDispatchConstruct &); 109 void Leave(const parser::OpenMPDispatchConstruct &); 110 void Enter(const parser::OmpErrorDirective &); 111 void Leave(const parser::OmpErrorDirective &); 112 void Enter(const parser::OpenMPExecutableAllocate &); 113 void Leave(const parser::OpenMPExecutableAllocate &); 114 void Enter(const parser::OpenMPAllocatorsConstruct &); 115 void Leave(const parser::OpenMPAllocatorsConstruct &); 116 void Enter(const parser::OpenMPRequiresConstruct &); 117 void Leave(const parser::OpenMPRequiresConstruct &); 118 void Enter(const parser::OpenMPThreadprivate &); 119 void Leave(const parser::OpenMPThreadprivate &); 120 121 void Enter(const parser::OpenMPSimpleStandaloneConstruct &); 122 void Leave(const parser::OpenMPSimpleStandaloneConstruct &); 123 void Enter(const parser::OpenMPFlushConstruct &); 124 void Leave(const parser::OpenMPFlushConstruct &); 125 void Enter(const parser::OpenMPCancelConstruct &); 126 void Leave(const parser::OpenMPCancelConstruct &); 127 void Enter(const parser::OpenMPCancellationPointConstruct &); 128 void Leave(const parser::OpenMPCancellationPointConstruct &); 129 void Enter(const parser::OpenMPCriticalConstruct &); 130 void Leave(const parser::OpenMPCriticalConstruct &); 131 void Enter(const parser::OpenMPAtomicConstruct &); 132 void Leave(const parser::OpenMPAtomicConstruct &); 133 134 void Leave(const parser::OmpClauseList &); 135 void Enter(const parser::OmpClause &); 136 137 void Enter(const parser::OmpAtomicRead &); 138 void Leave(const parser::OmpAtomicRead &); 139 void Enter(const parser::OmpAtomicWrite &); 140 void Leave(const parser::OmpAtomicWrite &); 141 void Enter(const parser::OmpAtomicUpdate &); 142 void Leave(const parser::OmpAtomicUpdate &); 143 void Enter(const parser::OmpAtomicCapture &); 144 void Leave(const parser::OmpAtomic &); 145 146 void Enter(const parser::DoConstruct &); 147 void Leave(const parser::DoConstruct &); 148 149 void Enter(const parser::OmpDirectiveSpecification &); 150 void Leave(const parser::OmpDirectiveSpecification &); 151 152 void Enter(const parser::OmpMetadirectiveDirective &); 153 void Leave(const parser::OmpMetadirectiveDirective &); 154 155 void Enter(const parser::OmpContextSelector &); 156 void Leave(const parser::OmpContextSelector &); 157 158 #define GEN_FLANG_CLAUSE_CHECK_ENTER 159 #include "llvm/Frontend/OpenMP/OMP.inc" 160 161 void Leave(const parser::OmpClause::Fail &); 162 void Enter(const parser::OmpFailClause &); 163 void Leave(const parser::OmpFailClause &); 164 165 private: 166 bool CheckAllowedClause(llvmOmpClause clause); 167 bool IsVariableListItem(const Symbol &sym); 168 bool IsExtendedListItem(const Symbol &sym); 169 bool IsCommonBlock(const Symbol &sym); 170 std::optional<bool> IsContiguous(const parser::OmpObject &object); 171 void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars, 172 const std::list<parser::Name> &nameList, const parser::CharBlock &item, 173 const std::string &clauseName); 174 void CheckMultListItems(); 175 void CheckStructureComponent( 176 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); 177 bool HasInvalidWorksharingNesting( 178 const parser::CharBlock &, const OmpDirectiveSet &); 179 bool IsCloselyNestedRegion(const OmpDirectiveSet &set); 180 void HasInvalidTeamsNesting( 181 const llvm::omp::Directive &dir, const parser::CharBlock &source); 182 void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); 183 void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x); 184 // specific clause related 185 void CheckAllowedMapTypes(const parser::OmpMapType::Value &, 186 const std::list<parser::OmpMapType::Value> &); 187 llvm::StringRef getClauseName(llvm::omp::Clause clause) override; 188 llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; 189 190 template < // 191 typename LessTy, typename RangeTy, 192 typename IterTy = decltype(std::declval<RangeTy>().begin())> 193 std::optional<IterTy> FindDuplicate(RangeTy &&); 194 195 const Symbol *GetObjectSymbol(const parser::OmpObject &object); 196 std::optional<parser::CharBlock> GetObjectSource( 197 const parser::OmpObject &object); 198 void CheckDependList(const parser::DataRef &); 199 void CheckDependArraySection( 200 const common::Indirection<parser::ArrayElement> &, const parser::Name &); 201 void CheckDoacross(const parser::OmpDoacross &doa); 202 bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); 203 void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source, 204 const parser::OmpObjectList &objList, llvm::StringRef clause = ""); 205 void CheckThreadprivateOrDeclareTargetVar( 206 const parser::OmpObjectList &objList); 207 void CheckSymbolNames( 208 const parser::CharBlock &source, const parser::OmpObjectList &objList); 209 void CheckIntentInPointer(SymbolSourceMap &, const llvm::omp::Clause); 210 void CheckProcedurePointer(SymbolSourceMap &, const llvm::omp::Clause); 211 void CheckCrayPointee(const parser::OmpObjectList &objectList, 212 llvm::StringRef clause, bool suggestToUseCrayPointer = true); 213 void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); 214 void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); 215 void CheckCopyingPolymorphicAllocatable( 216 SymbolSourceMap &, const llvm::omp::Clause); 217 void CheckPrivateSymbolsInOuterCxt( 218 SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); 219 const parser::Name GetLoopIndex(const parser::DoConstruct *x); 220 void SetLoopInfo(const parser::OpenMPLoopConstruct &x); 221 void CheckIsLoopIvPartOfClause( 222 llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); 223 bool CheckTargetBlockOnlyTeams(const parser::Block &); 224 void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); 225 226 void CheckIteratorRange(const parser::OmpIteratorSpecifier &x); 227 void CheckIteratorModifier(const parser::OmpIterator &x); 228 void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); 229 void CheckDoWhile(const parser::OpenMPLoopConstruct &x); 230 void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x); 231 template <typename T, typename D> bool IsOperatorValid(const T &, const D &); 232 void CheckAtomicMemoryOrderClause( 233 const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); 234 void CheckAtomicUpdateStmt(const parser::AssignmentStmt &); 235 void CheckAtomicCaptureStmt(const parser::AssignmentStmt &); 236 void CheckAtomicWriteStmt(const parser::AssignmentStmt &); 237 void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &); 238 void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &); 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 CheckTargetUpdate(); 244 void CheckDependenceType(const parser::OmpDependenceType::Value &x); 245 void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Value &x); 246 void CheckCancellationNest( 247 const parser::CharBlock &source, const parser::OmpCancelType::Type &type); 248 std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); 249 void CheckReductionObjects( 250 const parser::OmpObjectList &objects, llvm::omp::Clause clauseId); 251 bool CheckReductionOperator(const parser::OmpReductionIdentifier &ident, 252 parser::CharBlock source, llvm::omp::Clause clauseId); 253 void CheckReductionObjectTypes(const parser::OmpObjectList &objects, 254 const parser::OmpReductionIdentifier &ident); 255 void CheckReductionModifier(const parser::OmpReductionModifier &); 256 void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); 257 void ChecksOnOrderedAsBlock(); 258 void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); 259 void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x); 260 void ChecksOnOrderedAsStandalone(); 261 void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue); 262 void CheckReductionArraySection( 263 const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId); 264 void CheckArraySection(const parser::ArrayElement &arrayElement, 265 const parser::Name &name, const llvm::omp::Clause clause); 266 void CheckSharedBindingInOuterContext( 267 const parser::OmpObjectList &ompObjectList); 268 void CheckIfContiguous(const parser::OmpObject &object); 269 const parser::Name *GetObjectName(const parser::OmpObject &object); 270 const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &); 271 void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source, 272 const parser::OmpObjectList &ompObjectList); 273 void CheckPredefinedAllocatorRestriction( 274 const parser::CharBlock &source, const parser::Name &name); 275 bool isPredefinedAllocator{false}; 276 277 void CheckAllowedRequiresClause(llvmOmpClause clause); 278 bool deviceConstructFound_{false}; 279 280 void CheckAlignValue(const parser::OmpClause &); 281 282 void EnterDirectiveNest(const int index) { directiveNest_[index]++; } 283 void ExitDirectiveNest(const int index) { directiveNest_[index]--; } 284 int GetDirectiveNest(const int index) { return directiveNest_[index]; } 285 template <typename D> void CheckHintClause(D *, D *); 286 inline void ErrIfAllocatableVariable(const parser::Variable &); 287 inline void ErrIfLHSAndRHSSymbolsMatch( 288 const parser::Variable &, const parser::Expr &); 289 inline void ErrIfNonScalarAssignmentStmt( 290 const parser::Variable &, const parser::Expr &); 291 enum directiveNestType : int { 292 SIMDNest, 293 TargetBlockOnlyTeams, 294 TargetNest, 295 DeclarativeNest, 296 ContextSelectorNest, 297 LastType = ContextSelectorNest, 298 }; 299 int directiveNest_[LastType + 1] = {0}; 300 301 SymbolSourceMap deferredNonVariables_; 302 303 using LoopConstruct = std::variant<const parser::DoConstruct *, 304 const parser::OpenMPLoopConstruct *>; 305 std::vector<LoopConstruct> loopStack_; 306 bool isFailClause{false}; 307 }; 308 309 /// Find a duplicate entry in the range, and return an iterator to it. 310 /// If there are no duplicate entries, return nullopt. 311 template <typename LessTy, typename RangeTy, typename IterTy> 312 std::optional<IterTy> OmpStructureChecker::FindDuplicate(RangeTy &&range) { 313 // Deal with iterators, since the actual elements may be rvalues (i.e. 314 // have no addresses), for example with custom-constructed ranges that 315 // are not simple c.begin()..c.end(). 316 std::set<IterTy, LessTy> uniq; 317 for (auto it{range.begin()}, end{range.end()}; it != end; ++it) { 318 if (!uniq.insert(it).second) { 319 return it; 320 } 321 } 322 return std::nullopt; 323 } 324 325 } // namespace Fortran::semantics 326 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ 327