Skip to content

Commit bdfe5d6

Browse files
authored
[flang][openacc] Apply mutually exclusive clauses restriction to routine (llvm#77802)
this patch enforce or fix the enforcement of two restrictions from section 2.15.1: > Only the gang, worker, vector, seq and bind clauses may follow a device_type clause. `seq` was not allowed after `device_type` with the current implementation. > Exactly one of the gang, worker, vector, or seq clauses must appear. This was not properly checked. This patch check correctly for mutually exclusion as described in section 2.4. Mutually exclusive clauses may appear on the same directive if they apply for different device_type.
1 parent d447304 commit bdfe5d6

File tree

3 files changed

+201
-14
lines changed

3 files changed

+201
-14
lines changed

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

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@ static constexpr inline AccClauseSet updateOnlyAllowedAfterDeviceTypeClauses{
6969

7070
static constexpr inline AccClauseSet routineOnlyAllowedAfterDeviceTypeClauses{
7171
llvm::acc::Clause::ACCC_bind, llvm::acc::Clause::ACCC_gang,
72-
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker};
72+
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_worker,
73+
llvm::acc::Clause::ACCC_seq};
74+
75+
static constexpr inline AccClauseSet routineMutuallyExclusiveClauses{
76+
llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_worker,
77+
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_seq};
7378

7479
bool AccStructureChecker::CheckAllowedModifier(llvm::acc::Clause clause) {
7580
if (GetContext().directive == llvm::acc::ACCD_enter_data ||
@@ -388,7 +393,6 @@ CHECK_SIMPLE_CLAUSE(NoCreate, ACCC_no_create)
388393
CHECK_SIMPLE_CLAUSE(Nohost, ACCC_nohost)
389394
CHECK_SIMPLE_CLAUSE(Private, ACCC_private)
390395
CHECK_SIMPLE_CLAUSE(Read, ACCC_read)
391-
CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq)
392396
CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device)
393397
CHECK_SIMPLE_CLAUSE(Wait, ACCC_wait)
394398
CHECK_SIMPLE_CLAUSE(Write, ACCC_write)
@@ -532,18 +536,40 @@ void AccStructureChecker::Enter(const parser::AccClause::DeviceType &d) {
532536
.str()),
533537
ContextDirectiveAsFortran());
534538
}
539+
ResetCrtGroup();
540+
}
541+
542+
void AccStructureChecker::Enter(const parser::AccClause::Seq &g) {
543+
llvm::acc::Clause crtClause = llvm::acc::Clause::ACCC_seq;
544+
if (GetContext().directive == llvm::acc::Directive::ACCD_routine) {
545+
CheckMutuallyExclusivePerGroup(crtClause,
546+
llvm::acc::Clause::ACCC_device_type, routineMutuallyExclusiveClauses);
547+
}
548+
CheckAllowed(crtClause);
535549
}
536550

537551
void AccStructureChecker::Enter(const parser::AccClause::Vector &g) {
538-
CheckAllowed(llvm::acc::Clause::ACCC_vector);
539-
CheckAllowedOncePerGroup(
540-
llvm::acc::Clause::ACCC_vector, llvm::acc::Clause::ACCC_device_type);
552+
llvm::acc::Clause crtClause = llvm::acc::Clause::ACCC_vector;
553+
if (GetContext().directive == llvm::acc::Directive::ACCD_routine) {
554+
CheckMutuallyExclusivePerGroup(crtClause,
555+
llvm::acc::Clause::ACCC_device_type, routineMutuallyExclusiveClauses);
556+
}
557+
CheckAllowed(crtClause);
558+
if (GetContext().directive != llvm::acc::Directive::ACCD_routine) {
559+
CheckAllowedOncePerGroup(crtClause, llvm::acc::Clause::ACCC_device_type);
560+
}
541561
}
542562

