Skip to content

Commit 05169af

Browse files
committed
[flang][openacc] Handle optional end directive in combined construct
OpenACC combined construct can have an optional end directive. This patch handle this case in the parsing/unparsing with a canonicalization step. Unlike OmpEndLoopDirective, this doesn't need a special treatment in the pre-fir tree as there is no clause attached to a AccEndCombinedDirective. Reviewed By: klausler Differential Revision: https://reviews.llvm.org/D84481
1 parent 8d58eb1 commit 05169af

File tree

11 files changed

+230
-18
lines changed

11 files changed

+230
-18
lines changed

flang/include/flang/Parser/parse-tree.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ struct AssignStmt;
258258
struct AssignedGotoStmt;
259259
struct PauseStmt;
260260
struct OpenACCConstruct;
261+
struct AccEndCombinedDirective;
261262
struct OpenACCDeclarativeConstruct;
262263
struct OpenMPConstruct;
263264
struct OpenMPDeclarativeConstruct;
@@ -517,6 +518,7 @@ struct ExecutableConstruct {
517518
common::Indirection<WhereConstruct>, common::Indirection<ForallConstruct>,
518519
common::Indirection<CompilerDirective>,
519520
common::Indirection<OpenACCConstruct>,
521+
common::Indirection<AccEndCombinedDirective>,
520522
common::Indirection<OpenMPConstruct>,
521523
common::Indirection<OmpEndLoopDirective>>
522524
u;
@@ -3970,6 +3972,7 @@ struct OpenACCStandaloneDeclarativeConstruct {
39703972

39713973
struct AccBeginCombinedDirective {
39723974
TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective);
3975+
CharBlock source;
39733976
std::tuple<AccCombinedDirective, AccClauseList> t;
39743977
};
39753978

@@ -3981,7 +3984,9 @@ struct AccEndCombinedDirective {
39813984
struct OpenACCCombinedConstruct {
39823985
TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct);
39833986
CharBlock source;
3984-
std::tuple<AccBeginCombinedDirective, Block,
3987+
OpenACCCombinedConstruct(AccBeginCombinedDirective &&a)
3988+
: t({std::move(a), std::nullopt, std::nullopt}) {}
3989+
std::tuple<AccBeginCombinedDirective, std::optional<DoConstruct>,
39853990
std::optional<AccEndCombinedDirective>>
39863991
t;
39873992
};

flang/lib/Parser/executable-parsers.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ constexpr auto executableConstruct{
5050
construct<ExecutableConstruct>(indirect(whereConstruct)),
5151
construct<ExecutableConstruct>(indirect(forallConstruct)),
5252
construct<ExecutableConstruct>(indirect(ompEndLoopDirective)),
53-
construct<ExecutableConstruct>(indirect(openaccConstruct)),
5453
construct<ExecutableConstruct>(indirect(openmpConstruct)),
54+
construct<ExecutableConstruct>(indirect(accEndCombinedDirective)),
55+
construct<ExecutableConstruct>(indirect(openaccConstruct)),
5556
construct<ExecutableConstruct>(indirect(compilerDirective)))};
5657

5758
// R510 execution-part-construct ->

flang/lib/Parser/openacc-parsers.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,9 @@ TYPE_PARSER(sourced(
199199
parenthesized(Parser<AccObjectListWithModifier>{}))))
200200

201201
// 2.11 Combined constructs
202-
TYPE_PARSER(startAccLine >> construct<AccEndCombinedDirective>(sourced(
203-
"END"_tok >> Parser<AccCombinedDirective>{})))
204-
205202
TYPE_PARSER(construct<AccBeginCombinedDirective>(
206203
sourced(Parser<AccCombinedDirective>{}), Parser<AccClauseList>{}))
207204

208-
TYPE_PARSER(construct<OpenACCCombinedConstruct>(
209-
Parser<AccBeginCombinedDirective>{} / endAccLine, block,
210-
maybe(Parser<AccEndCombinedDirective>{} / endAccLine)))
211-
212205
// 2.12 Atomic constructs
213206
TYPE_PARSER(construct<AccEndAtomic>(startAccLine >> "END ATOMIC"_tok))
214207

