1 //===-- lib/Semantics/check-acc-structure.cpp -----------------------------===// 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 #include "check-acc-structure.h" 10 #include "flang/Parser/parse-tree.h" 11 #include "flang/Semantics/tools.h" 12 13 #define CHECK_SIMPLE_CLAUSE(X, Y) \ 14 void AccStructureChecker::Enter(const parser::AccClause::X &) { \ 15 CheckAllowed(llvm::acc::Clause::Y); \ 16 } 17 18 #define CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(X, Y) \ 19 void AccStructureChecker::Enter(const parser::AccClause::X &c) { \ 20 CheckAllowed(llvm::acc::Clause::Y); \ 21 RequiresConstantPositiveParameter(llvm::acc::Clause::Y, c.v); \ 22 } 23 24 namespace Fortran::semantics { 25 26 static constexpr inline AccClauseSet 27 parallelAndKernelsOnlyAllowedAfterDeviceTypeClauses{ 28 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait, 29 llvm::acc::Clause::ACCC_num_gangs, llvm::acc::Clause::ACCC_num_workers, 30 llvm::acc::Clause::ACCC_vector_length}; 31 32 static constexpr inline AccClauseSet serialOnlyAllowedAfterDeviceTypeClauses{ 33 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait}; 34 35 static constexpr inline AccClauseSet loopOnlyAllowedAfterDeviceTypeClauses{ 36 llvm::acc::Clause::ACCC_auto, llvm::acc::Clause::ACCC_collapse, 37 llvm::acc::Clause::ACCC_independent, llvm::acc::Clause::ACCC_gang, 38 llvm::acc::Clause::ACCC_seq, llvm::acc::Clause::ACCC_tile, 39 llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker}; 40 41 static constexpr inline AccClauseSet updateOnlyAllowedAfterDeviceTypeClauses{ 42 llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait}; 43 44 static constexpr inline AccClauseSet routineOnlyAllowedAfterDeviceTypeClauses{ 45 llvm::acc::Clause::ACCC_bind, llvm::acc::Clause::ACCC_gang, 46 llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker}; 47 48 class NoBranchingEnforce { 49 public: 50 NoBranchingEnforce(SemanticsContext &context, 51 parser::CharBlock sourcePosition, llvm::acc::Directive directive) 52 : context_{context}, sourcePosition_{sourcePosition}, currentDirective_{ 53 directive} {} 54 template <typename T> bool Pre(const T &) { return true; } 55 template <typename T> void Post(const T &) {} 56 57 template <typename T> bool Pre(const parser::Statement<T> &statement) { 58 currentStatementSourcePosition_ = statement.source; 59 return true; 60 } 61 62 void Post(const parser::ReturnStmt &) { emitBranchOutError("RETURN"); } 63 void Post(const parser::ExitStmt &) { emitBranchOutError("EXIT"); } 64 void Post(const parser::StopStmt &) { emitBranchOutError("STOP"); } 65 66 private: 67 parser::MessageFixedText GetEnclosingMsg() { 68 return "Enclosing block construct"_en_US; 69 } 70 71 void emitBranchOutError(const char *stmt) { 72 context_ 73 .Say(currentStatementSourcePosition_, 74 "%s statement is not allowed in a %s construct"_err_en_US, stmt, 75 parser::ToUpperCaseLetters( 76 llvm::acc::getOpenACCDirectiveName(currentDirective_).str())) 77 .Attach(sourcePosition_, GetEnclosingMsg()); 78 } 79 80 SemanticsContext &context_; 81 parser::CharBlock currentStatementSourcePosition_; 82 parser::CharBlock sourcePosition_; 83 llvm::acc::Directive currentDirective_; 84 }; 85 86 void AccStructureChecker::Enter(const parser::AccClause &x) { 87 SetContextClause(x); 88 } 89 90 void AccStructureChecker::Leave(const parser::AccClauseList &) {} 91 92 void AccStructureChecker::Enter(const parser::OpenACCBlockConstruct &x) { 93 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)}; 94 const auto &endBlockDir{std::get<parser::AccEndBlockDirective>(x.t)}; 95 const auto &beginAccBlockDir{ 96 std::get<parser::AccBlockDirective>(beginBlockDir.t)}; 97 98 CheckMatching(beginAccBlockDir, endBlockDir.v); 99 PushContextAndClauseSets(beginAccBlockDir.source, beginAccBlockDir.v); 100 } 101 102 void AccStructureChecker::Leave(const parser::OpenACCBlockConstruct &x) { 103 const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)}; 104 const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)}; 105 const parser::Block &block{std::get<parser::Block>(x.t)}; 106 switch (blockDir.v) { 107 case llvm::acc::Directive::ACCD_kernels: 108 case llvm::acc::Directive::ACCD_parallel: 109 // Restriction - 880-881 (KERNELS) 110 // Restriction - 843-844 (PARALLEL) 111 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 112 parallelAndKernelsOnlyAllowedAfterDeviceTypeClauses); 113 // Restriction - 877 (KERNELS) 114 // Restriction - 840 (PARALLEL) 115 CheckNoBranching(block, GetContext().directive, blockDir.source); 116 break; 117 case llvm::acc::Directive::ACCD_serial: 118 // Restriction - 919 119 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 120 serialOnlyAllowedAfterDeviceTypeClauses); 121 // Restriction - 916 122 CheckNoBranching(block, llvm::acc::Directive::ACCD_serial, blockDir.source); 123 break; 124 case llvm::acc::Directive::ACCD_data: 125 // Restriction - 1117-1118 126 CheckRequireAtLeastOneOf(); 127 break; 128 case llvm::acc::Directive::ACCD_host_data: 129 // Restriction - 1578 130 CheckRequireAtLeastOneOf(); 131 break; 132 default: 133 break; 134 } 135 dirContext_.pop_back(); 136 } 137 138 void AccStructureChecker::CheckNoBranching(const parser::Block &block, 139 const llvm::acc::Directive directive, 140 const parser::CharBlock &directiveSource) const { 141 NoBranchingEnforce noBranchingEnforce{context_, directiveSource, directive}; 142 parser::Walk(block, noBranchingEnforce); 143 } 144 145 void AccStructureChecker::Enter( 146 const parser::OpenACCStandaloneDeclarativeConstruct &x) { 147 const auto &declarativeDir{std::get<parser::AccDeclarativeDirective>(x.t)}; 148 PushContextAndClauseSets(declarativeDir.source, declarativeDir.v); 149 } 150 151 void AccStructureChecker::Leave( 152 const parser::OpenACCStandaloneDeclarativeConstruct &) { 153 // Restriction - 2075 154 CheckAtLeastOneClause(); 155 dirContext_.pop_back(); 156 } 157 158 void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) { 159 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)}; 160 const auto &combinedDir{ 161 std::get<parser::AccCombinedDirective>(beginBlockDir.t)}; 162 PushContextAndClauseSets(combinedDir.source, combinedDir.v); 163 } 164 165 void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) { 166 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)}; 167 const auto &combinedDir{ 168 std::get<parser::AccCombinedDirective>(beginBlockDir.t)}; 169 switch (combinedDir.v) { 170 case llvm::acc::Directive::ACCD_kernels_loop: 171 case llvm::acc::Directive::ACCD_parallel_loop: 172 // Restriction - 1962 -> (880-881) (KERNELS LOOP) 173 // Restriction - 1962 -> (843-844) (PARALLEL LOOP) 174 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 175 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait, 176 llvm::acc::Clause::ACCC_num_gangs, 177 llvm::acc::Clause::ACCC_num_workers, 178 llvm::acc::Clause::ACCC_vector_length}); 179 break; 180 case llvm::acc::Directive::ACCD_serial_loop: 181 // Restriction - 1962 -> (919) (SERIAL LOOP) 182 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 183 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait}); 184 break; 185 default: 186 break; 187 } 188 dirContext_.pop_back(); 189 } 190 191 void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) { 192 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 193 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 194 PushContextAndClauseSets(loopDir.source, loopDir.v); 195 } 196 197 void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) { 198 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 199 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 200 if (loopDir.v == llvm::acc::Directive::ACCD_loop) { 201 // Restriction - 1615-1616 202 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 203 loopOnlyAllowedAfterDeviceTypeClauses); 204 // Restriction - 1622 205 CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq, 206 {llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector, 207 llvm::acc::Clause::ACCC_worker}); 208 } 209 dirContext_.pop_back(); 210 } 211 212 void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) { 213 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 214 PushContextAndClauseSets(standaloneDir.source, standaloneDir.v); 215 } 216 217 void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) { 218 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 219 switch (standaloneDir.v) { 220 case llvm::acc::Directive::ACCD_enter_data: 221 case llvm::acc::Directive::ACCD_exit_data: 222 case llvm::acc::Directive::ACCD_set: 223 // Restriction - 1117-1118 (ENTER DATA) 224 // Restriction - 1161-1162 (EXIT DATA) 225 // Restriction - 2254 (SET) 226 CheckRequireAtLeastOneOf(); 227 break; 228 case llvm::acc::Directive::ACCD_update: 229 // Restriction - 2301 230 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 231 updateOnlyAllowedAfterDeviceTypeClauses); 232 break; 233 default: 234 break; 235 } 236 dirContext_.pop_back(); 237 } 238 239 void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) { 240 PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_routine); 241 } 242 void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) { 243 // Restriction - 2409 244 CheckRequireAtLeastOneOf(); 245 // Restriction - 2407-2408 246 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 247 routineOnlyAllowedAfterDeviceTypeClauses); 248 dirContext_.pop_back(); 249 } 250 251 // Clause checkers 252 CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse) 253 254 CHECK_SIMPLE_CLAUSE(Auto, ACCC_auto) 255 CHECK_SIMPLE_CLAUSE(Async, ACCC_async) 256 CHECK_SIMPLE_CLAUSE(Attach, ACCC_attach) 257 CHECK_SIMPLE_CLAUSE(Bind, ACCC_bind) 258 CHECK_SIMPLE_CLAUSE(Capture, ACCC_capture) 259 CHECK_SIMPLE_CLAUSE(Copy, ACCC_copy) 260 CHECK_SIMPLE_CLAUSE(Default, ACCC_default) 261 CHECK_SIMPLE_CLAUSE(DefaultAsync, ACCC_default_async) 262 CHECK_SIMPLE_CLAUSE(Delete, ACCC_delete) 263 CHECK_SIMPLE_CLAUSE(Detach, ACCC_detach) 264 CHECK_SIMPLE_CLAUSE(Device, ACCC_device) 265 CHECK_SIMPLE_CLAUSE(DeviceNum, ACCC_device_num) 266 CHECK_SIMPLE_CLAUSE(DevicePtr, ACCC_deviceptr) 267 CHECK_SIMPLE_CLAUSE(DeviceResident, ACCC_device_resident) 268 CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type) 269 CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize) 270 CHECK_SIMPLE_CLAUSE(FirstPrivate, ACCC_firstprivate) 271 CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang) 272 CHECK_SIMPLE_CLAUSE(Host, ACCC_host) 273 CHECK_SIMPLE_CLAUSE(If, ACCC_if) 274 CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present) 275 CHECK_SIMPLE_CLAUSE(Independent, ACCC_independent) 276 CHECK_SIMPLE_CLAUSE(Link, ACCC_link) 277 CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create) 278 CHECK_SIMPLE_CLAUSE(NoHost, ACCC_nohost) 279 CHECK_SIMPLE_CLAUSE(NumGangs, ACCC_num_gangs) 280 CHECK_SIMPLE_CLAUSE(NumWorkers, ACCC_num_workers) 281 CHECK_SIMPLE_CLAUSE(Present, ACCC_present) 282 CHECK_SIMPLE_CLAUSE(Private, ACCC_private) 283 CHECK_SIMPLE_CLAUSE(Read, ACCC_read) 284 CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction) 285 CHECK_SIMPLE_CLAUSE(Self, ACCC_self) 286 CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq) 287 CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile) 288 CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device) 289 CHECK_SIMPLE_CLAUSE(Vector, ACCC_vector) 290 CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length) 291 CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait) 292 CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker) 293 CHECK_SIMPLE_CLAUSE(Write, ACCC_write) 294 295 void AccStructureChecker::Enter(const parser::AccClause::Create &c) { 296 CheckAllowed(llvm::acc::Clause::ACCC_create); 297 const auto &modifierClause{c.v}; 298 if (const auto &modifier{ 299 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 300 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 301 context_.Say(GetContext().clauseSource, 302 "Only the ZERO modifier is allowed for the %s clause " 303 "on the %s directive"_err_en_US, 304 parser::ToUpperCaseLetters( 305 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_create) 306 .str()), 307 ContextDirectiveAsFortran()); 308 } 309 } 310 } 311 312 void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) { 313 CheckAllowed(llvm::acc::Clause::ACCC_copyin); 314 const auto &modifierClause{c.v}; 315 if (const auto &modifier{ 316 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 317 if (modifier->v != parser::AccDataModifier::Modifier::ReadOnly) { 318 context_.Say(GetContext().clauseSource, 319 "Only the READONLY modifier is allowed for the %s clause " 320 "on the %s directive"_err_en_US, 321 parser::ToUpperCaseLetters( 322 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyin) 323 .str()), 324 ContextDirectiveAsFortran()); 325 } 326 } 327 } 328 329 void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) { 330 CheckAllowed(llvm::acc::Clause::ACCC_copyout); 331 const auto &modifierClause{c.v}; 332 if (const auto &modifier{ 333 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 334 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 335 context_.Say(GetContext().clauseSource, 336 "Only the ZERO modifier is allowed for the %s clause " 337 "on the %s directive"_err_en_US, 338 parser::ToUpperCaseLetters( 339 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyout) 340 .str()), 341 ContextDirectiveAsFortran()); 342 } 343 } 344 } 345 346 llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) { 347 return llvm::acc::getOpenACCClauseName(clause); 348 } 349 350 llvm::StringRef AccStructureChecker::getDirectiveName( 351 llvm::acc::Directive directive) { 352 return llvm::acc::getOpenACCDirectiveName(directive); 353 } 354 355 } // namespace Fortran::semantics 356