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 void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) { 242 const auto &verbatim = std::get<parser::Verbatim>(x.t); 243 PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache); 244 SetContextDirectiveSource(verbatim.source); 245 } 246 void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) { 247 dirContext_.pop_back(); 248 } 249 250 // Clause checkers 251 CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse) 252 253 CHECK_SIMPLE_CLAUSE(Auto, ACCC_auto) 254 CHECK_SIMPLE_CLAUSE(Async, ACCC_async) 255 CHECK_SIMPLE_CLAUSE(Attach, ACCC_attach) 256 CHECK_SIMPLE_CLAUSE(Bind, ACCC_bind) 257 CHECK_SIMPLE_CLAUSE(Capture, ACCC_capture) 258 CHECK_SIMPLE_CLAUSE(Copy, ACCC_copy) 259 CHECK_SIMPLE_CLAUSE(Default, ACCC_default) 260 CHECK_SIMPLE_CLAUSE(DefaultAsync, ACCC_default_async) 261 CHECK_SIMPLE_CLAUSE(Delete, ACCC_delete) 262 CHECK_SIMPLE_CLAUSE(Detach, ACCC_detach) 263 CHECK_SIMPLE_CLAUSE(Device, ACCC_device) 264 CHECK_SIMPLE_CLAUSE(DeviceNum, ACCC_device_num) 265 CHECK_SIMPLE_CLAUSE(Deviceptr, ACCC_deviceptr) 266 CHECK_SIMPLE_CLAUSE(DeviceResident, ACCC_device_resident) 267 CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type) 268 CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize) 269 CHECK_SIMPLE_CLAUSE(Firstprivate, ACCC_firstprivate) 270 CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang) 271 CHECK_SIMPLE_CLAUSE(Host, ACCC_host) 272 CHECK_SIMPLE_CLAUSE(If, ACCC_if) 273 CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present) 274 CHECK_SIMPLE_CLAUSE(Independent, ACCC_independent) 275 CHECK_SIMPLE_CLAUSE(Link, ACCC_link) 276 CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create) 277 CHECK_SIMPLE_CLAUSE(Nohost, ACCC_nohost) 278 CHECK_SIMPLE_CLAUSE(NumGangs, ACCC_num_gangs) 279 CHECK_SIMPLE_CLAUSE(NumWorkers, ACCC_num_workers) 280 CHECK_SIMPLE_CLAUSE(Present, ACCC_present) 281 CHECK_SIMPLE_CLAUSE(Private, ACCC_private) 282 CHECK_SIMPLE_CLAUSE(Read, ACCC_read) 283 CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction) 284 CHECK_SIMPLE_CLAUSE(Self, ACCC_self) 285 CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq) 286 CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile) 287 CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device) 288 CHECK_SIMPLE_CLAUSE(Vector, ACCC_vector) 289 CHECK_SIMPLE_CLAUSE(VectorLength, ACCC_vector_length) 290 CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait) 291 CHECK_SIMPLE_CLAUSE(Worker, ACCC_worker) 292 CHECK_SIMPLE_CLAUSE(Write, ACCC_write) 293 294 void AccStructureChecker::Enter(const parser::AccClause::Create &c) { 295 CheckAllowed(llvm::acc::Clause::ACCC_create); 296 const auto &modifierClause{c.v}; 297 if (const auto &modifier{ 298 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 299 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 300 context_.Say(GetContext().clauseSource, 301 "Only the ZERO modifier is allowed for the %s clause " 302 "on the %s directive"_err_en_US, 303 parser::ToUpperCaseLetters( 304 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_create) 305 .str()), 306 ContextDirectiveAsFortran()); 307 } 308 } 309 } 310 311 void AccStructureChecker::Enter(const parser::AccClause::Copyin &c) { 312 CheckAllowed(llvm::acc::Clause::ACCC_copyin); 313 const auto &modifierClause{c.v}; 314 if (const auto &modifier{ 315 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 316 if (CheckAllowedModifier(llvm::acc::Clause::ACCC_copyin)) 317 return; 318 if (modifier->v != parser::AccDataModifier::Modifier::ReadOnly) { 319 context_.Say(GetContext().clauseSource, 320 "Only the READONLY modifier is allowed for the %s clause " 321 "on the %s directive"_err_en_US, 322 parser::ToUpperCaseLetters( 323 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyin) 324 .str()), 325 ContextDirectiveAsFortran()); 326 } 327 } 328 } 329 330 void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) { 331 CheckAllowed(llvm::acc::Clause::ACCC_copyout); 332 const auto &modifierClause{c.v}; 333 if (const auto &modifier{ 334 std::get<std::optional<parser::AccDataModifier>>(modifierClause.t)}) { 335 if (CheckAllowedModifier(llvm::acc::Clause::ACCC_copyout)) 336 return; 337 if (modifier->v != parser::AccDataModifier::Modifier::Zero) { 338 context_.Say(GetContext().clauseSource, 339 "Only the ZERO modifier is allowed for the %s clause " 340 "on the %s directive"_err_en_US, 341 parser::ToUpperCaseLetters( 342 llvm::acc::getOpenACCClauseName(llvm::acc::Clause::ACCC_copyout) 343 .str()), 344 ContextDirectiveAsFortran()); 345 } 346 } 347 } 348 349 llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) { 350 return llvm::acc::getOpenACCClauseName(clause); 351 } 352 353 llvm::StringRef AccStructureChecker::getDirectiveName( 354 llvm::acc::Directive directive) { 355 return llvm::acc::getOpenACCDirectiveName(directive); 356 } 357 358 } // namespace Fortran::semantics 359