543563
void AccStructureChecker::Enter(const parser::AccClause::Worker &g) {
544-
CheckAllowed(llvm::acc::Clause::ACCC_worker);
545-
CheckAllowedOncePerGroup(
546-
llvm::acc::Clause::ACCC_worker, llvm::acc::Clause::ACCC_device_type);
564+
llvm::acc::Clause crtClause = llvm::acc::Clause::ACCC_worker;
565+
if (GetContext().directive == llvm::acc::Directive::ACCD_routine) {
566+
CheckMutuallyExclusivePerGroup(crtClause,
567+
llvm::acc::Clause::ACCC_device_type, routineMutuallyExclusiveClauses);
568+
}
569+
CheckAllowed(crtClause);
570+
if (GetContext().directive != llvm::acc::Directive::ACCD_routine) {
571+
CheckAllowedOncePerGroup(crtClause, llvm::acc::Clause::ACCC_device_type);
572+
}
547573
}
548574

549575
void AccStructureChecker::Enter(const parser::AccClause::Tile &g) {
@@ -553,24 +579,32 @@ void AccStructureChecker::Enter(const parser::AccClause::Tile &g) {
553579
}
554580

555581
void AccStructureChecker::Enter(const parser::AccClause::Gang &g) {
556-
CheckAllowed(llvm::acc::Clause::ACCC_gang);
557-
CheckAllowedOncePerGroup(
558-
llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_device_type);
582+
llvm::acc::Clause crtClause = llvm::acc::Clause::ACCC_gang;
583+
if (GetContext().directive == llvm::acc::Directive::ACCD_routine) {
584+
CheckMutuallyExclusivePerGroup(crtClause,
585+
llvm::acc::Clause::ACCC_device_type, routineMutuallyExclusiveClauses);
586+
}
587+
CheckAllowed(crtClause);
588+
if (GetContext().directive != llvm::acc::Directive::ACCD_routine) {
589+
CheckAllowedOncePerGroup(crtClause, llvm::acc::Clause::ACCC_device_type);
590+
}
559591

560592
if (g.v) {
561593
bool hasNum = false;
562594
bool hasDim = false;
563595
const Fortran::parser::AccGangArgList &x = *g.v;
564596
for (const Fortran::parser::AccGangArg &gangArg : x.v) {
565-
if (std::get_if<Fortran::parser::AccGangArg::Num>(&gangArg.u))
597+
if (std::get_if<Fortran::parser::AccGangArg::Num>(&gangArg.u)) {
566598
hasNum = true;
567-
else if (std::get_if<Fortran::parser::AccGangArg::Dim>(&gangArg.u))
599+
} else if (std::get_if<Fortran::parser::AccGangArg::Dim>(&gangArg.u)) {
568600
hasDim = true;
601+
}
569602
}
570603

571-
if (hasDim && hasNum)
604+
if (hasDim && hasNum) {
572605
context_.Say(GetContext().clauseSource,
573606
"The num argument is not allowed when dim is specified"_err_en_US);
607+
}
574608
}
575609
}
576610

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class DirectiveStructureChecker : public virtual BaseChecker {
197197
const PC *clause{nullptr};
198198
ClauseMapTy clauseInfo;
199199
std::list<C> actualClauses;
200+
std::list<C> crtGroup;
200201
Symbol *loopIV{nullptr};
201202
};
202203

@@ -261,6 +262,12 @@ class DirectiveStructureChecker : public virtual BaseChecker {
261262
GetContext().actualClauses.push_back(type);
262263
}
263264

265+
void AddClauseToCrtGroupInContext(C type) {
266+
GetContext().crtGroup.push_back(type);
267+
}
268+
269+
void ResetCrtGroup() { GetContext().crtGroup.clear(); }
270+
264271
// Check if the given clause is present in the current context
265272
const PC *FindClause(C type) { return FindClause(GetContext(), type); }
266273

@@ -353,6 +360,9 @@ class DirectiveStructureChecker : public virtual BaseChecker {
353360
// separator clause appears.
354361
void CheckAllowedOncePerGroup(C clause, C separator);
355362

363+
void CheckMutuallyExclusivePerGroup(
364+
C clause, C separator, common::EnumSet<C, ClauseEnumSize> set);
365+
356366
void CheckAtLeastOneClause();
357367

358368
void CheckNotAllowedIfClause(
@@ -526,6 +536,7 @@ void DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::CheckAllowed(
526536
}
527537
SetContextClauseInfo(clause);
528538
AddClauseToCrtContext(clause);
539+
AddClauseToCrtGroupInContext(clause);
529540
}
530541

531542
// Enforce restriction where clauses in the given set are not allowed if the
@@ -570,6 +581,37 @@ void DirectiveStructureChecker<D, C, PC,
570581
}
571582
}
572583

