Skip to content

Commit b0f31df

Browse files
PeixinQiaojeanPerier
authored andcommitted
[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 <[email protected]> Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D108512
1 parent f4a6615 commit b0f31df

File tree

6 files changed

+192
-4
lines changed

6 files changed

+192
-4
lines changed

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,25 @@ void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
771771
dirContext_.pop_back();
772772
}
773773

774+
void OmpStructureChecker::ChecksOnOrderedAsBlock() {
775+
if (FindClause(llvm::omp::Clause::OMPC_depend)) {
776+
context_.Say(GetContext().clauseSource,
777+
"DEPEND(*) clauses are not allowed when ORDERED construct is a block"
778+
" construct with an ORDERED region"_err_en_US);
779+
}
780+
}
781+
782+
void OmpStructureChecker::Leave(const parser::OmpBeginBlockDirective &) {
783+
switch (GetContext().directive) {
784+
case llvm::omp::Directive::OMPD_ordered:
785+
// [5.1] 2.19.9 Ordered Construct Restriction
786+
ChecksOnOrderedAsBlock();
787+
break;
788+
default:
789+
break;
790+
}
791+
}
792+
774793
void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
775794
const auto &beginSectionsDir{
776795
std::get<parser::OmpBeginSectionsDirective>(x.t)};
@@ -911,6 +930,48 @@ void OmpStructureChecker::CheckBarrierNesting(
911930
}
912931
}
913932

933+
void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
934+
if (FindClause(llvm::omp::Clause::OMPC_threads) ||
935+
FindClause(llvm::omp::Clause::OMPC_simd)) {
936+
context_.Say(GetContext().clauseSource,
937+
"THREADS, SIMD clauses are not allowed when ORDERED construct is a "
938+
"standalone construct with no ORDERED region"_err_en_US);
939+
}
940+
941+
bool isSinkPresent{false};
942+
int dependSourceCount{0};
943+
auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_depend);
944+
for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
945+
const auto &dependClause{
946+
std::get<parser::OmpClause::Depend>(itr->second->u)};
947+
if (std::get_if<parser::OmpDependClause::Source>(&dependClause.v.u)) {
948+
dependSourceCount++;
949+
if (isSinkPresent) {
950+
context_.Say(itr->second->source,
951+
"DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present "
952+
"on ORDERED directive"_err_en_US);
953+
}
954+
if (dependSourceCount > 1) {
955+
context_.Say(itr->second->source,
956+
"At most one DEPEND(SOURCE) clause can appear on the ORDERED "
957+
"directive"_err_en_US);
958+
}
959+
} else if (std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)) {
960+
isSinkPresent = true;
961+
if (dependSourceCount > 0) {
962+
context_.Say(itr->second->source,
963+
"DEPEND(SINK: vec) is not allowed when DEPEND(SOURCE) is present "
964+
"on ORDERED directive"_err_en_US);
965+
}
966+
} else {
967+
context_.Say(itr->second->source,
968+
"Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED "
969+
"construct is a standalone construct with no ORDERED "
970+
"region"_err_en_US);
971+
}
972+
}
973+
}
974+
914975
void OmpStructureChecker::Enter(
915976
const parser::OpenMPSimpleStandaloneConstruct &x) {
916977
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
@@ -920,6 +981,14 @@ void OmpStructureChecker::Enter(
920981

921982
void OmpStructureChecker::Leave(
922983
const parser::OpenMPSimpleStandaloneConstruct &) {
984+
switch (GetContext().directive) {
985+
case llvm::omp::Directive::OMPD_ordered:
986+
// [5.1] 2.19.9 Ordered Construct Restriction
987+
ChecksOnOrderedAsStandalone();
988+
break;
989+
default:
990+
break;
991+
}
923992
dirContext_.pop_back();
924993
}
925994

flang/lib/Semantics/check-omp-structure.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ class OmpStructureChecker
135135

136136
void Enter(const parser::OpenMPBlockConstruct &);
137137
void Leave(const parser::OpenMPBlockConstruct &);
138+
void Leave(const parser::OmpBeginBlockDirective &);
138139
void Enter(const parser::OmpEndBlockDirective &);
139140
void Leave(const parser::OmpEndBlockDirective &);
140141

@@ -238,7 +239,9 @@ class OmpStructureChecker
238239
const parser::DefinedOperator::IntrinsicOperator &);
239240
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
240241
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
242+
void ChecksOnOrderedAsBlock();
241243
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
244+
void ChecksOnOrderedAsStandalone();
242245
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
243246
void CheckIntentInPointerAndDefinable(
244247
const parser::OmpObjectList &, const llvm::omp::Clause);

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
298298
GetContext().withinConstruct = true;
299299
}
300300

301+
bool Pre(const parser::OpenMPSimpleStandaloneConstruct &);
302+
void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); }
303+
301304
bool Pre(const parser::OpenMPLoopConstruct &);
302305
void Post(const parser::OpenMPLoopConstruct &) { PopContext(); }
303306
void Post(const parser::OmpBeginLoopDirective &) {
@@ -414,6 +417,18 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
414417
return false;
415418
}
416419