@@ -281,4 +274,11 @@ TYPE_CONTEXT_PARSER("OpenACC construct"_en_US,
281274
construct<OpenACCConstruct>(Parser<OpenACCCacheConstruct>{}),
282275
construct<OpenACCConstruct>(Parser<OpenACCWaitConstruct>{}),
283276
construct<OpenACCConstruct>(Parser<OpenACCAtomicConstruct>{})))
277+
278+
TYPE_PARSER(startAccLine >> sourced(construct<AccEndCombinedDirective>(sourced(
279+
"END"_tok >> Parser<AccCombinedDirective>{}))))
280+
281+
TYPE_PARSER(construct<OpenACCCombinedConstruct>(
282+
sourced(Parser<AccBeginCombinedDirective>{} / endAccLine)))
283+
284284
} // namespace Fortran::parser

flang/lib/Parser/program-parsers.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ TYPE_CONTEXT_PARSER("specification part"_en_US,
7676
// are in contexts that impose constraints on the kinds of statements that
7777
// are allowed, and so we have a variant production for declaration-construct
7878
// that implements those constraints.
79-
constexpr auto execPartLookAhead{first(actionStmt >> ok,
80-
ompEndLoopDirective >> ok, openaccConstruct >> ok, openmpConstruct >> ok,
81-
"ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
82-
"CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
79+
constexpr auto execPartLookAhead{
80+
first(actionStmt >> ok, openaccConstruct >> ok, openmpConstruct >> ok,
81+
"ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
82+
"CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
8383
constexpr auto declErrorRecovery{
8484
stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery};
8585
constexpr auto misplacedSpecificationStmt{Parser<UseStmt>{} >>

flang/lib/Parser/type-parsers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ constexpr Parser<EntryStmt> entryStmt; // R1541
131131
constexpr Parser<ContainsStmt> containsStmt; // R1543
132132
constexpr Parser<CompilerDirective> compilerDirective;
133133
constexpr Parser<OpenACCConstruct> openaccConstruct;
134+
constexpr Parser<AccEndCombinedDirective> accEndCombinedDirective;
134135
constexpr Parser<OpenACCDeclarativeConstruct> openaccDeclarativeConstruct;
135136
constexpr Parser<OpenMPConstruct> openmpConstruct;
136137
constexpr Parser<OpenMPDeclarativeConstruct> openmpDeclarativeConstruct;

flang/lib/Parser/unparse.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,10 +2104,9 @@ class UnparseVisitor {
21042104
Walk(std::get<AccBeginCombinedDirective>(x.t));
21052105
Put("\n");
21062106
EndOpenACC();
2107-
Walk(std::get<Block>(x.t), "");
2107+
Walk(std::get<std::optional<DoConstruct>>(x.t));
21082108
BeginOpenACC();
2109-
Word("!$ACC END ");
2110-
Walk(std::get<std::optional<AccEndCombinedDirective>>(x.t));
2109+
Walk("!$ACC END ", std::get<std::optional<DoConstruct>>(x.t));
21112110
Put("\n");
21122111
EndOpenACC();
21132112
}

flang/lib/Semantics/canonicalize-acc.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
// 1. move structured DoConstruct into
1717
// OpenACCLoopConstruct. Compilation will not proceed in case of errors
1818
// after this pass.
19+
// 2. move structured DoConstruct into OpenACCCombinedConstruct. Move
20+
// AccEndCombinedConstruct into OpenACCCombinedConstruct if present.
21+
// Compilation will not proceed in case of errors after this pass.
1922
namespace Fortran::semantics {
2023

2124
using namespace parser::literals;
@@ -30,6 +33,16 @@ class CanonicalizationOfAcc {
3033
for (auto it{block.begin()}; it != block.end(); ++it) {
3134
if (auto *accLoop{parser::Unwrap<parser::OpenACCLoopConstruct>(*it)}) {
3235
RewriteOpenACCLoopConstruct(*accLoop, block, it);
36+
} else if (auto *accCombined{
37+
parser::Unwrap<parser::OpenACCCombinedConstruct>(*it)}) {
38+
RewriteOpenACCCombinedConstruct(*accCombined, block, it);
39+
} else if (auto *endDir{
40+
parser::Unwrap<parser::AccEndCombinedDirective>(*it)}) {
41+
// Unmatched AccEndCombinedDirective
42+
messages_.Say(endDir->v.source,
43+
"The %s directive must follow the DO loop associated with the "
44+
"loop construct"_err_en_US,
45+
parser::ToUpperCaseLetters(endDir->v.source.ToString()));
3346
}
3447
} // Block list
3548
}
@@ -73,6 +86,55 @@ class CanonicalizationOfAcc {
7386
parser::ToUpperCaseLetters(dir.source.ToString()));
7487
}
7588

89+
void RewriteOpenACCCombinedConstruct(parser::OpenACCCombinedConstruct &x,
90+
parser::Block &block, parser::Block::iterator it) {
91+
// Check the sequence of DoConstruct in the same iteration
92+
//
93+
// Original:
94+
// ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
95+
// ACCBeginCombinedDirective
96+
// ExecutableConstruct -> DoConstruct
97+
// ExecutableConstruct -> AccEndCombinedDirective (if available)
98+
//
99+
// After rewriting:
100+
// ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
101+
// ACCBeginCombinedDirective
102+
// DoConstruct
103+
// AccEndCombinedDirective (if available)
104+
parser::Block::iterator nextIt;
105+
auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
106+
auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};
107+
108+
nextIt = it;
109+
if (++nextIt != block.end()) {
110+
if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
111+
if (doCons->GetLoopControl()) {
112+
// move DoConstruct
113+
std::get<std::optional<parser::DoConstruct>>(x.t) =
114+
std::move(*doCons);
115+
nextIt = block.erase(nextIt);
116+
// try to match AccEndCombinedDirective
117+
if (nextIt != block.end()) {
118+
if (auto *endDir{
119+
parser::Unwrap<parser::AccEndCombinedDirective>(*nextIt)}) {
120+
std::get<std::optional<parser::AccEndCombinedDirective>>(x.t) =
121+
std::move(*endDir);
122+
block.erase(nextIt);
123+
}
124+
}
125+
} else {
126+
messages_.Say(dir.source,
127+
"DO loop after the %s directive must have loop control"_err_en_US,
128+
parser::ToUpperCaseLetters(dir.source.ToString()));
129+
}
130+
return; // found do-loop
131+
}
132+
}
133+
messages_.Say(dir.source,
134+
"A DO loop must follow the %s directive"_err_en_US,
135+
parser::ToUpperCaseLetters(dir.source.ToString()));
136+
}
137+
76138
parser::Messages &messages_;
77139
};
78140

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,17 @@ void AccStructureChecker::Leave(
156156
}
157157

158158
void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
159-
const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
159+
const auto &beginCombinedDir{
160+
std::get<parser::AccBeginCombinedDirective>(x.t)};
160161
const auto &combinedDir{
161-
std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
162+
std::get<parser::AccCombinedDirective>(beginCombinedDir.t)};
163+
164+
// check matching, End directive is optional
165+
if (const auto &endCombinedDir{
166+
std::get<std::optional<parser::AccEndCombinedDirective>>(x.t)}) {
167+
CheckMatching<parser::AccCombinedDirective>(combinedDir, endCombinedDir->v);
168+
}
169+
162170
PushContextAndClauseSets(combinedDir.source, combinedDir.v);
163171
}
164172

flang/test/Lower/pre-fir-tree05.f90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,19 @@ subroutine foo()
3131
end subroutine
3232
! CHECK-NEXT: EndSubroutine foo
3333

34+
! CHECK: Subroutine foo
35+
subroutine foo2()
36+
! CHECK-NEXT: <<OpenACCConstruct>>
37+
!$acc parallel loop
38+
! CHECK-NEXT: <<DoConstruct>>
39+
! CHECK-NEXT: NonLabelDoStmt
40+
do i=1,5
41+
! CHECK-NEXT: EndDoStmt
42+
! CHECK-NEXT: <<End DoConstruct>>
43+
end do
44+
!$acc end parallel loop
45+
! CHECK-NEXT: <<End OpenACCConstruct>>
46+
! CHECK-NEXT: ContinueStmt
47+
end subroutine
48+
! CHECK-NEXT: EndSubroutine foo2
49+
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
! RUN: %S/test_errors.sh %s %t %f18 -fopenacc
2+
3+
! Check OpenACC canonalization validity for the construct defined below:
4+
! 2.9 Loop
5+
! 2.11 Parallel Loop
6+
! 2.11 Kernels Loop
7+
! 2.11 Serial Loop
8+
9+
program openacc_clause_validity
10+
11+
implicit none
12+
13+
integer :: i, j
14+
integer :: N = 256
15+
real(8) :: a(256)
16+
17+
!ERROR: A DO loop must follow the LOOP directive
18+
!$acc loop
19+
i = 1
20+
21+
!ERROR: DO loop after the LOOP directive must have loop control
22+
!$acc loop
23+
do
24+
end do
25+
26+
!ERROR: A DO loop must follow the PARALLEL LOOP directive
27+
!$acc parallel loop
28+
i = 1
29+
30+
!ERROR: A DO loop must follow the KERNELS LOOP directive
31+
!$acc kernels loop
32+
i = 1
33+
34+
!ERROR: A DO loop must follow the SERIAL LOOP directive
35+
!$acc serial loop
36+
i = 1
37+
38+
!ERROR: The END PARALLEL LOOP directive must follow the DO loop associated with the loop construct
39+
!$acc end parallel loop
40+
41+
!ERROR: The END KERNELS LOOP directive must follow the DO loop associated with the loop construct
42+
!$acc end kernels loop
43+
44+
!ERROR: The END SERIAL LOOP directive must follow the DO loop associated with the loop construct
45+
!$acc end serial loop
46+
47+
!$acc parallel loop
48+
do i = 1, N
49+
a(i) = 3.14
50+
end do
51+
52+
!$acc kernels loop
53+
do i = 1, N
54+
a(i) = 3.14
55+
end do
56+
57+
!$acc serial loop
58+
do i = 1, N
59+
a(i) = 3.14
60+
end do
61+
62+
!$acc parallel loop
63+
do i = 1, N
64+
a(i) = 3.14
65+
end do
66+
!$acc end parallel loop
67+
68+
!$acc kernels loop
69+
do i = 1, N
70+
a(i) = 3.14
71+
end do
72+
!$acc end kernels loop
73+
74+
!$acc serial loop
75+
do i = 1, N
76+
a(i) = 3.14
77+
end do
78+
!$acc end serial loop
79+
80+
!ERROR: DO loop after the PARALLEL LOOP directive must have loop control
81+
!$acc parallel loop
82+
do
83+
end do
84+
85+
!ERROR: DO loop after the KERNELS LOOP directive must have loop control
86+
!$acc kernels loop
87+
do
88+
end do
89+
90+
!ERROR: DO loop after the SERIAL LOOP directive must have loop control
91+
!$acc serial loop
92+
do
93+
end do
94+
95+
end program openacc_clause_validity

flang/test/Semantics/acc-clause-validity.f90

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
! 2.5.1 Parallel
66
! 2.5.2 Kernels
77
! 2.5.3 Serial
8+
! 2.9 Loop
9+
! 2.13 Declare
10+
! 2.14.3 Set
11+
! 2.14.4 Update
812
! 2.15.1 Routine
913
! 2.11 Parallel Loop
1014
! 2.11 Kernels Loop
@@ -162,6 +166,27 @@ program openacc_clause_validity
162166
end do
163167
!$acc end serial loop
164168

169+
!$acc parallel loop
170+
do i = 1, N
171+
a(i) = 3.14
172+
end do
173+
!ERROR: Unmatched END KERNELS LOOP directive
174+
!$acc end kernels loop
175+
176+
!$acc kernels loop
177+
do i = 1, N
178+
a(i) = 3.14
179+
end do
180+
!ERROR: Unmatched END SERIAL LOOP directive
181+
!$acc end serial loop
182+
183+
!$acc serial loop
184+
do i = 1, N
185+
a(i) = 3.14
186+
end do
187+
!ERROR: Unmatched END PARALLEL LOOP directive
188+
!$acc end parallel loop
189+
165190
contains
166191

167192
subroutine sub1(a)

0 commit comments

Comments
 (0)