584+
template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
585+
void DirectiveStructureChecker<D, C, PC,
586+
ClauseEnumSize>::CheckMutuallyExclusivePerGroup(C clause, C separator,
587+
common::EnumSet<C, ClauseEnumSize> set) {
588+
589+
// Checking of there is any offending clauses before the first separator.
590+
for (auto cl : GetContext().actualClauses) {
591+
if (cl == separator) {
592+
break;
593+
}
594+
if (set.test(cl)) {
595+
context_.Say(GetContext().directiveSource,
596+
"Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
597+
parser::ToUpperCaseLetters(getClauseName(clause).str()),
598+
parser::ToUpperCaseLetters(getClauseName(cl).str()),
599+
ContextDirectiveAsFortran());
600+
}
601+
}
602+
603+
// Checking for mutually exclusive clauses in the current group.
604+
for (auto cl : GetContext().crtGroup) {
605+
if (set.test(cl)) {
606+
context_.Say(GetContext().directiveSource,
607+
"Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
608+
parser::ToUpperCaseLetters(getClauseName(clause).str()),
609+
parser::ToUpperCaseLetters(getClauseName(cl).str()),
610+
ContextDirectiveAsFortran());
611+
}
612+
}
613+
}
614+
573615
// Check the value of the clause is a constant positive integer.
574616
template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
575617
void DirectiveStructureChecker<D, C, PC,

