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