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 &beginCombinedDir{ 160 std::get<parser::AccBeginCombinedDirective>(x.t)}; 161 const auto &combinedDir{ 162 std::get<parser::AccCombinedDirective>(beginCombinedDir.t)}; 163 164 // check matching, End directive is optional 165 if (const auto &endCombinedDir{ 166 std::get<std::optional<parser::AccEndCombinedDirective>>(x.t)}) { 167 CheckMatching<parser::AccCombinedDirective>(combinedDir, endCombinedDir->v); 168 } 169 170 PushContextAndClauseSets(combinedDir.source, combinedDir.v); 171 } 172 173 void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) { 174 const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)}; 175 const auto &combinedDir{ 176 std::get<parser::AccCombinedDirective>(beginBlockDir.t)}; 177 switch (combinedDir.v) { 178 case llvm::acc::Directive::ACCD_kernels_loop: 179 case llvm::acc::Directive::ACCD_parallel_loop: 180 // Restriction - 1962 -> (880-881) (KERNELS LOOP) 181 // Restriction - 1962 -> (843-844) (PARALLEL LOOP) 182 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 183 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait, 184 llvm::acc::Clause::ACCC_num_gangs, 185 llvm::acc::Clause::ACCC_num_workers, 186 llvm::acc::Clause::ACCC_vector_length}); 187 break; 188 case llvm::acc::Directive::ACCD_serial_loop: 189 // Restriction - 1962 -> (919) (SERIAL LOOP) 190 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 191 {llvm::acc::Clause::ACCC_async, llvm::acc::Clause::ACCC_wait}); 192 break; 193 default: 194 break; 195 } 196 dirContext_.pop_back(); 197 } 198 199 void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) { 200 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 201 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 202 PushContextAndClauseSets(loopDir.source, loopDir.v); 203 } 204 205 void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) { 206 const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)}; 207 const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)}; 208 if (loopDir.v == llvm::acc::Directive::ACCD_loop) { 209 // Restriction - 1615-1616 210 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 211 loopOnlyAllowedAfterDeviceTypeClauses); 212 // Restriction - 1622 213 CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq, 214 {llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector, 215 llvm::acc::Clause::ACCC_worker}); 216 } 217 dirContext_.pop_back(); 218 } 219 220 void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) { 221 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 222 PushContextAndClauseSets(standaloneDir.source, standaloneDir.v); 223 } 224 225 void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) { 226 const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)}; 227 switch (standaloneDir.v) { 228 case llvm::acc::Directive::ACCD_enter_data: 229 case llvm::acc::Directive::ACCD_exit_data: 230 case llvm::acc::Directive::ACCD_set: 231 // Restriction - 1117-1118 (ENTER DATA) 232 // Restriction - 1161-1162 (EXIT DATA) 233 // Restriction - 2254 (SET) 234 CheckRequireAtLeastOneOf(); 235 break; 236 case llvm::acc::Directive::ACCD_update: 237 // Restriction - 2301 238 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 239 updateOnlyAllowedAfterDeviceTypeClauses); 240 break; 241 default: 242 break; 243 } 244 dirContext_.pop_back(); 245 } 246 247 void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) { 248 PushContextAndClauseSets(x.source, llvm::acc::Directive::ACCD_routine); 249 } 250 void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) { 251 // Restriction - 2409 252 CheckRequireAtLeastOneOf(); 253 // Restriction - 2407-2408 254 CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type, 255 routineOnlyAllowedAfterDeviceTypeClauses); 256 dirContext_.pop_back(); 257 } 258 259 // Clause checkers 260 CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse) 261 262 CHECK_SIMPLE_CLAUSE(Auto, ACCC_auto) 263 CHECK_SIMPLE_CLAUSE(Async, ACCC_async) 264 CHECK_SIMPLE_CLAUSE(Attach, ACCC_attach) 265 CHECK_SIMPLE_CLAUSE(Bind, ACCC_bind) 266 CHECK_SIMPLE_CLAUSE(Capture, ACCC_capture) 267 CHECK_SIMPLE_CLAUSE(Copy, ACCC_copy) 268 CHECK_SIMPLE_CLAUSE(Default, ACCC_default) 269 CHECK_SIMPLE_CLAUSE(DefaultAsync, ACCC_default_async) 270 CHECK_SIMPLE_CLAUSE(Delete, ACCC_delete) 271 CHECK_SIMPLE_CLAUSE(Detach, ACCC_detach) 272 CHECK_SIMPLE_CLAUSE(Device, ACCC_device) 273 CHECK_SIMPLE_CLAUSE(DeviceNum, ACCC_device_num) 274 CHECK_SIMPLE_CLAUSE(Deviceptr, ACCC_deviceptr) 275 CHECK_SIMPLE_CLAUSE(DeviceResident, ACCC_device_resident) 276 CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type) 277 CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize) 278 CHECK_SIMPLE_CLAUSE(Firstprivate, ACCC_firstprivate) 279 CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang) 280 CHECK_SIMPLE_CLAUSE(Host, ACCC_host) 281 CHECK_SIMPLE_CLAUSE(If, ACCC_if) 282 CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present) 283 CHECK_SIMPLE_CLAUSE(Independent, ACCC_independent) 284 CHECK_SIMPLE_CLAUSE(Link, ACCC_link) 285 CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create) 286 CHECK_SIMPLE_CLAUSE(Nohost, ACCC_nohost) 287 CHECK_SIMPLE_CLAUSE(NumGangs, ACCC_num_gangs) 288 CHECK_SIMPLE_CLAUSE(NumWorkers, ACCC_num_workers) 289 CHECK_SIMPLE_CLAUSE(Present, ACCC_present) 290 CHECK_SIMPLE_CLAUSE(Private, ACCC_private) 291 CHECK_SIMPLE_CLAUSE(Read, ACCC_read) 292 CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction) 293 CHECK_SIMPLE_CLAUSE(Self, ACCC_self) 294 CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq) 295 CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile) 296 CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device) 297 CHECK_SIMPLE_CLAUSE(Vector, ACCC_vector) 298 CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length) 299 CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait) 300 CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker) 301 CHECK_SIMPLE_CLAUSE(Write, ACCC_write) 302 303 void AccStructureChecker::Enter(const parser::AccClause::Create &c) { 304 CheckAllowed(llvm::acc::Clause::ACCC_create); 305 const auto &modifierClause{c.v}; 306 if (const auto &modifier{ 307 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 308 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 309 context_.Say(GetContext().clauseSource, 310 "Only the ZERO modifier is allowed for the %s clause " 311 "on the %s directive"_err_en_US, 312 parser::ToUpperCaseLetters( 313 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_create) 314 .str()), 315 ContextDirectiveAsFortran()); 316 } 317 } 318 } 319 320 void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) { 321 CheckAllowed(llvm::acc::Clause::ACCC_copyin); 322 const auto &modifierClause{c.v}; 323 if (const auto &modifier{ 324 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 325 if (modifier->v != parser::AccDataModifier::Modifier::ReadOnly) { 326 context_.Say(GetContext().clauseSource, 327 "Only the READONLY modifier is allowed for the %s clause " 328 "on the %s directive"_err_en_US, 329 parser::ToUpperCaseLetters( 330 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyin) 331 .str()), 332 ContextDirectiveAsFortran()); 333 } 334 } 335 } 336 337 void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) { 338 CheckAllowed(llvm::acc::Clause::ACCC_copyout); 339 const auto &modifierClause{c.v}; 340 if (const auto &modifier{ 341 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 342 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 343 context_.Say(GetContext().clauseSource, 344 "Only the ZERO modifier is allowed for the %s clause " 345 "on the %s directive"_err_en_US, 346 parser::ToUpperCaseLetters( 347 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyout) 348 .str()), 349 ContextDirectiveAsFortran()); 350 } 351 } 352 } 353 354 llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) { 355 return llvm::acc::getOpenACCClauseName(clause); 356 } 357 358 llvm::StringRef AccStructureChecker::getDirectiveName( 359 llvm::acc::Directive directive) { 360 return llvm::acc::getOpenACCDirectiveName(directive); 361 } 362 363 } // namespace Fortran::semantics 364