flang/test/Semantics/OpenACC/acc-routine.f90

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,114 @@ subroutine sub2(a)
1313
subroutine sub3()
1414
!$acc routine bind(sub1)
1515
end subroutine
16+
17+
subroutine sub6()
18+
!ERROR: Clause GANG is not allowed if clause GANG appears on the ROUTINE directive
19+
!$acc routine gang gang
20+
21+
!ERROR: Clause GANG is not allowed if clause WORKER appears on the ROUTINE directive
22+
!$acc routine worker gang
23+
24+
!ERROR: Clause GANG is not allowed if clause VECTOR appears on the ROUTINE directive
25+
!$acc routine vector gang
26+
27+
!ERROR: Clause GANG is not allowed if clause SEQ appears on the ROUTINE directive
28+
!$acc routine seq gang
29+
30+
!ERROR: Clause WORKER is not allowed if clause WORKER appears on the ROUTINE directive
31+
!$acc routine worker worker
32+
33+
!ERROR: Clause WORKER is not allowed if clause GANG appears on the ROUTINE directive
34+
!$acc routine gang worker
35+
36+
!ERROR: Clause WORKER is not allowed if clause VECTOR appears on the ROUTINE directive
37+
!$acc routine vector worker
38+
39+
!ERROR: Clause WORKER is not allowed if clause SEQ appears on the ROUTINE directive
40+
!$acc routine seq worker
41+
42+
!ERROR: Clause VECTOR is not allowed if clause VECTOR appears on the ROUTINE directive
43+
!$acc routine vector vector
44+
45+
!ERROR: Clause VECTOR is not allowed if clause GANG appears on the ROUTINE directive
46+
!$acc routine gang vector
47+
48+
!ERROR: Clause VECTOR is not allowed if clause WORKER appears on the ROUTINE directive
49+
!$acc routine worker vector
50+
51+
!ERROR: Clause VECTOR is not allowed if clause SEQ appears on the ROUTINE directive
52+
!$acc routine seq vector
53+
54+
!ERROR: Clause SEQ is not allowed if clause SEQ appears on the ROUTINE directive
55+
!$acc routine seq seq
56+
57+
!ERROR: Clause SEQ is not allowed if clause GANG appears on the ROUTINE directive
58+
!$acc routine gang seq
59+
60+
!ERROR: Clause SEQ is not allowed if clause WORKER appears on the ROUTINE directive
61+
!$acc routine worker seq
62+
63+
!ERROR: Clause SEQ is not allowed if clause VECTOR appears on the ROUTINE directive
64+
!$acc routine vector seq
65+
66+
end subroutine
67+
68+
subroutine sub7()
69+
!$acc routine device_type(*) gang device_type(host) worker
70+
71+
!ERROR: Clause SEQ is not allowed if clause GANG appears on the ROUTINE directive
72+
!$acc routine device_type(*) gang seq
73+
74+
!ERROR: Clause WORKER is not allowed if clause GANG appears on the ROUTINE directive
75+
!$acc routine device_type(*) gang worker
76+
77+
!ERROR: Clause GANG is not allowed if clause GANG appears on the ROUTINE directive
78+
!$acc routine gang device_type(*) gang
79+
80+
!ERROR: Clause WORKER is not allowed if clause GANG appears on the ROUTINE directive
81+
!$acc routine gang device_type(*) worker
82+
83+
!ERROR: Clause VECTOR is not allowed if clause GANG appears on the ROUTINE directive
84+
!$acc routine gang device_type(*) vector
85+
86+
!ERROR: Clause SEQ is not allowed if clause GANG appears on the ROUTINE directive
87+
!$acc routine gang device_type(*) seq
88+
89+
!ERROR: Clause WORKER is not allowed if clause WORKER appears on the ROUTINE directive
90+
!$acc routine worker device_type(*) worker
91+
92+
!ERROR: Clause GANG is not allowed if clause WORKER appears on the ROUTINE directive
93+
!$acc routine worker device_type(*) gang
94+
95+
!ERROR: Clause VECTOR is not allowed if clause WORKER appears on the ROUTINE directive
96+
!$acc routine worker device_type(*) vector
97+
98+
!ERROR: Clause SEQ is not allowed if clause WORKER appears on the ROUTINE directive
99+
!$acc routine worker device_type(*) seq
100+
101+
!ERROR: Clause VECTOR is not allowed if clause VECTOR appears on the ROUTINE directive
102+
!$acc routine vector device_type(*) vector
103+
104+
!ERROR: Clause GANG is not allowed if clause VECTOR appears on the ROUTINE directive
105+
!$acc routine vector device_type(*) gang
106+
107+
!ERROR: Clause VECTOR is not allowed if clause VECTOR appears on the ROUTINE directive
108+
!$acc routine vector device_type(*) vector
109+
110+
!ERROR: Clause SEQ is not allowed if clause VECTOR appears on the ROUTINE directive
111+
!$acc routine vector device_type(*) seq
112+
113+
!ERROR: Clause SEQ is not allowed if clause SEQ appears on the ROUTINE directive
114+
!$acc routine seq device_type(*) seq
115+
116+
!ERROR: Clause GANG is not allowed if clause SEQ appears on the ROUTINE directive
117+
!$acc routine seq device_type(*) gang
118+
119+
!ERROR: Clause VECTOR is not allowed if clause SEQ appears on the ROUTINE directive
120+
!$acc routine seq device_type(*) vector
121+
122+
!ERROR: Clause WORKER is not allowed if clause SEQ appears on the ROUTINE directive
123+
!$acc routine seq device_type(*) worker
124+
125+
!$acc routine device_type(host) seq device_type(nvidia) gang device_type(multicore) vector device_type(*) worker
126+
end subroutine

0 commit comments

Comments
 (0)