420+
bool Pre(const parser::OmpDependClause &x) {
421+
if (const auto *dependSink{
422+
std::get_if<parser::OmpDependClause::Sink>(&x.u)}) {
423+
const auto &dependSinkVec{dependSink->v};
424+
for (const auto &dependSinkElement : dependSinkVec) {
425+
const auto &name{std::get<parser::Name>(dependSinkElement.t)};
426+
ResolveName(&name);
427+
}
428+
}
429+
return false;
430+
}
431+
417432
void Post(const parser::Name &);
418433

419434
// Keep track of labels in the statements that causes jumps to target labels
@@ -1132,6 +1147,27 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
11321147
PopContext();
11331148
}
11341149

1150+
bool OmpAttributeVisitor::Pre(
1151+
const parser::OpenMPSimpleStandaloneConstruct &x) {
1152+
const auto &standaloneDir{
1153+
std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
1154+
switch (standaloneDir.v) {
1155+
case llvm::omp::Directive::OMPD_barrier:
1156+
case llvm::omp::Directive::OMPD_ordered:
1157+
case llvm::omp::Directive::OMPD_target_enter_data:
1158+
case llvm::omp::Directive::OMPD_target_exit_data:
1159+
case llvm::omp::Directive::OMPD_target_update:
1160+
case llvm::omp::Directive::OMPD_taskwait:
1161+
case llvm::omp::Directive::OMPD_taskyield:
1162+
PushContext(standaloneDir.source, standaloneDir.v);
1163+
break;
1164+
default:
1165+
break;
1166+
}
1167+
ClearDataSharingAttributeObjects();
1168+
return true;
1169+
}
1170+
11351171
bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
11361172
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
11371173
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};

flang/test/Semantics/omp-clause-validity01.f90

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,6 @@
480480
! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
481481
! !$omp target update from(arrayA) to(arrayB)
482482
! !$omp target exit data map(from:arrayA) map(delete:arrayB)
483-
!$omp ordered depend(source)
484-
! !$omp ordered depend(sink:i-1)
485483
!$omp flush (c)
486484
!$omp flush acq_rel
487485
!$omp flush release
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
! RUN: %python %S/test_errors.py %s %flang -fopenmp
2+
! OpenMP Version 5.1
3+
! Check OpenMP construct validity for the following directives:
4+
! 2.19.9 Ordered Construct
5+
6+
program main
7+
integer :: i, N = 10
8+
real :: a, arrayA(10), arrayB(10), arrayC(10)
9+
real, external :: foo, bar, baz
10+
11+
!$omp do ordered
12+
do i = 1, N
13+
!ERROR: At most one THREADS clause can appear on the ORDERED directive
14+
!$omp ordered threads threads
15+
arrayA(i) = i
16+
!$omp end ordered
17+
end do
18+
!$omp end do
19+
20+
!$omp simd
21+
do i = 1, N
22+
!ERROR: At most one SIMD clause can appear on the ORDERED directive
23+
!$omp ordered simd simd
24+
arrayA(i) = i
25+
!$omp end ordered
26+
end do
27+
!$omp end simd
28+
29+
!$omp do simd ordered
30+
do i = 1, N
31+
!ERROR: At most one SIMD clause can appear on the ORDERED directive
32+
!$omp ordered simd simd
33+
arrayA(i) = i
34+
!$omp end ordered
35+
end do
36+
!$omp end do simd
37+
38+
!$omp do ordered(1)
39+
do i = 2, N
40+
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
41+
!ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
42+
!$omp ordered depend(source) depend(inout: arrayA) depend(source)
43+
arrayA(i) = foo(i)
44+
!ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
45+
!ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
46+
!ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
47+
!$omp ordered depend(sink: i - 1) depend(source) depend(source)
48+
arrayB(i) = bar(arrayA(i), arrayB(i-1))
49+
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
50+
!ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
51+
!$omp ordered depend(out: arrayC) depend(in: arrayB)
52+
arrayC(i) = baz(arrayB(i-1))
53+
end do
54+
!$omp end do
55+
56+
!$omp do ordered(1)
57+
do i = 2, N
58+
!ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
59+
!$omp ordered depend(source)
60+
arrayA(i) = foo(i)
61+
!$omp end ordered
62+
!ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
63+
!$omp ordered depend(sink: i - 1)
64+
arrayB(i) = bar(arrayA(i), arrayB(i-1))
65+
!$omp end ordered
66+
end do
67+
!$omp end do
68+
69+
contains
70+
subroutine work1()
71+
!ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
72+
!$omp ordered simd
73+
end subroutine work1
74+
75+
subroutine work2()
76+
!ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
77+
!$omp ordered threads
78+
end subroutine work2
79+
80+
end program main

llvm/include/llvm/Frontend/OpenMP/OMP.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,12 @@ def OMP_Flush : Directive<"flush"> {
483483
}
484484
def OMP_Ordered : Directive<"ordered"> {
485485
let allowedClauses = [
486-
VersionedClause<OMPC_Threads>,
487-
VersionedClause<OMPC_Simd>,
488486
VersionedClause<OMPC_Depend>
489487
];
488+
let allowedOnceClauses = [
489+
VersionedClause<OMPC_Threads>,
490+
VersionedClause<OMPC_Simd>
491+
];
490492
}
491493
def OMP_Atomic : Directive<"atomic"> {
492494
let allowedClauses = [

0 commit comments

Comments
 (0)