forked from OSchip/llvm-project
[flang][OpenMP] Add semantic checks for ordered construct
This patch implements the following semantic checks according to OpenMP Version 5.1 Ordered construct restriction: ``` At most one threads clause can appear on an ordered construct; At most one simd clause can appear on an ordered construct; At most one depend(source) clause can appear on an ordered construct; Either depend(sink:vec) clauses or depend(source) clauses may appear on an ordered construct, but not both. ``` This patch also implements the following semantic checks according to the syntax and descriptions in OpenMP Version 5.1 Ordered construct: ``` The dependence types of sink or source are only allowed on an ordered construct. The depend(*) clauses are not allowed when ordered construct is a block construct with an ordered region. The threads or simd clauses are not allowed when the ordered construct is a standalone construct with no ordered region. ``` Co-authored-by: Sameeran Joshi <sameeranjayant.joshi@amd.com> Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D108512
This commit is contained in:
parent
ff6b074674
commit
6fb01a9470
|
@ -771,6 +771,25 @@ void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
|
||||||
dirContext_.pop_back();
|
dirContext_.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OmpStructureChecker::ChecksOnOrderedAsBlock() {
|
||||||
|
if (FindClause(llvm::omp::Clause::OMPC_depend)) {
|
||||||
|
context_.Say(GetContext().clauseSource,
|
||||||
|
"DEPEND(*) clauses are not allowed when ORDERED construct is a block"
|
||||||
|
" construct with an ORDERED region"_err_en_US);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmpStructureChecker::Leave(const parser::OmpBeginBlockDirective &) {
|
||||||
|
switch (GetContext().directive) {
|
||||||
|
case llvm::omp::Directive::OMPD_ordered:
|
||||||
|
// [5.1] 2.19.9 Ordered Construct Restriction
|
||||||
|
ChecksOnOrderedAsBlock();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
|
void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
|
||||||
const auto &beginSectionsDir{
|
const auto &beginSectionsDir{
|
||||||
std::get<parser::OmpBeginSectionsDirective>(x.t)};
|
std::get<parser::OmpBeginSectionsDirective>(x.t)};
|
||||||
|
@ -911,6 +930,48 @@ void OmpStructureChecker::CheckBarrierNesting(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
|
||||||
|
if (FindClause(llvm::omp::Clause::OMPC_threads) ||
|
||||||
|
FindClause(llvm::omp::Clause::OMPC_simd)) {
|
||||||
|
context_.Say(GetContext().clauseSource,
|
||||||
|
"THREADS, SIMD clauses are not allowed when ORDERED construct is a "
|
||||||
|
"standalone construct with no ORDERED region"_err_en_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSinkPresent{false};
|
||||||
|
int dependSourceCount{0};
|
||||||
|
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 (std::get_if<parser::OmpDependClause::Source>(&dependClause.v.u)) {
|
||||||
|
dependSourceCount++;
|
||||||
|
if (isSinkPresent) {
|
||||||
|
context_.Say(itr->second->source,
|
||||||
|
"DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present "
|
||||||
|
"on ORDERED directive"_err_en_US);
|
||||||
|
}
|
||||||
|
if (dependSourceCount > 1) {
|
||||||
|
context_.Say(itr->second->source,
|
||||||
|
"At most one DEPEND(SOURCE) clause can appear on the ORDERED "
|
||||||
|
"directive"_err_en_US);
|
||||||
|
}
|
||||||
|
} else if (std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)) {
|
||||||
|
isSinkPresent = true;
|
||||||
|
if (dependSourceCount > 0) {
|
||||||
|
context_.Say(itr->second->source,
|
||||||
|
"DEPEND(SINK: vec) is not allowed when DEPEND(SOURCE) is present "
|
||||||
|
"on ORDERED directive"_err_en_US);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context_.Say(itr->second->source,
|
||||||
|
"Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED "
|
||||||
|
"construct is a standalone construct with no ORDERED "
|
||||||
|
"region"_err_en_US);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OmpStructureChecker::Enter(
|
void OmpStructureChecker::Enter(
|
||||||
const parser::OpenMPSimpleStandaloneConstruct &x) {
|
const parser::OpenMPSimpleStandaloneConstruct &x) {
|
||||||
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
|
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
|
||||||
|
@ -920,6 +981,14 @@ void OmpStructureChecker::Enter(
|
||||||
|
|
||||||
void OmpStructureChecker::Leave(
|
void OmpStructureChecker::Leave(
|
||||||
const parser::OpenMPSimpleStandaloneConstruct &) {
|
const parser::OpenMPSimpleStandaloneConstruct &) {
|
||||||
|
switch (GetContext().directive) {
|
||||||
|
case llvm::omp::Directive::OMPD_ordered:
|
||||||
|
// [5.1] 2.19.9 Ordered Construct Restriction
|
||||||
|
ChecksOnOrderedAsStandalone();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
dirContext_.pop_back();
|
dirContext_.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,7 @@ public:
|
||||||
|
|
||||||
void Enter(const parser::OpenMPBlockConstruct &);
|
void Enter(const parser::OpenMPBlockConstruct &);
|
||||||
void Leave(const parser::OpenMPBlockConstruct &);
|
void Leave(const parser::OpenMPBlockConstruct &);
|
||||||
|
void Leave(const parser::OmpBeginBlockDirective &);
|
||||||
void Enter(const parser::OmpEndBlockDirective &);
|
void Enter(const parser::OmpEndBlockDirective &);
|
||||||
void Leave(const parser::OmpEndBlockDirective &);
|
void Leave(const parser::OmpEndBlockDirective &);
|
||||||
|
|
||||||
|
@ -238,7 +239,9 @@ private:
|
||||||
const parser::DefinedOperator::IntrinsicOperator &);
|
const parser::DefinedOperator::IntrinsicOperator &);
|
||||||
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
|
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
|
||||||
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
|
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
|
||||||
|
void ChecksOnOrderedAsBlock();
|
||||||
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
|
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
|
||||||
|
void ChecksOnOrderedAsStandalone();
|
||||||
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
|
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
|
||||||
void CheckIntentInPointerAndDefinable(
|
void CheckIntentInPointerAndDefinable(
|
||||||
const parser::OmpObjectList &, const llvm::omp::Clause);
|
const parser::OmpObjectList &, const llvm::omp::Clause);
|
||||||
|
|
|
@ -298,6 +298,9 @@ public:
|
||||||
GetContext().withinConstruct = true;
|
GetContext().withinConstruct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Pre(const parser::OpenMPSimpleStandaloneConstruct &);
|
||||||
|
void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); }
|
||||||
|
|
||||||
bool Pre(const parser::OpenMPLoopConstruct &);
|
bool Pre(const parser::OpenMPLoopConstruct &);
|
||||||
void Post(const parser::OpenMPLoopConstruct &) { PopContext(); }
|
void Post(const parser::OpenMPLoopConstruct &) { PopContext(); }
|
||||||
void Post(const parser::OmpBeginLoopDirective &) {
|
void Post(const parser::OmpBeginLoopDirective &) {
|
||||||
|
@ -414,6 +417,18 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Pre(const parser::OmpDependClause &x) {
|
||||||
|
if (const auto *dependSink{
|
||||||
|
std::get_if<parser::OmpDependClause::Sink>(&x.u)}) {
|
||||||
|
const auto &dependSinkVec{dependSink->v};
|
||||||
|
for (const auto &dependSinkElement : dependSinkVec) {
|
||||||
|
const auto &name{std::get<parser::Name>(dependSinkElement.t)};
|
||||||
|
ResolveName(&name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Post(const parser::Name &);
|
void Post(const parser::Name &);
|
||||||
|
|
||||||
// Keep track of labels in the statements that causes jumps to target labels
|
// Keep track of labels in the statements that causes jumps to target labels
|
||||||
|
@ -1132,6 +1147,27 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
|
||||||
PopContext();
|
PopContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OmpAttributeVisitor::Pre(
|
||||||
|
const parser::OpenMPSimpleStandaloneConstruct &x) {
|
||||||
|
const auto &standaloneDir{
|
||||||
|
std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
|
||||||
|
switch (standaloneDir.v) {
|
||||||
|
case llvm::omp::Directive::OMPD_barrier:
|
||||||
|
case llvm::omp::Directive::OMPD_ordered:
|
||||||
|
case llvm::omp::Directive::OMPD_target_enter_data:
|
||||||
|
case llvm::omp::Directive::OMPD_target_exit_data:
|
||||||
|
case llvm::omp::Directive::OMPD_target_update:
|
||||||
|
case llvm::omp::Directive::OMPD_taskwait:
|
||||||
|
case llvm::omp::Directive::OMPD_taskyield:
|
||||||
|
PushContext(standaloneDir.source, standaloneDir.v);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ClearDataSharingAttributeObjects();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
|
bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
|
||||||
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
|
||||||
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
|
||||||
|
|
|
@ -480,8 +480,6 @@ use omp_lib
|
||||||
! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
|
! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
|
||||||
! !$omp target update from(arrayA) to(arrayB)
|
! !$omp target update from(arrayA) to(arrayB)
|
||||||
! !$omp target exit data map(from:arrayA) map(delete:arrayB)
|
! !$omp target exit data map(from:arrayA) map(delete:arrayB)
|
||||||
!$omp ordered depend(source)
|
|
||||||
! !$omp ordered depend(sink:i-1)
|
|
||||||
!$omp flush (c)
|
!$omp flush (c)
|
||||||
!$omp flush acq_rel
|
!$omp flush acq_rel
|
||||||
!$omp flush release
|
!$omp flush release
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
! 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
|
||||||
|
|
||||||
|
program main
|
||||||
|
integer :: i, N = 10
|
||||||
|
real :: a, arrayA(10), arrayB(10), arrayC(10)
|
||||||
|
real, external :: foo, bar, baz
|
||||||
|
|
||||||
|
!$omp do ordered
|
||||||
|
do i = 1, N
|
||||||
|
!ERROR: At most one THREADS clause can appear on the ORDERED directive
|
||||||
|
!$omp ordered threads threads
|
||||||
|
arrayA(i) = i
|
||||||
|
!$omp end ordered
|
||||||
|
end do
|
||||||
|
!$omp end do
|
||||||
|
|
||||||
|
!$omp simd
|
||||||
|
do i = 1, N
|
||||||
|
!ERROR: At most one SIMD clause can appear on the ORDERED directive
|
||||||
|
!$omp ordered simd simd
|
||||||
|
arrayA(i) = i
|
||||||
|
!$omp end ordered
|
||||||
|
end do
|
||||||
|
!$omp end simd
|
||||||
|
|
||||||
|
!$omp do simd ordered
|
||||||
|
do i = 1, N
|
||||||
|
!ERROR: At most one SIMD clause can appear on the ORDERED directive
|
||||||
|
!$omp ordered simd simd
|
||||||
|
arrayA(i) = i
|
||||||
|
!$omp end ordered
|
||||||
|
end do
|
||||||
|
!$omp end do simd
|
||||||
|
|
||||||
|
!$omp do ordered(1)
|
||||||
|
do i = 2, N
|
||||||
|
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
|
||||||
|
!ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
|
||||||
|
!$omp ordered depend(source) depend(inout: arrayA) depend(source)
|
||||||
|
arrayA(i) = foo(i)
|
||||||
|
!ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
|
||||||
|
!ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
|
||||||
|
!ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
|
||||||
|
!$omp ordered depend(sink: i - 1) depend(source) depend(source)
|
||||||
|
arrayB(i) = bar(arrayA(i), arrayB(i-1))
|
||||||
|
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
|
||||||
|
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
|
||||||
|
!$omp ordered depend(out: arrayC) depend(in: arrayB)
|
||||||
|
arrayC(i) = baz(arrayB(i-1))
|
||||||
|
end do
|
||||||
|
!$omp end do
|
||||||
|
|
||||||
|
!$omp do ordered(1)
|
||||||
|
do i = 2, N
|
||||||
|
!ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
|
||||||
|
!$omp ordered depend(source)
|
||||||
|
arrayA(i) = foo(i)
|
||||||
|
!$omp end ordered
|
||||||
|
!ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
|
||||||
|
!$omp ordered depend(sink: i - 1)
|
||||||
|
arrayB(i) = bar(arrayA(i), arrayB(i-1))
|
||||||
|
!$omp end ordered
|
||||||
|
end do
|
||||||
|
!$omp end do
|
||||||
|
|
||||||
|
contains
|
||||||
|
subroutine work1()
|
||||||
|
!ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
|
||||||
|
!$omp ordered simd
|
||||||
|
end subroutine work1
|
||||||
|
|
||||||
|
subroutine work2()
|
||||||
|
!ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
|
||||||
|
!$omp ordered threads
|
||||||
|
end subroutine work2
|
||||||
|
|
||||||
|
end program main
|
|
@ -491,10 +491,12 @@ def OMP_Flush : Directive<"flush"> {
|
||||||
}
|
}
|
||||||
def OMP_Ordered : Directive<"ordered"> {
|
def OMP_Ordered : Directive<"ordered"> {
|
||||||
let allowedClauses = [
|
let allowedClauses = [
|
||||||
VersionedClause<OMPC_Threads>,
|
|
||||||
VersionedClause<OMPC_Simd>,
|
|
||||||
VersionedClause<OMPC_Depend>
|
VersionedClause<OMPC_Depend>
|
||||||
];
|
];
|
||||||
|
let allowedOnceClauses = [
|
||||||
|
VersionedClause<OMPC_Threads>,
|
||||||
|
VersionedClause<OMPC_Simd>
|
||||||
|
];
|
||||||
}
|
}
|
||||||
def OMP_Atomic : Directive<"atomic"> {
|
def OMP_Atomic : Directive<"atomic"> {
|
||||||
let allowedClauses = [
|
let allowedClauses = [
|
||||||
|
|
Loading…
Reference in New Issue