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 @@ -169,6 +169,7 @@ void Enter(const parser::OmpProcBindClause &); void Enter(const parser::OmpReductionClause &); void Enter(const parser::OmpScheduleClause &); + void Enter(const parser::OpenMPThreadprivate &); private: bool HasInvalidWorksharingNesting( @@ -187,6 +188,18 @@ const common::Indirection &, const parser::Name &); void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList); + + bool doWhileFlag{false}; + Symbol *loopIv{nullptr}; + std::list threadPrivateSymbols; + + void CheckIvForThreadPrivate(const parser::OpenMPLoopConstruct &x); + void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); + void CheckDoWhile(const parser::OpenMPLoopConstruct &x); + void SetLoopIv(Symbol *symbol) { loopIv = symbol; } + const parser::Name GetLoopIndex(const parser::DoConstruct *x); + void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + std::int64_t GetCollapseLevel(const parser::OpenMPLoopConstruct &x); }; } // 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,146 @@ llvm::omp::Directive::OMPD_master}); PushContextAndClauseSets(beginDir.source, llvm::omp::Directive::OMPD_do); } + CheckDoWhile(x); + CheckLoopItrVariableIsInt(x); + CheckIvForThreadPrivate(x); + CheckCycleConstraints(x); +} + +void OmpStructureChecker::CheckDoWhile(const parser::OpenMPLoopConstruct &x) { + const auto &beginLoopDir{std::get(x.t)}; + const auto &beginDir{std::get(beginLoopDir.t)}; + doWhileFlag = false; + if (beginDir.v == llvm::omp::Directive::OMPD_do) { + if (const auto &doConstruct{ + std::get>(x.t)}) { + if (doConstruct.value().IsDoWhile()) { + doWhileFlag = true; + 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 (!doWhileFlag) { + if (const auto &loopConstruct{ + std::get>(x.t)}) { + for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) { + // go through all the nested do-loops and to get index variables + const parser::Name &itrVal{GetLoopIndex(loop)}; + if (itrVal.symbol) { + auto type{itrVal.symbol->GetType()}; + if (auto *tySpec{type->AsIntrinsic()}) { + if (tySpec->category() != Fortran::common::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 (!doWhileFlag && loopIv) { + if (const auto &loopConstruct{ + std::get>(x.t)}) { + + if (!threadPrivateSymbols.empty()) { + for (const parser::DoConstruct *loop{&*loopConstruct}; loop && collapseLevel; --collapseLevel) { + // go through all the nested do-loops and to get index variables + const parser::Name &itrVal{GetLoopIndex(loop)}; + + for (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::Leave(const parser::OpenMPLoopConstruct &) { @@ -169,7 +309,37 @@ 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)}) { + SetLoopIv(name->symbol); + 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); @@ -324,6 +494,7 @@ if (llvm::omp::simdSet.test(GetContext().directive)) { if (auto *clause{FindClause(llvm::omp::Clause::OMPC_simdlen)}) { if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_safelen)}) { + const auto &simdlenClause{ std::get(clause->u)}; const auto &safelenClause{ 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 @@ -371,6 +371,7 @@ const parser::Name &, const Symbol &, Symbol::Flag); void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause); + bool doWhileFlag{false}; }; template @@ -786,7 +787,18 @@ } ClearDataSharingAttributeObjects(); SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList)); - PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x); + + if (beginDir.v == llvm::omp::Directive::OMPD_do) { + if (const auto &doConstruct{ + std::get>(x.t)}) { + if (doConstruct.value().IsDoWhile()) { + doWhileFlag = true; + } + } + } + if (!doWhileFlag) { + PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x); + } return true; } @@ -817,7 +829,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 && !doWhileFlag) { if (const auto &iv{GetLoopIndex(x)}; iv.symbol) { if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) { ResolveSeqLoopIndexInParallelOrTaskConstruct(iv); diff --git a/flang/test/Semantics/omp-doloop-positivecases.f90 b/flang/test/Semantics/omp-doloop-positivecases.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop-positivecases.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-doloop01.f90 b/flang/test/Semantics/omp-doloop01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop01.f90 @@ -0,0 +1,17 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop constructs. + +program omp_do + real i, j, k + !$omp do + !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 *, "it", i, j + end do + end do + !$omp end do +end program omp_do + diff --git a/flang/test/Semantics/omp-doloop02.f90 b/flang/test/Semantics/omp-doloop02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop02.f90 @@ -0,0 +1,29 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop Constructs + +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-doloop03.f90 b/flang/test/Semantics/omp-doloop03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop03.f90 @@ -0,0 +1,26 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop constructs. + +program omp_do + 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: 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 + end do + !$omp end do +end program omp_do + diff --git a/flang/test/Semantics/omp-doloop04-pc.f90 b/flang/test/Semantics/omp-doloop04-pc.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop04-pc.f90 @@ -0,0 +1,60 @@ +!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 +end program omp_cycle diff --git a/flang/test/Semantics/omp-doloop04.f90 b/flang/test/Semantics/omp-doloop04.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-doloop04.f90 @@ -0,0 +1,48 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.7.1 Do Loop constructs. + +program omp + integer i, j, k + + !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. 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