@@ -541,6 +541,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPConstruct &) {
541541}
542542
543543void OmpStructureChecker::Enter (const parser::OpenMPLoopConstruct &x) {
544+ loopStack_.push_back (&x);
544545 const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t )};
545546 const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t )};
546547
@@ -933,11 +934,19 @@ void OmpStructureChecker::CheckDistLinear(
933934 }
934935}
935936
936- void OmpStructureChecker::Leave (const parser::OpenMPLoopConstruct &) {
937+ void OmpStructureChecker::Leave (const parser::OpenMPLoopConstruct &x ) {
937938 if (llvm::omp::allSimdSet.test (GetContext ().directive )) {
938939 ExitDirectiveNest (SIMDNest);
939940 }
940941 dirContext_.pop_back ();
942+
943+ assert (!loopStack_.empty () && " Expecting non-empty loop stack" );
944+ const LoopConstruct &top = loopStack_.back ();
945+ #ifndef NDEBUG
946+ auto *loopc = std::get_if<const parser::OpenMPLoopConstruct *>(&top);
947+ assert (loopc != nullptr && *loopc == &x && " Mismatched loop constructs" );
948+ #endif
949+ loopStack_.pop_back ();
941950}
942951
943952void OmpStructureChecker::Enter (const parser::OmpEndLoopDirective &x) {
@@ -1068,8 +1077,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
10681077void OmpStructureChecker::ChecksOnOrderedAsBlock () {
10691078 if (FindClause (llvm::omp::Clause::OMPC_depend)) {
10701079 context_.Say (GetContext ().clauseSource ,
1071- " DEPEND(*) clauses are not allowed when ORDERED construct is a block"
1072- " construct with an ORDERED region" _err_en_US);
1080+ " DEPEND clauses are not allowed when ORDERED construct is a block construct with an ORDERED region" _err_en_US);
10731081 return ;
10741082 }
10751083
@@ -1618,7 +1626,8 @@ void OmpStructureChecker::CheckBarrierNesting(
16181626void OmpStructureChecker::ChecksOnOrderedAsStandalone () {
16191627 if (FindClause (llvm::omp::Clause::OMPC_threads) ||
16201628 FindClause (llvm::omp::Clause::OMPC_simd)) {
1621- context_.Say (GetContext ().clauseSource ,
1629+ context_.Say (
1630+ GetContext ().clauseSource ,
16221631 " THREADS, SIMD clauses are not allowed when ORDERED construct is a "
16231632 " standalone construct with no ORDERED region" _err_en_US);
16241633 }
@@ -1645,8 +1654,9 @@ void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
16451654 }
16461655 };
16471656
1648- auto clauseAll = FindClauses (llvm::omp::Clause::OMPC_depend);
1649- for (auto itr = clauseAll.first ; itr != clauseAll.second ; ++itr) {
1657+ // Visit the DEPEND and DOACROSS clauses.
1658+ auto depClauses = FindClauses (llvm::omp::Clause::OMPC_depend);
1659+ for (auto itr = depClauses.first ; itr != depClauses.second ; ++itr) {
16501660 const auto &dependClause{
16511661 std::get<parser::OmpClause::Depend>(itr->second ->u )};
16521662 if (auto *doAcross{std::get_if<parser::OmpDoacross>(&dependClause.v .u )}) {
@@ -1656,6 +1666,11 @@ void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
16561666 " Only SINK or SOURCE dependence types are allowed when ORDERED construct is a standalone construct with no ORDERED region" _err_en_US);
16571667 }
16581668 }
1669+ auto doaClauses = FindClauses (llvm::omp::Clause::OMPC_doacross);
1670+ for (auto itr = doaClauses.first ; itr != doaClauses.second ; ++itr) {
1671+ auto &doaClause{std::get<parser::OmpClause::Doacross>(itr->second ->u )};
1672+ visitDoacross (doaClause.v .v , itr->second ->source );
1673+ }
16591674
16601675 bool isNestedInDoOrderedWithPara{false };
16611676 if (CurrentDirectiveIsNested () &&
@@ -1693,13 +1708,18 @@ void OmpStructureChecker::CheckOrderedDependClause(
16931708 }
16941709 }
16951710 };
1696- auto clauseAll {FindClauses (llvm::omp::Clause::OMPC_depend)};
1697- for (auto itr = clauseAll .first ; itr != clauseAll .second ; ++itr) {
1711+ auto depClauses {FindClauses (llvm::omp::Clause::OMPC_depend)};
1712+ for (auto itr = depClauses .first ; itr != depClauses .second ; ++itr) {
16981713 auto &dependClause{std::get<parser::OmpClause::Depend>(itr->second ->u )};
16991714 if (auto *doAcross{std::get_if<parser::OmpDoacross>(&dependClause.v .u )}) {
17001715 visitDoacross (*doAcross, itr->second ->source );
17011716 }
17021717 }
1718+ auto doaClauses = FindClauses (llvm::omp::Clause::OMPC_doacross);
1719+ for (auto itr = doaClauses.first ; itr != doaClauses.second ; ++itr) {
1720+ auto &doaClause{std::get<parser::OmpClause::Doacross>(itr->second ->u )};
1721+ visitDoacross (doaClause.v .v , itr->second ->source );
1722+ }
17031723}
17041724
17051725void OmpStructureChecker::CheckTargetUpdate () {
@@ -2677,7 +2697,6 @@ CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind)
26772697CHECK_SIMPLE_CLAUSE (Align, OMPC_align)
26782698CHECK_SIMPLE_CLAUSE (Compare, OMPC_compare)
26792699CHECK_SIMPLE_CLAUSE (CancellationConstructType, OMPC_cancellation_construct_type)
2680- CHECK_SIMPLE_CLAUSE (Doacross, OMPC_doacross)
26812700CHECK_SIMPLE_CLAUSE (OmpxAttribute, OMPC_ompx_attribute)
26822701CHECK_SIMPLE_CLAUSE (OmpxBare, OMPC_ompx_bare)
26832702CHECK_SIMPLE_CLAUSE (Fail, OMPC_fail)
@@ -3458,6 +3477,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
34583477 " Unexpected alternative in update clause" );
34593478
34603479 if (doaDep) {
3480+ CheckDoacross (*doaDep);
34613481 CheckDependenceType (doaDep->GetDepType ());
34623482 } else {
34633483 CheckTaskDependenceType (taskDep->GetTaskDepType ());
@@ -3537,6 +3557,93 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
35373557 }
35383558}
35393559
3560+ void OmpStructureChecker::Enter (const parser::OmpClause::Doacross &x) {
3561+ CheckAllowedClause (llvm::omp::Clause::OMPC_doacross);
3562+ CheckDoacross (x.v .v );
3563+ }
3564+
3565+ void OmpStructureChecker::CheckDoacross (const parser::OmpDoacross &doa) {
3566+ if (std::holds_alternative<parser::OmpDoacross::Source>(doa.u )) {
3567+ // Nothing to check here.
3568+ return ;
3569+ }
3570+
3571+ // Process SINK dependence type. SINK may only appear in an ORDER construct,
3572+ // which references a prior ORDERED(n) clause on a DO or SIMD construct
3573+ // that marks the top of the loop nest.
3574+
3575+ auto &sink{std::get<parser::OmpDoacross::Sink>(doa.u )};
3576+ const std::list<parser::OmpIteration> &vec{sink.v .v };
3577+
3578+ // Check if the variables in the iteration vector are unique.
3579+ struct Less {
3580+ bool operator ()(
3581+ const parser::OmpIteration *a, const parser::OmpIteration *b) const {
3582+ auto namea{std::get<parser::Name>(a->t )};
3583+ auto nameb{std::get<parser::Name>(b->t )};
3584+ assert (namea.symbol && nameb.symbol && " Unresolved symbols" );
3585+ // The non-determinism of the "<" doesn't matter, we only care about
3586+ // equality, i.e. a == b <=> !(a < b) && !(b < a)
3587+ return reinterpret_cast <uintptr_t >(namea.symbol ) <
3588+ reinterpret_cast <uintptr_t >(nameb.symbol );
3589+ }
3590+ };
3591+ if (auto *duplicate{FindDuplicateEntry<parser::OmpIteration, Less>(vec)}) {
3592+ auto name{std::get<parser::Name>(duplicate->t )};
3593+ context_.Say (name.source ,
3594+ " Duplicate variable '%s' in the iteration vector" _err_en_US,
3595+ name.ToString ());
3596+ }
3597+
3598+ // Check if the variables in the iteration vector are induction variables.
3599+ // Ignore any mismatch between the size of the iteration vector and the
3600+ // number of DO constructs on the stack. This is checked elsewhere.
3601+
3602+ auto GetLoopDirective{[](const parser::OpenMPLoopConstruct &x) {
3603+ auto &begin{std::get<parser::OmpBeginLoopDirective>(x.t )};
3604+ return std::get<parser::OmpLoopDirective>(begin.t ).v ;
3605+ }};
3606+ auto GetLoopClauses{[](const parser::OpenMPLoopConstruct &x)
3607+ -> const std::list<parser::OmpClause> & {
3608+ auto &begin{std::get<parser::OmpBeginLoopDirective>(x.t )};
3609+ return std::get<parser::OmpClauseList>(begin.t ).v ;
3610+ }};
3611+
3612+ std::set<const Symbol *> inductionVars;
3613+ for (const LoopConstruct &loop : llvm::reverse (loopStack_)) {
3614+ if (auto *doc{std::get_if<const parser::DoConstruct *>(&loop)}) {
3615+ // Do-construct, collect the induction variable.
3616+ if (auto &control{(*doc)->GetLoopControl ()}) {
3617+ if (auto *b{std::get_if<parser::LoopControl::Bounds>(&control->u )}) {
3618+ inductionVars.insert (b->name .thing .symbol );
3619+ }
3620+ }
3621+ } else {
3622+ // Omp-loop-construct, check if it's do/simd with an ORDERED clause.
3623+ auto *loopc{std::get_if<const parser::OpenMPLoopConstruct *>(&loop)};
3624+ assert (loopc && " Expecting OpenMPLoopConstruct" );
3625+ llvm::omp::Directive loopDir{GetLoopDirective (**loopc)};
3626+ if (loopDir == llvm::omp::OMPD_do || loopDir == llvm::omp::OMPD_simd) {
3627+ auto IsOrdered{[](const parser::OmpClause &c) {
3628+ return c.Id () == llvm::omp::OMPC_ordered;
3629+ }};
3630+ // If it has ORDERED clause, stop the traversal.
3631+ if (llvm::any_of (GetLoopClauses (**loopc), IsOrdered)) {
3632+ break ;
3633+ }
3634+ }
3635+ }
3636+ }
3637+ for (const parser::OmpIteration &iter : vec) {
3638+ auto &name{std::get<parser::Name>(iter.t )};
3639+ if (!inductionVars.count (name.symbol )) {
3640+ context_.Say (name.source ,
3641+ " The iteration vector element '%s' is not an induction variable within the ORDERED loop nest" _err_en_US,
3642+ name.ToString ());
3643+ }
3644+ }
3645+ }
3646+
35403647void OmpStructureChecker::CheckCopyingPolymorphicAllocatable (
35413648 SymbolSourceMap &symbols, const llvm::omp::Clause clause) {
35423649 if (context_.ShouldWarn (common::UsageWarning::Portability)) {
@@ -4291,6 +4398,22 @@ void OmpStructureChecker::Enter(
42914398 CheckAllowedRequiresClause (llvm::omp::Clause::OMPC_unified_shared_memory);
42924399}
42934400
4401+ void OmpStructureChecker::Enter (const parser::DoConstruct &x) {
4402+ Base::Enter (x);
4403+ loopStack_.push_back (&x);
4404+ }
4405+
4406+ void OmpStructureChecker::Leave (const parser::DoConstruct &x) {
4407+ assert (!loopStack_.empty () && " Expecting non-empty loop stack" );
4408+ const LoopConstruct &top = loopStack_.back ();
4409+ #ifndef NDEBUG
4410+ auto *doc = std::get_if<const parser::DoConstruct *>(&top);
4411+ assert (doc != nullptr && *doc == &x && " Mismatched loop constructs" );
4412+ #endif
4413+ loopStack_.pop_back ();
4414+ Base::Leave (x);
4415+ }
4416+
42944417void OmpStructureChecker::CheckAllowedRequiresClause (llvmOmpClause clause) {
42954418 CheckAllowedClause (clause);
42964419
0 commit comments