[flang][OpenMP] Add semantic checks of nesting of region about ordered construct

This patch supports the following checks for ORDERED construct:

```
[5.1] 2.19.9 ORDERED Construct
The worksharing-loop or worksharing-loop SIMD region to which an ordered
region corresponding to an ordered construct without a depend clause
binds must have an ordered clause without the parameter specified on the
corresponding worksharing-loop or worksharing-loop SIMD directive.
The worksharing-loop region to which an ordered region that corresponds
to an ordered construct with any depend clauses binds must have an
ordered clause with the parameter specified on the corresponding
worksharing-loop directive.
An ordered construct with the depend clause specified must be closely
nested inside a worksharing-loop (or parallel worksharing-loop)
construct.
An ordered region that corresponds to an ordered construct with the simd
clause specified must be closely nested inside a simd or
worksharing-loop SIMD region.
```

Reviewed By: kiranchandramohan, shraiysh, NimishMishra

Differential Revision: https://reviews.llvm.org/D113399
This commit is contained in:
PeixinQiao 2022-04-13 22:27:58 +08:00
parent f71f105901
commit 154135c11c
9 changed files with 389 additions and 32 deletions

View File

@ -250,9 +250,12 @@ protected:
}
// Check if the given clause is present in the current context
const PC *FindClause(C type) {
auto it{GetContext().clauseInfo.find(type)};
if (it != GetContext().clauseInfo.end()) {
const PC *FindClause(C type) { return FindClause(GetContext(), type); }
// Check if the given clause is present in the given context
const PC *FindClause(DirectiveContext &context, C type) {
auto it{context.clauseInfo.find(type)};
if (it != context.clauseInfo.end()) {
return it->second;
}
return nullptr;

View File

@ -673,7 +673,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
}
if (CurrentDirectiveIsNested()) {
CheckIfDoOrderedClause(beginDir);
if (llvm::omp::teamSet.test(GetContextParent().directive)) {
HasInvalidTeamsNesting(beginDir.v, beginDir.source);
}
@ -740,27 +739,6 @@ void OmpStructureChecker::CheckMasterNesting(
}
}
void OmpStructureChecker::CheckIfDoOrderedClause(
const parser::OmpBlockDirective &blkDirective) {
if (blkDirective.v == llvm::omp::OMPD_ordered) {
// Loops
if (llvm::omp::doSet.test(GetContextParent().directive) &&
!FindClauseParent(llvm::omp::Clause::OMPC_ordered)) {
context_.Say(blkDirective.source,
"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);
}
// Other disallowed nestings, these directives do not support
// ordered clause in them, so no need to check
else if (IsCloselyNestedRegion(llvm::omp::nestedOrderedErrSet)) {
context_.Say(blkDirective.source,
"`ORDERED` region may not be closely nested inside of "
"`CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US);
}
}
}
void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
if (GetDirectiveNest(TargetBlockOnlyTeams)) {
ExitDirectiveNest(TargetBlockOnlyTeams);
@ -776,6 +754,68 @@ void OmpStructureChecker::ChecksOnOrderedAsBlock() {
context_.Say(GetContext().clauseSource,
"DEPEND(*) clauses are not allowed when ORDERED construct is a block"
" construct with an ORDERED region"_err_en_US);
return;
}
OmpDirectiveSet notAllowedParallelSet{llvm::omp::Directive::OMPD_parallel,
llvm::omp::Directive::OMPD_target_parallel,
llvm::omp::Directive::OMPD_parallel_sections,
llvm::omp::Directive::OMPD_parallel_workshare};
bool isNestedInDo{false};
bool isNestedInDoSIMD{false};
bool isNestedInSIMD{false};
bool noOrderedClause{false};
bool isOrderedClauseWithPara{false};
bool isCloselyNestedRegion{true};
if (CurrentDirectiveIsNested()) {
for (int i = (int)dirContext_.size() - 2; i >= 0; i--) {
if (llvm::omp::nestedOrderedErrSet.test(dirContext_[i].directive)) {
context_.Say(GetContext().directiveSource,
"`ORDERED` region may not be closely nested inside of `CRITICAL`, "
"`ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US);
break;
} else if (llvm::omp::doSet.test(dirContext_[i].directive)) {
isNestedInDo = true;
isNestedInDoSIMD = llvm::omp::doSimdSet.test(dirContext_[i].directive);
if (const auto *clause{
FindClause(dirContext_[i], llvm::omp::Clause::OMPC_ordered)}) {
const auto &orderedClause{
std::get<parser::OmpClause::Ordered>(clause->u)};
const auto orderedValue{GetIntValue(orderedClause.v)};
isOrderedClauseWithPara = orderedValue > 0;
} else {
noOrderedClause = true;
}
break;
} else if (llvm::omp::simdSet.test(dirContext_[i].directive)) {
isNestedInSIMD = true;
break;
} else if (notAllowedParallelSet.test(dirContext_[i].directive)) {
isCloselyNestedRegion = false;
break;
}
}
}
if (!isCloselyNestedRegion) {
context_.Say(GetContext().directiveSource,
"An ORDERED directive without the DEPEND clause must be closely nested "
"in a SIMD, worksharing-loop, or worksharing-loop SIMD "
"region"_err_en_US);
} else {
if (CurrentDirectiveIsNested() &&
FindClause(llvm::omp::Clause::OMPC_simd) &&
(!isNestedInDoSIMD && !isNestedInSIMD)) {
context_.Say(GetContext().directiveSource,
"An ORDERED directive with SIMD clause must be closely nested in a "
"SIMD or worksharing-loop SIMD region"_err_en_US);
}
if (isNestedInDo && (noOrderedClause || isOrderedClauseWithPara)) {
context_.Say(GetContext().directiveSource,
"An ORDERED directive without the DEPEND clause must be closely "
"nested in a worksharing-loop (or worksharing-loop SIMD) region with "
"ORDERED clause without the parameter"_err_en_US);
}
}
}
@ -1063,6 +1103,50 @@ void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
"region"_err_en_US);
}
}
OmpDirectiveSet allowedDoSet{llvm::omp::Directive::OMPD_do,
llvm::omp::Directive::OMPD_parallel_do,
llvm::omp::Directive::OMPD_target_parallel_do};
bool isNestedInDoOrderedWithPara{false};
if (CurrentDirectiveIsNested() &&
allowedDoSet.test(GetContextParent().directive)) {
if (const auto *clause{
FindClause(GetContextParent(), llvm::omp::Clause::OMPC_ordered)}) {
const auto &orderedClause{
std::get<parser::OmpClause::Ordered>(clause->u)};
const auto orderedValue{GetIntValue(orderedClause.v)};
if (orderedValue > 0) {
isNestedInDoOrderedWithPara = true;
CheckOrderedDependClause(orderedValue);
}
}
}
if (FindClause(llvm::omp::Clause::OMPC_depend) &&
!isNestedInDoOrderedWithPara) {
context_.Say(GetContext().clauseSource,
"An ORDERED construct with the DEPEND clause must be closely nested "
"in a worksharing-loop (or parallel worksharing-loop) construct with "
"ORDERED clause with a parameter"_err_en_US);
}
}
void OmpStructureChecker::CheckOrderedDependClause(
std::optional<std::int64_t> orderedValue) {
auto clauseAll{FindClauses(llvm::omp::Clause::OMPC_depend)};
for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
const auto &dependClause{
std::get<parser::OmpClause::Depend>(itr->second->u)};
if (const auto *sinkVectors{
std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)}) {
std::int64_t numVar = sinkVectors->v.size();
if (orderedValue != numVar) {
context_.Say(itr->second->source,
"The number of variables in DEPEND(SINK: vec) clause does not "
"match the parameter specified in ORDERED clause"_err_en_US);
}
}
}
}
void OmpStructureChecker::Enter(

View File

@ -241,7 +241,6 @@ private:
void CheckCancellationNest(
const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
bool CheckReductionOperators(const parser::OmpClause::Reduction &);
bool CheckIntrinsicOperator(
const parser::DefinedOperator::IntrinsicOperator &);
@ -250,6 +249,7 @@ private:
void ChecksOnOrderedAsBlock();
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
void ChecksOnOrderedAsStandalone();
void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
void CheckIntentInPointerAndDefinable(
const parser::OmpObjectList &, const llvm::omp::Clause);

View File

@ -30,7 +30,7 @@ program omp_doordered
end do
end do
!$omp do ordered(1)
!$omp do ordered
!DEF: /omp_doordered/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,10
!$omp ordered
@ -53,7 +53,7 @@ program omp_doordered
!$omp end do
!$omp parallel num_threads(4)
!$omp do ordered(1) collapse(1)
!$omp do ordered collapse(1)
!DEF: /omp_doordered/Block5/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,10
!$omp ordered

View File

@ -27,6 +27,7 @@ program omp_doOrdered
!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 ordered(2)
do i = 1,10
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
do j = 1, 10
print *, "hello"
@ -48,6 +49,7 @@ program omp_doOrdered
!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 ordered(2) collapse(1)
do i = 1,10
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
do j = 1, 10
print *, "hello"

View File

@ -9,7 +9,7 @@ program omp_do
!$omp do
do i = 1, 10
!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.
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
call my_func()
!$omp end ordered
@ -21,7 +21,7 @@ program omp_do
!$omp parallel do
do j = 1, 10
print *,i
!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.
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
print *,i
!$omp end ordered

View File

@ -26,7 +26,7 @@ SUBROUTINE ORDERED_BAD(N)
DO I = 1,N
IF (I <= 10) THEN
!ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` 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.
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$OMP ORDERED
CALL WORK(I)
!$OMP END ORDERED
@ -37,7 +37,7 @@ SUBROUTINE ORDERED_BAD(N)
!$OMP PARALLEL DO
DO I = 1,N
IF (I <= 10) THEN
!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.
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$OMP ORDERED
CALL WORK(I)
!$OMP END ORDERED

View File

@ -0,0 +1,146 @@
! RUN: %python %S/test_errors.py %s %flang -fopenmp
! OpenMP Version 5.1
! Check OpenMP construct validity for the following directives:
! 2.19.9 Ordered Construct
subroutine sub1()
integer :: i, j, N = 10
real :: arrayA(10), arrayB(10)
real, external :: foo, bar
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
!$omp ordered threads
arrayA(i) = foo(i)
!$omp end ordered
!$omp ordered simd
arrayA(i) = foo(i)
!$omp end ordered
!$omp sections
do i = 1, N
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end sections
!$omp do ordered
do i = 1, N
arrayB(i) = bar(i)
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end do
!$omp sections
do i = 1, N
!ERROR: An ORDERED directive with SIMD clause must be closely nested in a SIMD or worksharing-loop SIMD region
!$omp ordered simd
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end sections
!$omp do ordered
do i = 1, N
!$omp parallel
do j = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a SIMD, worksharing-loop, or worksharing-loop SIMD region
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end parallel
end do
!$omp end do
!$omp do ordered
do i = 1, N
!$omp target parallel
do j = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a SIMD, worksharing-loop, or worksharing-loop SIMD region
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end target parallel
end do
!$omp end do
!$omp do
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end do
!$omp do
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered threads
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end do
!$omp do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end do
!$omp do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered threads
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end do
!$omp parallel do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end parallel do
!$omp parallel do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered threads
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end parallel do
!$omp target parallel do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end target parallel do
!$omp target parallel do ordered(1)
do i = 1, N
!ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
!$omp ordered threads
arrayA(i) = foo(i)
!$omp end ordered
end do
!$omp end target parallel do
end

View File

@ -0,0 +1,122 @@
! RUN: %python %S/test_errors.py %s %flang -fopenmp
! OpenMP Version 5.1
! Check OpenMP construct validity for the following directives:
! 2.19.9 Ordered Construct
subroutine sub1()
integer :: i, j, N = 10
real :: arrayA(10), arrayB(10)
real, external :: foo, bar
!$omp do ordered(1)
do i = 1, N
!$omp ordered depend(source)
arrayA(i) = foo(i)
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end do
!$omp do ordered(1)
do i = 1, N
!$omp target
do j = 1, N
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
arrayA(i) = foo(i)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end target
end do
!$omp end do
!$omp target
!$omp parallel do ordered(1)
do i = 1, N
!$omp ordered depend(source)
arrayA(i) = foo(i)
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end parallel do
!$omp end target
!$omp target parallel do ordered(1)
do i = 1, N
!$omp ordered depend(source)
arrayA(i) = foo(i)
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end target parallel do
!$omp target teams distribute parallel do ordered(1)
do i = 1, N
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
arrayA(i) = foo(i)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end target teams distribute parallel do
!$omp do ordered
do i = 1, N
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
arrayA(i) = foo(i)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end do
!$omp parallel do ordered
do i = 1, N
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
arrayA(i) = foo(i)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end parallel do
!$omp target parallel do ordered
do i = 1, N
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
arrayA(i) = foo(i)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
arrayB(i) = bar(i - 1)
end do
!$omp end target parallel do
!$omp do ordered(1)
do i = 1, N
!ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause
!$omp ordered depend(sink: i - 1) depend(sink: i - 1, j)
arrayB(i) = bar(i - 1, j)
end do
!$omp end do
!$omp do ordered(2)
do i = 1, N
do j = 1, N
!ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause
!$omp ordered depend(sink: i - 1) depend(sink: i - 1, j)
arrayB(i) = foo(i - 1) + bar(i - 1, j)
end do
end do
!$omp end do
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(source)
!ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter
!$omp ordered depend(sink: i - 1)
end