mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-14 14:56:47 +00:00
[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();
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto &beginSectionsDir{
|
||||
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(
|
||||
const parser::OpenMPSimpleStandaloneConstruct &x) {
|
||||
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
|
||||
@ -920,6 +981,14 @@ void OmpStructureChecker::Enter(
|
||||
|
||||
void OmpStructureChecker::Leave(
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,7 @@ public:
|
||||
|
||||
void Enter(const parser::OpenMPBlockConstruct &);
|
||||
void Leave(const parser::OpenMPBlockConstruct &);
|
||||
void Leave(const parser::OmpBeginBlockDirective &);
|
||||
void Enter(const parser::OmpEndBlockDirective &);
|
||||
void Leave(const parser::OmpEndBlockDirective &);
|
||||
|
||||
@ -238,7 +239,9 @@ private:
|
||||
const parser::DefinedOperator::IntrinsicOperator &);
|
||||
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
|
||||
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
|
||||
void ChecksOnOrderedAsBlock();
|
||||
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
|
||||
void ChecksOnOrderedAsStandalone();
|
||||
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
|
||||
void CheckIntentInPointerAndDefinable(
|
||||
const parser::OmpObjectList &, const llvm::omp::Clause);
|
||||
|
@ -298,6 +298,9 @@ public:
|
||||
GetContext().withinConstruct = true;
|
||||
}
|
||||
|
||||
bool Pre(const parser::OpenMPSimpleStandaloneConstruct &);
|
||||
void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); }
|
||||
|
||||
bool Pre(const parser::OpenMPLoopConstruct &);
|
||||
void Post(const parser::OpenMPLoopConstruct &) { PopContext(); }
|
||||
void Post(const parser::OmpBeginLoopDirective &) {
|
||||
@ -414,6 +417,18 @@ public:
|
||||
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 &);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.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 update from(arrayA) to(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 acq_rel
|
||||
!$omp flush release
|
||||
|
80
flang/test/Semantics/omp-ordered01.f90
Normal file
80
flang/test/Semantics/omp-ordered01.f90
Normal file
@ -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"> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Threads>,
|
||||
VersionedClause<OMPC_Simd>,
|
||||
VersionedClause<OMPC_Depend>
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Threads>,
|
||||
VersionedClause<OMPC_Simd>
|
||||
];
|
||||
}
|
||||
def OMP_Atomic : Directive<"atomic"> {
|
||||
let allowedClauses = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user