1 //===-- lib/Semantics/check-omp-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-omp-structure.h" 10 #include "flang/Parser/parse-tree.h" 11 #include "flang/Semantics/tools.h" 12 #include <unordered_map> 13 14 namespace Fortran::semantics { 15 16 static OmpClauseSet doAllowedClauses{llvm::omp::Clause::OMPC_private, 17 llvm::omp::Clause::OMPC_firstprivate, llvm::omp::Clause::OMPC_lastprivate, 18 llvm::omp::Clause::OMPC_linear, llvm::omp::Clause::OMPC_reduction}; 19 static OmpClauseSet doAllowedOnceClauses{llvm::omp::Clause::OMPC_schedule, 20 llvm::omp::Clause::OMPC_collapse, llvm::omp::Clause::OMPC_ordered}; 21 22 static OmpClauseSet simdAllowedClauses{llvm::omp::Clause::OMPC_linear, 23 llvm::omp::Clause::OMPC_aligned, llvm::omp::Clause::OMPC_private, 24 llvm::omp::Clause::OMPC_lastprivate, llvm::omp::Clause::OMPC_reduction}; 25 static OmpClauseSet simdAllowedOnceClauses{llvm::omp::Clause::OMPC_collapse, 26 llvm::omp::Clause::OMPC_safelen, llvm::omp::Clause::OMPC_simdlen}; 27 28 static OmpClauseSet parallelAllowedClauses{llvm::omp::Clause::OMPC_default, 29 llvm::omp::Clause::OMPC_private, llvm::omp::Clause::OMPC_firstprivate, 30 llvm::omp::Clause::OMPC_shared, llvm::omp::Clause::OMPC_copyin, 31 llvm::omp::Clause::OMPC_reduction}; 32 static OmpClauseSet parallelAllowedOnceClauses{llvm::omp::Clause::OMPC_if, 33 llvm::omp::Clause::OMPC_num_threads, llvm::omp::Clause::OMPC_proc_bind}; 34 35 static OmpClauseSet taskloopAllowedClauses{llvm::omp::Clause::OMPC_shared, 36 llvm::omp::Clause::OMPC_private, llvm::omp::Clause::OMPC_firstprivate, 37 llvm::omp::Clause::OMPC_lastprivate, llvm::omp::Clause::OMPC_default, 38 llvm::omp::Clause::OMPC_untied, llvm::omp::Clause::OMPC_mergeable, 39 llvm::omp::Clause::OMPC_nogroup}; 40 static OmpClauseSet taskloopAllowedOnceClauses{llvm::omp::Clause::OMPC_collapse, 41 llvm::omp::Clause::OMPC_if, llvm::omp::Clause::OMPC_final, 42 llvm::omp::Clause::OMPC_priority}; 43 static OmpClauseSet taskloopAllowedExclusiveClauses{ 44 llvm::omp::Clause::OMPC_grainsize, llvm::omp::Clause::OMPC_num_tasks}; 45 46 static OmpClauseSet distributeAllowedClauses{llvm::omp::Clause::OMPC_private, 47 llvm::omp::Clause::OMPC_firstprivate, llvm::omp::Clause::OMPC_lastprivate}; 48 static OmpClauseSet distributeAllowedOnceClauses{ 49 llvm::omp::Clause::OMPC_collapse, llvm::omp::Clause::OMPC_dist_schedule}; 50 51 static OmpClauseSet targetAllowedClauses{llvm::omp::Clause::OMPC_if, 52 llvm::omp::Clause::OMPC_private, llvm::omp::Clause::OMPC_firstprivate, 53 llvm::omp::Clause::OMPC_map, llvm::omp::Clause::OMPC_is_device_ptr, 54 llvm::omp::Clause::OMPC_depend}; 55 static OmpClauseSet targetAllowedOnceClauses{llvm::omp::Clause::OMPC_device, 56 llvm::omp::Clause::OMPC_defaultmap, llvm::omp::Clause::OMPC_nowait}; 57 58 static OmpClauseSet teamsAllowedClauses{llvm::omp::Clause::OMPC_private, 59 llvm::omp::Clause::OMPC_firstprivate, llvm::omp::Clause::OMPC_shared, 60 llvm::omp::Clause::OMPC_reduction}; 61 static OmpClauseSet teamsAllowedOnceClauses{llvm::omp::Clause::OMPC_num_teams, 62 llvm::omp::Clause::OMPC_thread_limit, llvm::omp::Clause::OMPC_default}; 63 64 static OmpClauseSet sectionsAllowedClauses{llvm::omp::Clause::OMPC_private, 65 llvm::omp::Clause::OMPC_firstprivate, llvm::omp::Clause::OMPC_lastprivate, 66 llvm::omp::Clause::OMPC_reduction}; 67 68 std::string OmpStructureChecker::ContextDirectiveAsFortran() { 69 auto dir = llvm::omp::getOpenMPDirectiveName(GetContext().directive).str(); 70 std::transform(dir.begin(), dir.end(), dir.begin(), 71 [](unsigned char c) { return std::toupper(c); }); 72 return dir; 73 } 74 75 void OmpStructureChecker::SayNotMatching( 76 const parser::CharBlock &beginSource, const parser::CharBlock &endSource) { 77 context_ 78 .Say(endSource, "Unmatched %s directive"_err_en_US, 79 parser::ToUpperCaseLetters(endSource.ToString())) 80 .Attach(beginSource, "Does not match directive"_en_US); 81 } 82 83 bool OmpStructureChecker::HasInvalidWorksharingNesting( 84 const parser::CharBlock &source, const OmpDirectiveSet &set) { 85 // set contains all the invalid closely nested directives 86 // for the given directive (`source` here) 87 if (CurrentDirectiveIsNested() && set.test(GetContext().directive)) { 88 context_.Say(source, 89 "A worksharing region may not be closely nested inside a " 90 "worksharing, explicit task, taskloop, critical, ordered, atomic, or " 91 "master region"_err_en_US); 92 return true; 93 } 94 return false; 95 } 96 97 void OmpStructureChecker::CheckAllowed(llvm::omp::Clause type) { 98 if (!GetContext().allowedClauses.test(type) && 99 !GetContext().allowedOnceClauses.test(type) && 100 !GetContext().allowedExclusiveClauses.test(type)) { 101 context_.Say(GetContext().clauseSource, 102 "%s clause is not allowed on the %s directive"_err_en_US, 103 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(type).str()), 104 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())); 105 return; 106 } 107 if ((GetContext().allowedOnceClauses.test(type) || 108 GetContext().allowedExclusiveClauses.test(type)) && 109 FindClause(type)) { 110 context_.Say(GetContext().clauseSource, 111 "At most one %s clause can appear on the %s directive"_err_en_US, 112 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(type).str()), 113 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())); 114 return; 115 } 116 if (GetContext().allowedExclusiveClauses.test(type)) { 117 std::vector<llvm::omp::Clause> others; 118 GetContext().allowedExclusiveClauses.IterateOverMembers( 119 [&](llvm::omp::Clause o) { 120 if (FindClause(o)) { 121 others.emplace_back(o); 122 } 123 }); 124 for (const auto &e : others) { 125 context_.Say(GetContext().clauseSource, 126 "%s and %s are mutually exclusive and may not appear on the " 127 "same %s directive"_err_en_US, 128 parser::ToUpperCaseLetters( 129 llvm::omp::getOpenMPClauseName(type).str()), 130 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(e).str()), 131 parser::ToUpperCaseLetters(GetContext().directiveSource.ToString())); 132 } 133 if (!others.empty()) { 134 return; 135 } 136 } 137 SetContextClauseInfo(type); 138 } 139 140 void OmpStructureChecker::CheckRequired(llvm::omp::Clause c) { 141 if (!FindClause(c)) { 142 context_.Say(GetContext().directiveSource, 143 "At least one %s clause must appear on the %s directive"_err_en_US, 144 parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(c).str()), 145 ContextDirectiveAsFortran()); 146 } 147 } 148 149 void OmpStructureChecker::RequiresConstantPositiveParameter( 150 const llvm::omp::Clause &clause, const parser::ScalarIntConstantExpr &i) { 151 if (const auto v{GetIntValue(i)}) { 152 if (*v <= 0) { 153 context_.Say(GetContext().clauseSource, 154 "The parameter of the %s clause must be " 155 "a constant positive integer expression"_err_en_US, 156 parser::ToUpperCaseLetters( 157 llvm::omp::getOpenMPClauseName(clause).str())); 158 } 159 } 160 } 161 162 void OmpStructureChecker::RequiresPositiveParameter( 163 const llvm::omp::Clause &clause, const parser::ScalarIntExpr &i) { 164 if (const auto v{GetIntValue(i)}) { 165 if (*v <= 0) { 166 context_.Say(GetContext().clauseSource, 167 "The parameter of the %s clause must be " 168 "a positive integer expression"_err_en_US, 169 parser::ToUpperCaseLetters( 170 llvm::omp::getOpenMPClauseName(clause).str())); 171 } 172 } 173 } 174 175 void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) { 176 // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check 177 } 178 179 void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { 180 const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)}; 181 const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)}; 182 183 // check matching, End directive is optional 184 if (const auto &endLoopDir{ 185 std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) { 186 CheckMatching<parser::OmpLoopDirective>(beginLoopDir, *endLoopDir); 187 } 188 189 if (beginDir.v != llvm::omp::Directive::OMPD_do) 190 PushContext(beginDir.source, beginDir.v); 191 192 switch (beginDir.v) { 193 // 2.7.1 do-clause -> private-clause | 194 // firstprivate-clause | 195 // lastprivate-clause | 196 // linear-clause | 197 // reduction-clause | 198 // schedule-clause | 199 // collapse-clause | 200 // ordered-clause 201 case llvm::omp::Directive::OMPD_do: { 202 // nesting check 203 HasInvalidWorksharingNesting(beginDir.source, 204 {llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_sections, 205 llvm::omp::Directive::OMPD_single, 206 llvm::omp::Directive::OMPD_workshare, 207 llvm::omp::Directive::OMPD_task, 208 llvm::omp::Directive::OMPD_taskloop, 209 llvm::omp::Directive::OMPD_critical, 210 llvm::omp::Directive::OMPD_ordered, 211 llvm::omp::Directive::OMPD_atomic, 212 llvm::omp::Directive::OMPD_master}); 213 PushContext(beginDir.source, llvm::omp::Directive::OMPD_do); 214 SetContextAllowed(doAllowedClauses); 215 SetContextAllowedOnce(doAllowedOnceClauses); 216 } break; 217 218 // 2.11.1 parallel-do-clause -> parallel-clause | 219 // do-clause 220 case llvm::omp::Directive::OMPD_parallel_do: { 221 SetContextAllowed(parallelAllowedClauses | doAllowedClauses); 222 SetContextAllowedOnce(parallelAllowedOnceClauses | doAllowedOnceClauses); 223 } break; 224 225 // 2.8.1 simd-clause -> safelen-clause | 226 // simdlen-clause | 227 // linear-clause | 228 // aligned-clause | 229 // private-clause | 230 // lastprivate-clause | 231 // reduction-clause | 232 // collapse-clause 233 case llvm::omp::Directive::OMPD_simd: { 234 SetContextAllowed(simdAllowedClauses); 235 SetContextAllowedOnce(simdAllowedOnceClauses); 236 } break; 237 238 // 2.8.3 do-simd-clause -> do-clause | 239 // simd-clause 240 case llvm::omp::Directive::OMPD_do_simd: { 241 SetContextAllowed(doAllowedClauses | simdAllowedClauses); 242 SetContextAllowedOnce(doAllowedOnceClauses | simdAllowedOnceClauses); 243 } break; 244 245 // 2.11.4 parallel-do-simd-clause -> parallel-clause | 246 // do-simd-clause 247 case llvm::omp::Directive::OMPD_parallel_do_simd: { 248 SetContextAllowed( 249 parallelAllowedClauses | doAllowedClauses | simdAllowedClauses); 250 SetContextAllowedOnce(parallelAllowedOnceClauses | doAllowedOnceClauses | 251 simdAllowedOnceClauses); 252 } break; 253 254 // 2.9.2 taskloop-clause -> if-clause | 255 // shared-clause | 256 // private-clause | 257 // firstprivate-clause | 258 // lastprivate-clause | 259 // default-clause | 260 // grainsize-clause | 261 // num-tasks-clause | 262 // collapse-clause | 263 // final-clause | 264 // priority-clause | 265 // untied-clause | 266 // mergeable-clause | 267 // nogroup-clause 268 case llvm::omp::Directive::OMPD_taskloop: { 269 SetContextAllowed(taskloopAllowedClauses); 270 SetContextAllowedOnce(taskloopAllowedOnceClauses); 271 SetContextAllowedExclusive(taskloopAllowedExclusiveClauses); 272 } break; 273 274 // 2.9.3 taskloop-simd-clause -> taskloop-clause | 275 // simd-clause 276 case llvm::omp::Directive::OMPD_taskloop_simd: { 277 SetContextAllowed((taskloopAllowedClauses | simdAllowedClauses) - 278 llvm::omp::Clause::OMPC_reduction); 279 SetContextAllowedOnce(taskloopAllowedOnceClauses | simdAllowedOnceClauses); 280 SetContextAllowedExclusive(taskloopAllowedExclusiveClauses); 281 } break; 282 283 // 2.10.8 distribute-clause -> private-clause | 284 // firstprivate-clause | 285 // lastprivate-clause | 286 // collapse-clause | 287 // dist-schedule-clause 288 case llvm::omp::Directive::OMPD_distribute: { 289 SetContextAllowed(distributeAllowedClauses); 290 SetContextAllowedOnce(distributeAllowedOnceClauses); 291 } break; 292 293 // 2.10.9 distribute-simd-clause -> distribute-clause | 294 // simd-clause 295 case llvm::omp::Directive::OMPD_distribute_simd: { 296 SetContextAllowed(distributeAllowedClauses | simdAllowedClauses); 297 SetContextAllowedOnce( 298 distributeAllowedOnceClauses | simdAllowedOnceClauses); 299 } break; 300 301 // 2.10.10 distribute-parallel-do-clause -> distribute-clause | 302 // parallel-do-clause 303 case llvm::omp::Directive::OMPD_distribute_parallel_do: { 304 SetContextAllowed( 305 distributeAllowedClauses | parallelAllowedClauses | doAllowedClauses); 306 SetContextAllowedOnce(distributeAllowedOnceClauses | 307 parallelAllowedOnceClauses | doAllowedOnceClauses); 308 } break; 309 310 // 2.10.11 distribute-parallel-do-simd-clause -> distribute-clause | 311 // parallel-do-simd-clause 312 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd: { 313 SetContextAllowed(distributeAllowedClauses | parallelAllowedClauses | 314 doAllowedClauses | simdAllowedClauses); 315 SetContextAllowedOnce(distributeAllowedOnceClauses | 316 parallelAllowedOnceClauses | doAllowedOnceClauses | simdAllowedClauses); 317 } break; 318 319 // 2.11.6 target-parallel-do-clause -> target-clause | 320 // parallel-do-clause 321 case llvm::omp::Directive::OMPD_target_parallel_do: { 322 SetContextAllowed( 323 targetAllowedClauses | parallelAllowedClauses | doAllowedClauses); 324 SetContextAllowedOnce( 325 (targetAllowedOnceClauses | parallelAllowedOnceClauses | 326 doAllowedOnceClauses) - 327 llvm::omp::Clause::OMPC_nowait); 328 } break; 329 330 // 2.11.7 target-parallel-do-simd-clause -> target-clause | 331 // parallel-do-simd-clause 332 case llvm::omp::Directive::OMPD_target_parallel_do_simd: { 333 SetContextAllowed(targetAllowedClauses | parallelAllowedClauses | 334 doAllowedClauses | simdAllowedClauses); 335 SetContextAllowedOnce( 336 (targetAllowedOnceClauses | parallelAllowedOnceClauses | 337 doAllowedOnceClauses | simdAllowedOnceClauses) - 338 llvm::omp::Clause::OMPC_nowait); 339 } break; 340 341 // 2.11.8 target-simd-clause -> target-clause | 342 // simd-clause 343 case llvm::omp::Directive::OMPD_target_simd: { 344 SetContextAllowed(targetAllowedClauses | simdAllowedClauses); 345 SetContextAllowedOnce(targetAllowedOnceClauses | simdAllowedOnceClauses); 346 } break; 347 348 // 2.11.10 teams-distribute-clause -> teams-clause | 349 // distribute-clause 350 case llvm::omp::Directive::OMPD_teams_distribute: { 351 SetContextAllowed(teamsAllowedClauses | distributeAllowedClauses); 352 SetContextAllowedOnce( 353 teamsAllowedOnceClauses | distributeAllowedOnceClauses); 354 } break; 355 356 // 2.11.11 teams-distribute-simd-clause -> teams-clause | 357 // distribute-simd-clause 358 case llvm::omp::Directive::OMPD_teams_distribute_simd: { 359 SetContextAllowed( 360 teamsAllowedClauses | distributeAllowedClauses | simdAllowedClauses); 361 SetContextAllowedOnce(teamsAllowedOnceClauses | 362 distributeAllowedOnceClauses | simdAllowedOnceClauses); 363 } break; 364 365 // 2.11.12 target-teams-distribute-clause -> target-clause | 366 // teams-distribute-clause 367 case llvm::omp::Directive::OMPD_target_teams_distribute: { 368 SetContextAllowed( 369 targetAllowedClauses | teamsAllowedClauses | distributeAllowedClauses); 370 SetContextAllowedOnce(targetAllowedOnceClauses | teamsAllowedOnceClauses | 371 distributeAllowedOnceClauses); 372 } break; 373 374 // 2.11.13 target-teams-distribute-simd-clause -> target-clause | 375 // teams-distribute-simd-clause 376 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: { 377 SetContextAllowed(targetAllowedClauses | teamsAllowedClauses | 378 distributeAllowedClauses | simdAllowedClauses); 379 SetContextAllowed(targetAllowedOnceClauses | teamsAllowedOnceClauses | 380 distributeAllowedOnceClauses | simdAllowedOnceClauses); 381 } break; 382 383 // 2.11.14 teams-distribute-parallel-do-clause -> teams-clause | 384 // distribute-parallel-do-clause 385 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do: { 386 SetContextAllowed(teamsAllowedClauses | distributeAllowedClauses | 387 parallelAllowedClauses | doAllowedClauses); 388 SetContextAllowedOnce(teamsAllowedOnceClauses | 389 distributeAllowedOnceClauses | parallelAllowedOnceClauses | 390 doAllowedOnceClauses); 391 } break; 392 393 // 2.11.15 target-teams-distribute-parallel-do-clause -> target-clause | 394 // teams-distribute-parallel-do-clause 395 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: { 396 SetContextAllowed(targetAllowedClauses | teamsAllowedClauses | 397 distributeAllowedClauses | parallelAllowedClauses | doAllowedClauses); 398 SetContextAllowedOnce(targetAllowedOnceClauses | teamsAllowedOnceClauses | 399 distributeAllowedOnceClauses | parallelAllowedOnceClauses | 400 doAllowedOnceClauses); 401 } break; 402 403 // 2.11.16 teams-distribute-parallel-do-clause -> teams-clause | 404 // distribute-parallel-do-simd-clause 405 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd: { 406 SetContextAllowed(teamsAllowedClauses | distributeAllowedClauses | 407 parallelAllowedClauses | doAllowedClauses | simdAllowedClauses); 408 SetContextAllowedOnce(teamsAllowedOnceClauses | 409 distributeAllowedOnceClauses | parallelAllowedOnceClauses | 410 doAllowedOnceClauses | simdAllowedOnceClauses); 411 } break; 412 413 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: { 414 SetContextAllowed(targetAllowedClauses | teamsAllowedClauses | 415 distributeAllowedClauses | parallelAllowedClauses | doAllowedClauses | 416 simdAllowedClauses); 417 SetContextAllowedOnce(targetAllowedOnceClauses | teamsAllowedOnceClauses | 418 distributeAllowedOnceClauses | parallelAllowedOnceClauses | 419 doAllowedOnceClauses | simdAllowedOnceClauses); 420 } break; 421 422 default: 423 // TODO others 424 break; 425 } 426 } 427 428 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { 429 ompContext_.pop_back(); 430 } 431 432 void OmpStructureChecker::Enter(const parser::OmpEndLoopDirective &x) { 433 const auto &dir{std::get<parser::OmpLoopDirective>(x.t)}; 434 ResetPartialContext(dir.source); 435 switch (dir.v) { 436 // 2.7.1 end-do -> END DO [nowait-clause] 437 // 2.8.3 end-do-simd -> END DO SIMD [nowait-clause] 438 case llvm::omp::Directive::OMPD_do: 439 SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_do); 440 SetContextAllowed(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); 441 break; 442 case llvm::omp::Directive::OMPD_do_simd: 443 SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_do_simd); 444 SetContextAllowed(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); 445 break; 446 default: 447 // no clauses are allowed 448 break; 449 } 450 } 451 452 void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { 453 const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)}; 454 const auto &endBlockDir{std::get<parser::OmpEndBlockDirective>(x.t)}; 455 const auto &beginDir{ 456 CheckMatching<parser::OmpBlockDirective>(beginBlockDir, endBlockDir)}; 457 458 PushContext(beginDir.source, beginDir.v); 459 switch (beginDir.v) { 460 // 2.5 parallel-clause -> if-clause | 461 // num-threads-clause | 462 // default-clause | 463 // private-clause | 464 // firstprivate-clause | 465 // shared-clause | 466 // copyin-clause | 467 // reduction-clause | 468 // proc-bind-clause 469 case llvm::omp::Directive::OMPD_parallel: { 470 // reserve for nesting check 471 SetContextAllowed(parallelAllowedClauses); 472 SetContextAllowedOnce(parallelAllowedOnceClauses); 473 } break; 474 // 2.7.3 single-clause -> private-clause | 475 // firstprivate-clause 476 case llvm::omp::Directive::OMPD_single: 477 SetContextAllowed({llvm::omp::Clause::OMPC_private, 478 llvm::omp::Clause::OMPC_firstprivate}); 479 break; 480 // 2.7.4 workshare (no clauses are allowed) 481 case llvm::omp::Directive::OMPD_workshare: 482 break; 483 // 2.11.3 parallel-workshare-clause -> parallel-clause 484 case llvm::omp::Directive::OMPD_parallel_workshare: { 485 SetContextAllowed(parallelAllowedClauses); 486 SetContextAllowedOnce(parallelAllowedOnceClauses); 487 } break; 488 // 2.9.1 task-clause -> if-clause | 489 // final-clause | 490 // untied-clause | 491 // default-clause | 492 // mergeable-clause | 493 // private-clause | 494 // firstprivate-clause | 495 // shared-clause | 496 // depend-clause | 497 // priority-clause 498 case llvm::omp::Directive::OMPD_task: { 499 OmpClauseSet allowed{llvm::omp::Clause::OMPC_untied, 500 llvm::omp::Clause::OMPC_default, llvm::omp::Clause::OMPC_mergeable, 501 llvm::omp::Clause::OMPC_private, llvm::omp::Clause::OMPC_firstprivate, 502 llvm::omp::Clause::OMPC_shared, llvm::omp::Clause::OMPC_depend}; 503 SetContextAllowed(allowed); 504 OmpClauseSet allowedOnce{llvm::omp::Clause::OMPC_if, 505 llvm::omp::Clause::OMPC_final, llvm::omp::Clause::OMPC_priority}; 506 SetContextAllowedOnce(allowedOnce); 507 } break; 508 // 2.10.4 target-clause -> if-clause | 509 // device-clause | 510 // private-clause | 511 // firstprivate-clause | 512 // map-clause | 513 // is-device-ptr-clause | 514 // defaultmap-clause | 515 // nowait-clause | 516 // depend-clause 517 case llvm::omp::Directive::OMPD_target: { 518 SetContextAllowed(targetAllowedClauses); 519 SetContextAllowedOnce(targetAllowedOnceClauses); 520 } break; 521 // 2.10.7 teams-clause -> num-teams-clause | 522 // thread-limit-clause | 523 // default-clause | 524 // private-clause | 525 // firstprivate-clause | 526 // shared-clause | 527 // reduction-clause 528 case llvm::omp::Directive::OMPD_teams: { 529 SetContextAllowed(teamsAllowedClauses); 530 SetContextAllowedOnce(teamsAllowedOnceClauses); 531 } break; 532 // 2.11.9 target-teams -> target-clause | 533 // teams-clause 534 case llvm::omp::Directive::OMPD_target_teams: { 535 SetContextAllowed(targetAllowedClauses | teamsAllowedClauses); 536 SetContextAllowedOnce(targetAllowedOnceClauses | teamsAllowedOnceClauses); 537 } break; 538 // 2.10.1 target-data-clause -> if-clause | 539 // device-clause | 540 // map-clause | 541 // use-device-ptr-clause 542 case llvm::omp::Directive::OMPD_target_data: { 543 OmpClauseSet allowed{llvm::omp::Clause::OMPC_if, 544 llvm::omp::Clause::OMPC_map, llvm::omp::Clause::OMPC_use_device_ptr}; 545 SetContextAllowed(allowed); 546 SetContextAllowedOnce({llvm::omp::Clause::OMPC_device}); 547 SetContextRequired({llvm::omp::Clause::OMPC_map}); 548 } break; 549 // 2.13.1 master (no clauses are allowed) 550 case llvm::omp::Directive::OMPD_master: 551 break; 552 // 2.11.5 target-parallel-clause -> target-clause | 553 // parallel-clause 554 case llvm::omp::Directive::OMPD_target_parallel: { 555 SetContextAllowed((targetAllowedClauses | parallelAllowedClauses) - 556 llvm::omp::Clause::OMPC_copyin); 557 SetContextAllowedOnce( 558 targetAllowedOnceClauses | parallelAllowedOnceClauses); 559 } break; 560 default: 561 // TODO others 562 break; 563 } 564 } 565 566 void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { 567 ompContext_.pop_back(); 568 } 569 570 void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) { 571 const auto &beginSectionsDir{ 572 std::get<parser::OmpBeginSectionsDirective>(x.t)}; 573 const auto &endSectionsDir{std::get<parser::OmpEndSectionsDirective>(x.t)}; 574 const auto &beginDir{CheckMatching<parser::OmpSectionsDirective>( 575 beginSectionsDir, endSectionsDir)}; 576 577 PushContext(beginDir.source, beginDir.v); 578 switch (beginDir.v) { 579 // 2.7.2 sections-clause -> private-clause | 580 // firstprivate-clause | 581 // lastprivate-clause | 582 // reduction-clause 583 case llvm::omp::Directive::OMPD_sections: { 584 SetContextAllowed(sectionsAllowedClauses); 585 } break; 586 // 2.11.2 -> parallel-sections-clause -> parallel-clause | 587 // sections-clause 588 case llvm::omp::Directive::OMPD_parallel_sections: { 589 SetContextAllowed(parallelAllowedClauses | sectionsAllowedClauses); 590 SetContextAllowedOnce(parallelAllowedOnceClauses); 591 } break; 592 default: 593 // TODO others 594 break; 595 } 596 } 597 598 void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &) { 599 ompContext_.pop_back(); 600 } 601 602 void OmpStructureChecker::Enter(const parser::OmpEndSectionsDirective &x) { 603 const auto &dir{std::get<parser::OmpSectionsDirective>(x.t)}; 604 ResetPartialContext(dir.source); 605 switch (dir.v) { 606 // 2.7.2 end-sections -> END SECTIONS [nowait-clause] 607 case llvm::omp::Directive::OMPD_sections: 608 SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_sections); 609 SetContextAllowed(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); 610 break; 611 default: 612 // no clauses are allowed 613 break; 614 } 615 } 616 617 void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) { 618 const auto &dir{std::get<parser::Verbatim>(x.t)}; 619 PushContext(dir.source, llvm::omp::Directive::OMPD_declare_simd); 620 // 2.8.2 declare-simd-clause -> simdlen-clause | 621 // linear-clause | 622 // aligned-clause | 623 // uniform-clause | 624 // inbranch-clause | 625 // notinbranch-clause 626 OmpClauseSet allowed{llvm::omp::Clause::OMPC_linear, 627 llvm::omp::Clause::OMPC_aligned, llvm::omp::Clause::OMPC_uniform}; 628 SetContextAllowed(allowed); 629 SetContextAllowedOnce({llvm::omp::Clause::OMPC_simdlen}); 630 SetContextAllowedExclusive( 631 {llvm::omp::Clause::OMPC_inbranch, llvm::omp::Clause::OMPC_notinbranch}); 632 } 633 634 void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) { 635 ompContext_.pop_back(); 636 } 637 638 void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) { 639 const auto &dir{std::get<parser::Verbatim>(x.t)}; 640 PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target); 641 const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)}; 642 if (std::holds_alternative<parser::OmpDeclareTargetWithClause>(spec.u)) { 643 SetContextAllowed( 644 OmpClauseSet{llvm::omp::Clause::OMPC_to, llvm::omp::Clause::OMPC_link}); 645 } 646 } 647 648 void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &) { 649 ompContext_.pop_back(); 650 } 651 652 void OmpStructureChecker::Enter( 653 const parser::OpenMPSimpleStandaloneConstruct &x) { 654 const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)}; 655 PushContext(dir.source, dir.v); 656 switch (dir.v) { 657 case llvm::omp::Directive::OMPD_barrier: { 658 // 2.13.3 barrier 659 } break; 660 case llvm::omp::Directive::OMPD_taskwait: { 661 // 2.13.4 taskwait 662 } break; 663 case llvm::omp::Directive::OMPD_taskyield: { 664 // 2.9.4 taskyield 665 } break; 666 case llvm::omp::Directive::OMPD_target_enter_data: { 667 // 2.10.2 target-enter-data-clause -> if-clause | 668 // device-clause | 669 // map-clause | 670 // depend-clause | 671 // nowait-clause 672 OmpClauseSet allowed{llvm::omp::Clause::OMPC_map, 673 llvm::omp::Clause::OMPC_depend, llvm::omp::Clause::OMPC_nowait}; 674 SetContextAllowed(allowed); 675 OmpClauseSet allowedOnce{ 676 llvm::omp::Clause::OMPC_device, llvm::omp::Clause::OMPC_if}; 677 SetContextAllowedOnce(allowedOnce); 678 SetContextRequired({llvm::omp::Clause::OMPC_map}); 679 } break; 680 case llvm::omp::Directive::OMPD_target_exit_data: { 681 // 2.10.3 target-enter-data-clause -> if-clause | 682 // device-clause | 683 // map-clause | 684 // depend-clause | 685 // nowait-clause 686 OmpClauseSet allowed{llvm::omp::Clause::OMPC_map, 687 llvm::omp::Clause::OMPC_depend, llvm::omp::Clause::OMPC_nowait}; 688 SetContextAllowed(allowed); 689 OmpClauseSet allowedOnce{ 690 llvm::omp::Clause::OMPC_device, llvm::omp::Clause::OMPC_if}; 691 SetContextAllowedOnce(allowedOnce); 692 SetContextRequired({llvm::omp::Clause::OMPC_map}); 693 } break; 694 case llvm::omp::Directive::OMPD_target_update: { 695 // 2.10.5 target-update 696 } break; 697 case llvm::omp::Directive::OMPD_ordered: { 698 // 2.13.8 ordered-construct-clause -> depend-clause 699 OmpClauseSet allowed{llvm::omp::Clause::OMPC_depend}; 700 SetContextAllowed(allowed); 701 } break; 702 default: 703 // TODO others 704 break; 705 } 706 } 707 708 void OmpStructureChecker::Leave( 709 const parser::OpenMPSimpleStandaloneConstruct &) { 710 ompContext_.pop_back(); 711 } 712 713 void OmpStructureChecker::Enter(const parser::OpenMPFlushConstruct &x) { 714 const auto &dir{std::get<parser::Verbatim>(x.t)}; 715 PushContext(dir.source, llvm::omp::Directive::OMPD_flush); 716 } 717 718 void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &) { 719 ompContext_.pop_back(); 720 } 721 722 void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) { 723 const auto &dir{std::get<parser::Verbatim>(x.t)}; 724 PushContext(dir.source, llvm::omp::Directive::OMPD_cancel); 725 } 726 727 void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) { 728 ompContext_.pop_back(); 729 } 730 731 void OmpStructureChecker::Enter( 732 const parser::OpenMPCancellationPointConstruct &x) { 733 const auto &dir{std::get<parser::Verbatim>(x.t)}; 734 PushContext(dir.source, llvm::omp::Directive::OMPD_cancellation_point); 735 } 736 737 void OmpStructureChecker::Leave( 738 const parser::OpenMPCancellationPointConstruct &) { 739 ompContext_.pop_back(); 740 } 741 742 void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) { 743 const auto &dir{std::get<parser::OmpBlockDirective>(x.t)}; 744 ResetPartialContext(dir.source); 745 switch (dir.v) { 746 // 2.7.3 end-single-clause -> copyprivate-clause | 747 // nowait-clause 748 case llvm::omp::Directive::OMPD_single: { 749 SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_single); 750 OmpClauseSet allowed{llvm::omp::Clause::OMPC_copyprivate}; 751 SetContextAllowed(allowed); 752 OmpClauseSet allowedOnce{llvm::omp::Clause::OMPC_nowait}; 753 SetContextAllowedOnce(allowedOnce); 754 } break; 755 // 2.7.4 end-workshare -> END WORKSHARE [nowait-clause] 756 case llvm::omp::Directive::OMPD_workshare: 757 SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_workshare); 758 SetContextAllowed(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); 759 break; 760 default: 761 // no clauses are allowed 762 break; 763 } 764 } 765 766 void OmpStructureChecker::Leave(const parser::OmpClauseList &) { 767 // 2.7 Loop Construct Restriction 768 if (llvm::omp::doSet.test(GetContext().directive)) { 769 if (auto *clause{FindClause(llvm::omp::Clause::OMPC_schedule)}) { 770 // only one schedule clause is allowed 771 const auto &schedClause{std::get<parser::OmpScheduleClause>(clause->u)}; 772 if (ScheduleModifierHasType(schedClause, 773 parser::OmpScheduleModifierType::ModType::Nonmonotonic)) { 774 if (FindClause(llvm::omp::Clause::OMPC_ordered)) { 775 context_.Say(clause->source, 776 "The NONMONOTONIC modifier cannot be specified " 777 "if an ORDERED clause is specified"_err_en_US); 778 } 779 if (ScheduleModifierHasType(schedClause, 780 parser::OmpScheduleModifierType::ModType::Monotonic)) { 781 context_.Say(clause->source, 782 "The MONOTONIC and NONMONOTONIC modifiers " 783 "cannot be both specified"_err_en_US); 784 } 785 } 786 } 787 788 if (auto *clause{FindClause(llvm::omp::Clause::OMPC_ordered)}) { 789 // only one ordered clause is allowed 790 const auto &orderedClause{ 791 std::get<parser::OmpClause::Ordered>(clause->u)}; 792 793 if (orderedClause.v) { 794 if (FindClause(llvm::omp::Clause::OMPC_linear)) { 795 context_.Say(clause->source, 796 "A loop directive may not have both a LINEAR clause and " 797 "an ORDERED clause with a parameter"_err_en_US); 798 } 799 800 if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_collapse)}) { 801 const auto &collapseClause{ 802 std::get<parser::OmpClause::Collapse>(clause2->u)}; 803 // ordered and collapse both have parameters 804 if (const auto orderedValue{GetIntValue(orderedClause.v)}) { 805 if (const auto collapseValue{GetIntValue(collapseClause.v)}) { 806 if (*orderedValue > 0 && *orderedValue < *collapseValue) { 807 context_.Say(clause->source, 808 "The parameter of the ORDERED clause must be " 809 "greater than or equal to " 810 "the parameter of the COLLAPSE clause"_err_en_US); 811 } 812 } 813 } 814 } 815 } 816 817 // TODO: ordered region binding check (requires nesting implementation) 818 } 819 } // doSet 820 821 // 2.8.1 Simd Construct Restriction 822 if (llvm::omp::simdSet.test(GetContext().directive)) { 823 if (auto *clause{FindClause(llvm::omp::Clause::OMPC_simdlen)}) { 824 if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_safelen)}) { 825 const auto &simdlenClause{ 826 std::get<parser::OmpClause::Simdlen>(clause->u)}; 827 const auto &safelenClause{ 828 std::get<parser::OmpClause::Safelen>(clause2->u)}; 829 // simdlen and safelen both have parameters 830 if (const auto simdlenValue{GetIntValue(simdlenClause.v)}) { 831 if (const auto safelenValue{GetIntValue(safelenClause.v)}) { 832 if (*safelenValue > 0 && *simdlenValue > *safelenValue) { 833 context_.Say(clause->source, 834 "The parameter of the SIMDLEN clause must be less than or " 835 "equal to the parameter of the SAFELEN clause"_err_en_US); 836 } 837 } 838 } 839 } 840 } 841 842 // TODO: A list-item cannot appear in more than one aligned clause 843 } // SIMD 844 845 // 2.7.3 Single Construct Restriction 846 if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) { 847 if (auto *clause{FindClause(llvm::omp::Clause::OMPC_copyprivate)}) { 848 if (FindClause(llvm::omp::Clause::OMPC_nowait)) { 849 context_.Say(clause->source, 850 "The COPYPRIVATE clause must not be used with " 851 "the NOWAIT clause"_err_en_US); 852 } 853 } 854 } 855 856 GetContext().requiredClauses.IterateOverMembers( 857 [this](llvm::omp::Clause c) { CheckRequired(c); }); 858 } 859 860 void OmpStructureChecker::Enter(const parser::OmpClause &x) { 861 SetContextClause(x); 862 } 863 864 void OmpStructureChecker::Enter(const parser::OmpNowait &) { 865 CheckAllowed(llvm::omp::Clause::OMPC_nowait); 866 } 867 void OmpStructureChecker::Enter(const parser::OmpClause::Inbranch &) { 868 CheckAllowed(llvm::omp::Clause::OMPC_inbranch); 869 } 870 void OmpStructureChecker::Enter(const parser::OmpClause::Mergeable &) { 871 CheckAllowed(llvm::omp::Clause::OMPC_mergeable); 872 } 873 void OmpStructureChecker::Enter(const parser::OmpClause::Nogroup &) { 874 CheckAllowed(llvm::omp::Clause::OMPC_nogroup); 875 } 876 void OmpStructureChecker::Enter(const parser::OmpClause::Notinbranch &) { 877 CheckAllowed(llvm::omp::Clause::OMPC_notinbranch); 878 } 879 void OmpStructureChecker::Enter(const parser::OmpClause::Untied &) { 880 CheckAllowed(llvm::omp::Clause::OMPC_untied); 881 } 882 883 void OmpStructureChecker::Enter(const parser::OmpClause::Collapse &x) { 884 CheckAllowed(llvm::omp::Clause::OMPC_collapse); 885 // collapse clause must have a parameter 886 RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_collapse, x.v); 887 } 888 889 void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &) { 890 CheckAllowed(llvm::omp::Clause::OMPC_copyin); 891 } 892 void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &) { 893 CheckAllowed(llvm::omp::Clause::OMPC_copyprivate); 894 } 895 void OmpStructureChecker::Enter(const parser::OmpClause::Device &) { 896 CheckAllowed(llvm::omp::Clause::OMPC_device); 897 } 898 void OmpStructureChecker::Enter(const parser::OmpClause::DistSchedule &) { 899 CheckAllowed(llvm::omp::Clause::OMPC_dist_schedule); 900 } 901 void OmpStructureChecker::Enter(const parser::OmpClause::Final &) { 902 CheckAllowed(llvm::omp::Clause::OMPC_final); 903 } 904 void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &) { 905 CheckAllowed(llvm::omp::Clause::OMPC_firstprivate); 906 } 907 void OmpStructureChecker::Enter(const parser::OmpClause::From &) { 908 CheckAllowed(llvm::omp::Clause::OMPC_from); 909 } 910 void OmpStructureChecker::Enter(const parser::OmpClause::Grainsize &x) { 911 CheckAllowed(llvm::omp::Clause::OMPC_grainsize); 912 RequiresPositiveParameter(llvm::omp::Clause::OMPC_grainsize, x.v); 913 } 914 void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &) { 915 CheckAllowed(llvm::omp::Clause::OMPC_lastprivate); 916 } 917 void OmpStructureChecker::Enter(const parser::OmpClause::NumTasks &x) { 918 CheckAllowed(llvm::omp::Clause::OMPC_num_tasks); 919 RequiresPositiveParameter(llvm::omp::Clause::OMPC_num_tasks, x.v); 920 } 921 void OmpStructureChecker::Enter(const parser::OmpClause::NumTeams &x) { 922 CheckAllowed(llvm::omp::Clause::OMPC_num_teams); 923 RequiresPositiveParameter(llvm::omp::Clause::OMPC_num_teams, x.v); 924 } 925 void OmpStructureChecker::Enter(const parser::OmpClause::NumThreads &x) { 926 CheckAllowed(llvm::omp::Clause::OMPC_num_threads); 927 RequiresPositiveParameter(llvm::omp::Clause::OMPC_num_threads, x.v); 928 // if parameter is variable, defer to Expression Analysis 929 } 930 931 void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) { 932 CheckAllowed(llvm::omp::Clause::OMPC_ordered); 933 // the parameter of ordered clause is optional 934 if (const auto &expr{x.v}) { 935 RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_ordered, *expr); 936 937 // 2.8.3 Loop SIMD Construct Restriction 938 if (llvm::omp::doSimdSet.test(GetContext().directive)) { 939 context_.Say(GetContext().clauseSource, 940 "No ORDERED clause with a parameter can be specified " 941 "on the %s directive"_err_en_US, 942 ContextDirectiveAsFortran()); 943 } 944 } 945 } 946 void OmpStructureChecker::Enter(const parser::OmpClause::Priority &x) { 947 CheckAllowed(llvm::omp::Clause::OMPC_priority); 948 RequiresPositiveParameter(llvm::omp::Clause::OMPC_priority, x.v); 949 } 950 void OmpStructureChecker::Enter(const parser::OmpClause::Private &) { 951 CheckAllowed(llvm::omp::Clause::OMPC_private); 952 } 953 void OmpStructureChecker::Enter(const parser::OmpClause::Safelen &x) { 954 CheckAllowed(llvm::omp::Clause::OMPC_safelen); 955 RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_safelen, x.v); 956 } 957 void OmpStructureChecker::Enter(const parser::OmpClause::Shared &) { 958 CheckAllowed(llvm::omp::Clause::OMPC_shared); 959 } 960 void OmpStructureChecker::Enter(const parser::OmpClause::Simdlen &x) { 961 CheckAllowed(llvm::omp::Clause::OMPC_simdlen); 962 RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_simdlen, x.v); 963 } 964 void OmpStructureChecker::Enter(const parser::OmpClause::ThreadLimit &x) { 965 CheckAllowed(llvm::omp::Clause::OMPC_thread_limit); 966 RequiresPositiveParameter(llvm::omp::Clause::OMPC_thread_limit, x.v); 967 } 968 void OmpStructureChecker::Enter(const parser::OmpClause::To &) { 969 CheckAllowed(llvm::omp::Clause::OMPC_to); 970 } 971 void OmpStructureChecker::Enter(const parser::OmpClause::Link &) { 972 CheckAllowed(llvm::omp::Clause::OMPC_link); 973 } 974 void OmpStructureChecker::Enter(const parser::OmpClause::Uniform &) { 975 CheckAllowed(llvm::omp::Clause::OMPC_uniform); 976 } 977 void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &) { 978 CheckAllowed(llvm::omp::Clause::OMPC_use_device_ptr); 979 } 980 void OmpStructureChecker::Enter(const parser::OmpClause::IsDevicePtr &) { 981 CheckAllowed(llvm::omp::Clause::OMPC_is_device_ptr); 982 } 983 984 void OmpStructureChecker::Enter(const parser::OmpAlignedClause &x) { 985 CheckAllowed(llvm::omp::Clause::OMPC_aligned); 986 987 if (const auto &expr{ 988 std::get<std::optional<parser::ScalarIntConstantExpr>>(x.t)}) { 989 if (const auto v{GetIntValue(*expr)}) { 990 if (*v <= 0) { 991 context_.Say(GetContext().clauseSource, 992 "The ALIGNMENT parameter of the ALIGNED clause must be " 993 "a constant positive integer expression"_err_en_US); 994 } 995 } 996 } 997 // 2.8.1 TODO: list-item attribute check 998 } 999 void OmpStructureChecker::Enter(const parser::OmpDefaultClause &) { 1000 CheckAllowed(llvm::omp::Clause::OMPC_default); 1001 } 1002 void OmpStructureChecker::Enter(const parser::OmpDefaultmapClause &x) { 1003 CheckAllowed(llvm::omp::Clause::OMPC_defaultmap); 1004 using VariableCategory = parser::OmpDefaultmapClause::VariableCategory; 1005 if (!std::get<std::optional<VariableCategory>>(x.t)) { 1006 context_.Say(GetContext().clauseSource, 1007 "The argument TOFROM:SCALAR must be specified on the DEFAULTMAP " 1008 "clause"_err_en_US); 1009 } 1010 } 1011 void OmpStructureChecker::Enter(const parser::OmpDependClause &) { 1012 CheckAllowed(llvm::omp::Clause::OMPC_depend); 1013 } 1014 1015 void OmpStructureChecker::Enter(const parser::OmpIfClause &x) { 1016 CheckAllowed(llvm::omp::Clause::OMPC_if); 1017 1018 using dirNameModifier = parser::OmpIfClause::DirectiveNameModifier; 1019 static std::unordered_map<dirNameModifier, OmpDirectiveSet> 1020 dirNameModifierMap{{dirNameModifier::Parallel, llvm::omp::parallelSet}, 1021 {dirNameModifier::Target, llvm::omp::targetSet}, 1022 {dirNameModifier::TargetEnterData, 1023 {llvm::omp::Directive::OMPD_target_enter_data}}, 1024 {dirNameModifier::TargetExitData, 1025 {llvm::omp::Directive::OMPD_target_exit_data}}, 1026 {dirNameModifier::TargetData, 1027 {llvm::omp::Directive::OMPD_target_data}}, 1028 {dirNameModifier::TargetUpdate, 1029 {llvm::omp::Directive::OMPD_target_update}}, 1030 {dirNameModifier::Task, {llvm::omp::Directive::OMPD_task}}, 1031 {dirNameModifier::Taskloop, llvm::omp::taskloopSet}}; 1032 if (const auto &directiveName{ 1033 std::get<std::optional<dirNameModifier>>(x.t)}) { 1034 auto search{dirNameModifierMap.find(*directiveName)}; 1035 if (search == dirNameModifierMap.end() || 1036 !search->second.test(GetContext().directive)) { 1037 context_ 1038 .Say(GetContext().clauseSource, 1039 "Unmatched directive name modifier %s on the IF clause"_err_en_US, 1040 parser::ToUpperCaseLetters( 1041 parser::OmpIfClause::EnumToString(*directiveName))) 1042 .Attach( 1043 GetContext().directiveSource, "Cannot apply to directive"_en_US); 1044 } 1045 } 1046 } 1047 1048 void OmpStructureChecker::Enter(const parser::OmpLinearClause &x) { 1049 CheckAllowed(llvm::omp::Clause::OMPC_linear); 1050 1051 // 2.7 Loop Construct Restriction 1052 if ((llvm::omp::doSet | llvm::omp::simdSet).test(GetContext().directive)) { 1053 if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.u)) { 1054 context_.Say(GetContext().clauseSource, 1055 "A modifier may not be specified in a LINEAR clause " 1056 "on the %s directive"_err_en_US, 1057 ContextDirectiveAsFortran()); 1058 } 1059 } 1060 } 1061 void OmpStructureChecker::Enter(const parser::OmpMapClause &x) { 1062 CheckAllowed(llvm::omp::Clause::OMPC_map); 1063 if (const auto &maptype{std::get<std::optional<parser::OmpMapType>>(x.t)}) { 1064 using Type = parser::OmpMapType::Type; 1065 const Type &type{std::get<Type>(maptype->t)}; 1066 switch (GetContext().directive) { 1067 case llvm::omp::Directive::OMPD_target: 1068 case llvm::omp::Directive::OMPD_target_teams: 1069 case llvm::omp::Directive::OMPD_target_teams_distribute: 1070 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: 1071 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: 1072 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: 1073 case llvm::omp::Directive::OMPD_target_data: { 1074 if (type != Type::To && type != Type::From && type != Type::Tofrom && 1075 type != Type::Alloc) { 1076 context_.Say(GetContext().clauseSource, 1077 "Only the TO, FROM, TOFROM, or ALLOC map types are permitted " 1078 "for MAP clauses on the %s directive"_err_en_US, 1079 ContextDirectiveAsFortran()); 1080 } 1081 } break; 1082 case llvm::omp::Directive::OMPD_target_enter_data: { 1083 if (type != Type::To && type != Type::Alloc) { 1084 context_.Say(GetContext().clauseSource, 1085 "Only the TO or ALLOC map types are permitted " 1086 "for MAP clauses on the %s directive"_err_en_US, 1087 ContextDirectiveAsFortran()); 1088 } 1089 } break; 1090 case llvm::omp::Directive::OMPD_target_exit_data: { 1091 if (type != Type::Delete && type != Type::Release && type != Type::From) { 1092 context_.Say(GetContext().clauseSource, 1093 "Only the FROM, RELEASE, or DELETE map types are permitted " 1094 "for MAP clauses on the %s directive"_err_en_US, 1095 ContextDirectiveAsFortran()); 1096 } 1097 } break; 1098 default: 1099 break; 1100 } 1101 } 1102 } 1103 void OmpStructureChecker::Enter(const parser::OmpProcBindClause &) { 1104 CheckAllowed(llvm::omp::Clause::OMPC_proc_bind); 1105 } 1106 void OmpStructureChecker::Enter(const parser::OmpReductionClause &) { 1107 CheckAllowed(llvm::omp::Clause::OMPC_reduction); 1108 } 1109 1110 bool OmpStructureChecker::ScheduleModifierHasType( 1111 const parser::OmpScheduleClause &x, 1112 const parser::OmpScheduleModifierType::ModType &type) { 1113 const auto &modifier{ 1114 std::get<std::optional<parser::OmpScheduleModifier>>(x.t)}; 1115 if (modifier) { 1116 const auto &modType1{ 1117 std::get<parser::OmpScheduleModifier::Modifier1>(modifier->t)}; 1118 const auto &modType2{ 1119 std::get<std::optional<parser::OmpScheduleModifier::Modifier2>>( 1120 modifier->t)}; 1121 if (modType1.v.v == type || (modType2 && modType2->v.v == type)) { 1122 return true; 1123 } 1124 } 1125 return false; 1126 } 1127 void OmpStructureChecker::Enter(const parser::OmpScheduleClause &x) { 1128 CheckAllowed(llvm::omp::Clause::OMPC_schedule); 1129 1130 // 2.7 Loop Construct Restriction 1131 if (llvm::omp::doSet.test(GetContext().directive)) { 1132 const auto &kind{std::get<1>(x.t)}; 1133 const auto &chunk{std::get<2>(x.t)}; 1134 if (chunk) { 1135 if (kind == parser::OmpScheduleClause::ScheduleType::Runtime || 1136 kind == parser::OmpScheduleClause::ScheduleType::Auto) { 1137 context_.Say(GetContext().clauseSource, 1138 "When SCHEDULE clause has %s specified, " 1139 "it must not have chunk size specified"_err_en_US, 1140 parser::ToUpperCaseLetters( 1141 parser::OmpScheduleClause::EnumToString(kind))); 1142 } 1143 } 1144 1145 if (ScheduleModifierHasType( 1146 x, parser::OmpScheduleModifierType::ModType::Nonmonotonic)) { 1147 if (kind != parser::OmpScheduleClause::ScheduleType::Dynamic && 1148 kind != parser::OmpScheduleClause::ScheduleType::Guided) { 1149 context_.Say(GetContext().clauseSource, 1150 "The NONMONOTONIC modifier can only be specified with " 1151 "SCHEDULE(DYNAMIC) or SCHEDULE(GUIDED)"_err_en_US); 1152 } 1153 } 1154 } 1155 } 1156 } // namespace Fortran::semantics 1157