diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -174,6 +174,7 @@ void Enter(const parser::OmpProcBindClause &); void Enter(const parser::OmpReductionClause &); void Enter(const parser::OmpScheduleClause &); + void Enter(const parser::OpenMPThreadprivate &); private: bool HasInvalidWorksharingNesting( @@ -195,6 +196,20 @@ const parser::OmpObjectList &, const llvm::omp::Clause); void GetSymbolsInObjectList( const parser::OmpObjectList &, std::vector &); + + void CheckIvForThreadPrivate(const parser::OpenMPLoopConstruct &x); + void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); + void CheckDoWhile(const parser::OpenMPLoopConstruct &x); + const parser::Name GetLoopIndex(const parser::DoConstruct *x); + void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + std::int64_t GetCollapseLevel(const parser::OpenMPLoopConstruct &x); + void CheckOrderedClause(const parser::OpenMPLoopConstruct &x); + void CheckIfDoOrderedClause(const parser::CharBlock &directiveSource); + void SetOrdClause(const parser::OmpClause::Ordered *c) { ordClause = c; } + const parser::OmpClause::Ordered *GetOrdClause() { return ordClause; } + + std::list threadPrivateSymbols; + const parser::OmpClause::Ordered *ordClause{nullptr}; }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -93,6 +93,156 @@ llvm::omp::Directive::OMPD_master}); PushContextAndClauseSets(beginDir.source, llvm::omp::Directive::OMPD_do); } + CheckDoWhile(x); + CheckLoopItrVariableIsInt(x); + CheckIvForThreadPrivate(x); + CheckCycleConstraints(x); + CheckOrderedClause(x); +} + +void OmpStructureChecker::CheckDoWhile(const parser::OpenMPLoopConstruct &x) { + const auto &beginLoopDir{std::get(x.t)}; + const auto &beginDir{std::get(beginLoopDir.t)}; + if (beginDir.v == llvm::omp::Directive::OMPD_do) { + if (const auto &doConstruct{ + std::get>(x.t)}) { + if (doConstruct.value().IsDoWhile()) { + const auto &doStmt{std::get>( + doConstruct.value().t)}; + context_.Say(doStmt.source, + "The do loop cannot be a DO WHILE with do directive."_err_en_US); + } + } + } +} + +void OmpStructureChecker::CheckLoopItrVariableIsInt( + const parser::OpenMPLoopConstruct &x) { + if (const auto &loopConstruct{ + std::get>(x.t)}) { + for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) { + if (loop->IsDoNormal()) { + const parser::Name &itrVal{GetLoopIndex(loop)}; + if (itrVal.symbol) { + const auto *type{itrVal.symbol->GetType()}; + if (!type->IsNumeric(TypeCategory::Integer)) { + context_.Say(itrVal.source, + "The do-loop iteration" + " variable must be of the type integer."_err_en_US, + itrVal.ToString()); + } + } + } + const auto &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + } +} + +void OmpStructureChecker::CheckIvForThreadPrivate( + const parser::OpenMPLoopConstruct &x) { + + std::int64_t collapseLevel{GetCollapseLevel(x)}; + if (!collapseLevel) + collapseLevel++; + + if (const auto &loopConstruct{ + std::get>(x.t)}) { + + if (!threadPrivateSymbols.empty()) { + for (const parser::DoConstruct *loop{&*loopConstruct}; + loop && collapseLevel; --collapseLevel) { + if (loop->IsDoNormal()) { + const parser::Name &itrVal{GetLoopIndex(loop)}; + + for (const auto *tps : threadPrivateSymbols) { + if (itrVal.symbol->name() == tps->name()) { + context_.Say(itrVal.source, + "Loop iteration variable %s is not allowed in THREADPRIVATE."_err_en_US, + itrVal.ToString()); + } + } + } + const auto &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + } + } +} + +const parser::Name OmpStructureChecker::GetLoopIndex( + const parser::DoConstruct *x) { + using Bounds = parser::LoopControl::Bounds; + return std::get(x->GetLoopControl()->u).name.thing; +} + +std::int64_t OmpStructureChecker::GetCollapseLevel( + const parser::OpenMPLoopConstruct &x) { + const auto &beginLoopDir{std::get(x.t)}; + const auto &clauseList{std::get(beginLoopDir.t)}; + + std::int64_t collapseLevel{0}; + + for (const auto &clause : clauseList.v) { + if (const auto *collapseClause{ + std::get_if(&clause.u)}) { + if (const auto v{GetIntValue(collapseClause->v)}) { + collapseLevel = *v; + break; + } + } + } + return collapseLevel; +} + +void OmpStructureChecker::CheckCycleConstraints( + const parser::OpenMPLoopConstruct &x) { + std::int64_t collapseLevel{GetCollapseLevel(x)}; + std::int64_t cycleLevel{collapseLevel - 1}; + const parser::DoConstruct *docns{nullptr}; + if (collapseLevel) { + if (const auto &loopConstruct{ + std::get>(x.t)}) { + for (const parser::DoConstruct *loop{&*loopConstruct}; loop; + --cycleLevel) { + docns = loop; + const parser::Block &blk{std::get(docns->t)}; + for (auto iit{blk.begin()}; iit != blk.end(); ++iit) { + if (const auto *ifstmt{parser::Unwrap(*iit)}) { + const auto &actionstmt{std::get<1>(ifstmt->t)}; + if (parser::Unwrap(actionstmt.statement.u)) { + + if (cycleLevel > 0) { + context_.Say(actionstmt.source, + "CYCLE statement to non-innermost collapsed !$OMP DO loop"_err_en_US); + } + } + } + } + const parser::Block &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + } + } +} + +void OmpStructureChecker::CheckOrderedClause( + const parser::OpenMPLoopConstruct &x) { + const auto &beginLoopDir{std::get(x.t)}; + const auto &clauseList{std::get(beginLoopDir.t)}; + + for (const auto &clause : clauseList.v) { + if (const auto *ordClause{ + std::get_if(&clause.u)}) { + SetOrdClause(ordClause); + } + } } void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { @@ -130,11 +280,24 @@ case llvm::omp::OMPD_parallel: CheckNoBranching(block, llvm::omp::OMPD_parallel, beginDir.source); break; + case llvm::omp::OMPD_ordered: + CheckIfDoOrderedClause(beginDir.source); + break; default: break; } } +void OmpStructureChecker::CheckIfDoOrderedClause( + const parser::CharBlock &directiveSource) { + if (!GetOrdClause()) { + context_.Say(directiveSource, + "The ORDERED clause must be present on the loop" + " construct if any ORDERED region ever binds" + " to a loop region arising from the loop construct."_err_en_US); + } +} + void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { dirContext_.pop_back(); } @@ -169,7 +332,36 @@ break; } } +void OmpStructureChecker::Enter(const parser::OpenMPThreadprivate &x) { + const auto &dir{std::get(x.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_threadprivate); + + threadPrivateSymbols.clear(); + const auto &list{std::get(x.t)}; + + for (const auto &ompObject : list.v) { + std::visit(common::visitors{ + [&](const parser::Designator &designator) { + const auto *dataRef{ + std::get_if(&designator.u)}; + if (dataRef) { + if (const parser::Name * + name{std::get_if(&dataRef->u)}) { + if (std::find(threadPrivateSymbols.begin(), + threadPrivateSymbols.end(), + name->symbol) == threadPrivateSymbols.end()) { + threadPrivateSymbols.push_back(name->symbol); + } + } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); + } +} void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) { const auto &dir{std::get(x.t)}; PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_declare_simd); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -849,6 +849,15 @@ } ClearDataSharingAttributeObjects(); SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); + + if (beginDir.v == llvm::omp::Directive::OMPD_do) { + if (const auto &doConstruct{ + std::get>(x.t)}) { + if (doConstruct.value().IsDoWhile()) { + return true; + } + } + } PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x); return true; } @@ -880,7 +889,7 @@ // or task generating construct is private in the innermost such // construct that encloses the loop bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) { - if (!dirContext_.empty() && GetContext().withinConstruct) { + if (!dirContext_.empty() && GetContext().withinConstruct && x.IsDoNormal()) { if (const auto &iv{GetLoopIndex(x)}; iv.symbol) { if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) { ResolveSeqLoopIndexInParallelOrTaskConstruct(iv); diff --git a/flang/test/Semantics/omp-do04.f90 b/flang/test/Semantics/omp-do04.f90 --- a/flang/test/Semantics/omp-do04.f90 +++ b/flang/test/Semantics/omp-do04.f90 @@ -1,20 +1,31 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.1 Loop Construct ! The loop iteration variable may not appear in a threadprivate directive. -program omp_do - integer i, j, k - !$omp do firstprivate(i) - !ERROR: !$OMP DO iteration variable i is not allowed in threadprivate +program omp_do + integer, save:: i, j, k,n + !$omp threadprivate(k,j,i) + !$omp do collapse(2) + !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE. do i = 1, 10 + !ERROR: Loop iteration variable j is not allowed in THREADPRIVATE. do j = 1, 10 print *, "Hello" end do end do !$omp end do - end program omp_do + +program omp_do1 + !$omp threadprivate(k,j,i) + !$omp do + !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE. + do i = 1, 10 + do j = 1, 10 + print *, "Hello" + end do + end do + !$omp end do +end program omp_do1 diff --git a/flang/test/Semantics/omp-do06.f90 b/flang/test/Semantics/omp-do06.f90 --- a/flang/test/Semantics/omp-do06.f90 +++ b/flang/test/Semantics/omp-do06.f90 @@ -1,6 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL:* - ! OpenMP Version 4.5 ! 2.7.1 Loop Construct ! The ordered clause must be present on the loop construct if any ordered @@ -11,11 +9,29 @@ !$omp do do i = 1, 10 - !ERROR: ‘ordered’ region inside a loop region without an ordered clause. + !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. !$omp ordered - call my_func() + call my_func() !$omp end ordered end do !$omp end do end program omp_do + +! A positive case +!DEF: /omp_do1 MainProgram +program omp_do1 + !DEF: /omp_do/i ObjectEntity INTEGER(4) + !DEF: /omp_do/j ObjectEntity INTEGER(4) + !DEF: /omp_do/k ObjectEntity INTEGER(4) + integer i, j, k + !$omp do ordered + !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !$omp ordered + !DEF: /my_func EXTERNAL (Subroutine) ProcEntity + call my_func + !$omp end ordered + end do + !$omp end do +end program omp_do1 diff --git a/flang/test/Semantics/omp-do08.f90 b/flang/test/Semantics/omp-do08.f90 --- a/flang/test/Semantics/omp-do08.f90 +++ b/flang/test/Semantics/omp-do08.f90 @@ -1,19 +1,75 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.1 Loop Construct -program omp_do +program omp integer i, j, k - !$omp do collapse(2) - do i = 1, 10 + + !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. + !$omp do collapse(3) + do i = 0, 10 + !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop + if (i .lt. 1) cycle + do j = 0, 10 + do k = 0, 10 + print *, i, j, k + end do + end do + end do + !$omp end do + + !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. + !$omp do collapse(3) + do i = 0, 10 + do j = 0, 10 + !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop + if (i .lt. 1) cycle + do k = 0, 10 + print *, i, j, k + end do + end do + end do + !$omp end do + + !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. + !$omp do collapse(2) + do i = 0, 10 !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop - if (i .lt. 5) cycle - do j = 1, 10 - print *, "Hello" + if (i .lt. 1) cycle + do j = 0, 10 + do k = 0, 10 + print *, i, j, k + end do end do end do !$omp end do -end program omp_do + + !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. + !$omp do collapse(2) + foo: do i = 0, 10 + !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop + if (i .lt. 1) cycle foo + do j = 0, 10 + do k = 0, 10 + print *, i, j, k + end do + end do + end do foo + !$omp end do + + + !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. + !$omp do collapse(3) + do 60 i=2,200,2 + do j=1,10 + !ERROR: CYCLE statement to non-innermost collapsed !$OMP DO loop + if(i==100) cycle + do k=1,10 + print *,i + end do + end do + 60 continue + !$omp end do + +end program omp diff --git a/flang/test/Semantics/omp-do09.f90 b/flang/test/Semantics/omp-do09.f90 --- a/flang/test/Semantics/omp-do09.f90 +++ b/flang/test/Semantics/omp-do09.f90 @@ -1,22 +1,26 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.1 Loop Construct ! The do-loop cannot be a DO WHILE or a DO loop without loop control. program omp_do - integer i, j, k - i = 0 + integer :: i = 0,k + !$omp do + !ERROR: The do loop cannot be a DO WHILE with do directive. + do while (i <= 10) + print *, "it",i + i = i+1 + end do + !$omp end do !$omp do - !ERROR: !$OMP DO cannot be a DO WHILE or DO without loop control - do while (i .lt. 10) - do j = 1, 10 - print *, "Hello" + !ERROR: The do loop cannot be a DO WHILE with do directive. + do while (i <= 10) + do while (j <= 10) + print *, "it",k + j = j+1 end do - i = i + 1 + i = i+1 end do !$omp end do - end program omp_do diff --git a/flang/test/Semantics/omp-do10.f90 b/flang/test/Semantics/omp-do10.f90 --- a/flang/test/Semantics/omp-do10.f90 +++ b/flang/test/Semantics/omp-do10.f90 @@ -1,20 +1,17 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.1 Loop Construct ! The do-loop iteration variable must be of type integer. program omp_do real i, j, k - !$omp do - !ERROR: The do-loop iteration variable must be of type integer. + !ERROR: The do-loop iteration variable must be of the type integer. do i = 1, 10 + !ERROR: The do-loop iteration variable must be of the type integer. do j = 1, 10 - print *, "Hello" + print *, "it", i, j end do end do !$omp end do - end program omp_do diff --git a/flang/test/Semantics/omp-do11.f90 b/flang/test/Semantics/omp-do11.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-do11.f90 @@ -0,0 +1,54 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop Constructs + +!DEF: /omp_do MainProgram +program omp_do + !DEF: /omp_do/i ObjectEntity INTEGER(4) + !DEF: /omp_do/j ObjectEntity INTEGER(4) + !DEF: /omp_do/k ObjectEntity INTEGER(4) + integer i, j, k + !$omp do + !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_do/j + do j=1,10 + !REF: /omp_do/Block1/i + !REF: /omp_do/j + print *, "it", i, j + end do + end do + !$omp end do +end program omp_do + +!DEF: /omp_do1 MainProgram +program omp_do1 + !DEF: /omp_do/i ObjectEntity INTEGER(4) + !DEF: /omp_do/j ObjectEntity INTEGER(4) + !DEF: /omp_do/k (OmpThreadprivate) ObjectEntity INTEGER(4) + integer i, j, k, n + !$omp threadprivate (k,n) + !$omp do + !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_do/j + do j=1,10 + print *, "Hello" + end do + end do + !$omp end do +end program omp_do1 + +!DEF: /omp_do3 MainProgram +program omp_do3 + !DEF: /omp_do/i ObjectEntity INTEGER(4) + !DEF: /omp_do/k ObjectEntity INTEGER(4) + integer :: i = 0, k + !$omp do + !DEF: /omp_do/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_do/Block1/i + print *, "it", i + end do + !$omp end do +end program omp_do3 diff --git a/flang/test/Semantics/omp-do12.f90 b/flang/test/Semantics/omp-do12.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-do12.f90 @@ -0,0 +1,96 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop constructs. + +!DEF: /omp_cycle MainProgram +program omp_cycle + !$omp do collapse(1) + !DEF: /omp_cycle/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=0,10 + !REF: /omp_cycle/Block1/i + if (i<1) cycle + !DEF: /omp_cycle/j (Implicit) ObjectEntity INTEGER(4) + do j=0,10 + !DEF: /omp_cycle/k (Implicit) ObjectEntity INTEGER(4) + do k=0,10 + !REF: /omp_cycle/Block1/i + !REF: /omp_cycle/j + !REF: /omp_cycle/k + print *, i, j, k + end do + end do + end do + !$omp end do + + !$omp do collapse(1) + !DEF: /omp_cycle/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=0,10 + !REF: /omp_cycle/j + do j=0,10 + !REF: /omp_cycle/Block2/i + if (i<1) cycle + !REF: /omp_cycle/k + do k=0,10 + !REF: /omp_cycle/Block2/i + !REF: /omp_cycle/j + !REF: /omp_cycle/k + print *, i, j, k + end do + end do + end do + !$omp end do + + !$omp do collapse(3) + !DEF: /omp_cycle/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=0,10 + !DEF: /omp_cycle/Block3/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do j=0,10 + !DEF: /omp_cycle/Block3/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do k=0,10 + !REF: /omp_cycle/Block3/i + if (i<1) cycle + !REF: /omp_cycle/Block3/i + !REF: /omp_cycle/Block3/j + !REF: /omp_cycle/Block3/k + print *, i, j, k + end do + end do + end do + !$omp end do + + !$omp do collapse(3) + !DEF: /omp_cycle/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + foo: do i=0,10 + !DEF: /omp_cycle/Block3/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do j=0,10 + !DEF: /omp_cycle/Block3/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do k=0,10 + !REF: /omp_cycle/Block3/i + if (i<1) cycle foo + !REF: /omp_cycle/Block3/i + !REF: /omp_cycle/Block3/j + !REF: /omp_cycle/Block3/k + print *, i, j, k + end do + end do + end do foo + !$omp end do + + !$omp do collapse(3) + !DEF: /omp_cycle/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do 100 i=0,10 + !DEF: /omp_cycle/Block3/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do j=0,10 + !DEF: /omp_cycle/Block3/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do k=0,10 + !REF: /omp_cycle/Block3/i + if (i<1) cycle + !REF: /omp_cycle/Block3/i + !REF: /omp_cycle/Block3/j + !REF: /omp_cycle/Block3/k + print *, i, j, k + end do + end do + 100 continue + !$omp end do +end program omp_cycle