Skip to content

Commit 760eca1

Browse files
committed
[flang][openacc] Accept !$acc end loop
Some compilers accept `!$acc end loop` associated with an `!$acc loop` directive. This patch updates the acc loop parser to accept it as well. The parser is also updated to be stricter on the following statement to match the OpenACC combined construct parser. The rewrite canonicalization is not a rewrite anymore and the naming will be updated in a follow up patch for the Loop and Combined constructs. Reviewed By: razvanlupusoru Differential Revision: https://reviews.llvm.org/D159015
1 parent 456fdf8 commit 760eca1

File tree

10 files changed

+57
-70
lines changed

10 files changed

+57
-70
lines changed

flang/docs/OpenACC.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
* The end directive for combined construct can omit the `loop` keyword.
1818
* An `!$acc routine` with no parallelism clause is treated as if the `seq`
1919
clause was present.
20+
* `!$acc end loop` does not trigger a parsing error and is just ignored.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class ParseTreeDumper {
105105
NODE(parser, AccTileExpr)
106106
NODE(parser, AccTileExprList)
107107
NODE(parser, AccLoopDirective)
108+
NODE(parser, AccEndLoop)
108109
NODE(parser, AccWaitArgument)
109110
static std::string GetNodeName(const llvm::acc::Directive &x) {
110111
return llvm::Twine(

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4244,11 +4244,10 @@ struct OpenACCDeclarativeConstruct {
42444244
};
42454245

42464246
// OpenACC directives enclosing do loop
4247+
EMPTY_CLASS(AccEndLoop);
42474248
struct OpenACCLoopConstruct {
42484249
TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct);
4249-
OpenACCLoopConstruct(AccBeginLoopDirective &&a)
4250-
: t({std::move(a), std::nullopt}) {}
4251-
std::tuple<AccBeginLoopDirective, std::optional<DoConstruct>> t;
4250+
std::tuple<AccBeginLoopDirective, DoConstruct, std::optional<AccEndLoop>> t;
42524251
};
42534252

42544253
struct OpenACCStandaloneConstruct {

flang/lib/Parser/openacc-parsers.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,13 @@ TYPE_PARSER(sourced(construct<AccLoopDirective>(
150150
TYPE_PARSER(construct<AccBeginLoopDirective>(
151151
sourced(Parser<AccLoopDirective>{}), Parser<AccClauseList>{}))
152152

153-
TYPE_PARSER(
154-
construct<OpenACCLoopConstruct>(sourced(Parser<AccBeginLoopDirective>{})))
153+
TYPE_PARSER(construct<AccEndLoop>(startAccLine >> "END LOOP"_tok))
154+
155+
TYPE_PARSER(construct<OpenACCLoopConstruct>(
156+
sourced(Parser<AccBeginLoopDirective>{} / endAccLine),
157+
withMessage("A DO loop must follow the loop construct"_err_en_US,
158+
Parser<DoConstruct>{}),
159+
maybe(Parser<AccEndLoop>{} / endAccLine)))
155160

156161
// 2.15.1 Routine directive
157162
TYPE_PARSER(sourced(construct<OpenACCRoutineConstruct>(verbatim("ROUTINE"_tok),

flang/lib/Parser/unparse.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1947,7 +1947,7 @@ class UnparseVisitor {
19471947
Walk(std::get<AccBeginLoopDirective>(x.t));
19481948
Put("\n");
19491949
EndOpenACC();
1950-
Walk(std::get<std::optional<DoConstruct>>(x.t));
1950+
Walk(std::get<DoConstruct>(x.t));
19511951
}
19521952
void Unparse(const AccBeginLoopDirective &x) {
19531953
Walk(std::get<AccLoopDirective>(x.t));

flang/lib/Semantics/canonicalize-acc.cpp

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class CanonicalizationOfAcc {
5252
// If there are n tile sizes in the list, the loop construct must be
5353
// immediately followed by n tightly-nested loops.
5454
template <typename C, typename D>
55-
void CheckTileClauseRestriction(const C &x) {
55+
void CheckTileClauseRestriction(
56+
const C &x, const parser::DoConstruct &outer) {
5657
const auto &beginLoopDirective = std::get<D>(x.t);
5758
const auto &accClauseList =
5859
std::get<parser::AccClauseList>(beginLoopDirective.t);
@@ -63,11 +64,10 @@ class CanonicalizationOfAcc {
6364
const std::list<parser::AccTileExpr> &listTileExpr = tileExprList.v;
6465
std::size_t tileArgNb = listTileExpr.size();
6566

66-
const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
67-
if (outer->IsDoConcurrent()) {
67+
if (outer.IsDoConcurrent()) {
6868
return; // Tile is not allowed on DO CONCURRENT
6969
}
70-
for (const parser::DoConstruct *loop{&*outer}; loop && tileArgNb > 0;
70+
for (const parser::DoConstruct *loop{&outer}; loop && tileArgNb > 0;
7171
--tileArgNb) {
7272
const auto &block{std::get<parser::Block>(loop->t)};
7373
const auto it{block.begin()};
@@ -89,9 +89,9 @@ class CanonicalizationOfAcc {
8989
// A tile and collapse clause may not appear on loop that is associated with
9090
// do concurrent.
9191
template <typename C, typename D>
92-
void CheckDoConcurrentClauseRestriction(const C &x) {
93-
const auto &doCons{std::get<std::optional<parser::DoConstruct>>(x.t)};
94-
if (!doCons->IsDoConcurrent()) {
92+
void CheckDoConcurrentClauseRestriction(
93+
const C &x, const parser::DoConstruct &doCons) {
94+
if (!doCons.IsDoConcurrent()) {
9595
return;
9696
}
9797
const auto &beginLoopDirective = std::get<D>(x.t);
@@ -109,73 +109,36 @@ class CanonicalizationOfAcc {
109109

110110
void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x,
111111
parser::Block &block, parser::Block::iterator it) {
112-
// Check the sequence of DoConstruct in the same iteration
113-
//
114-
// Original:
115-
// ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
116-
// ACCBeginLoopDirective
117-
// ExecutableConstruct -> DoConstruct
118-
//
119-
// After rewriting:
120-
// ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
121-
// AccBeginLoopDirective
122-
// DoConstruct
123-
parser::Block::iterator nextIt;
124112
auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
125113
auto &dir{std::get<parser::AccLoopDirective>(beginDir.t)};
114+
const auto &doCons{std::get<parser::DoConstruct>(x.t)};
126115

127-
nextIt = it;
128-
if (++nextIt != block.end()) {
129-
if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
130-
if (!doCons->GetLoopControl()) {
131-
messages_.Say(dir.source,
132-
"DO loop after the %s directive must have loop control"_err_en_US,
133-
parser::ToUpperCaseLetters(dir.source.ToString()));
134-
return;
135-
}
136-
137-
// move DoConstruct
138-
std::get<std::optional<parser::DoConstruct>>(x.t) = std::move(*doCons);
139-
nextIt = block.erase(nextIt);
140-
141-
CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,
142-
parser::AccBeginLoopDirective>(x);
143-
CheckTileClauseRestriction<parser::OpenACCLoopConstruct,
144-
parser::AccBeginLoopDirective>(x);
145-
146-
return; // found do-loop
147-
}
116+
if (!doCons.GetLoopControl()) {
117+
messages_.Say(dir.source,
118+
"DO loop after the %s directive must have loop control"_err_en_US,
119+
parser::ToUpperCaseLetters(dir.source.ToString()));
120+
return;
148121
}
149-
messages_.Say(dir.source,
150-
"A DO loop must follow the %s directive"_err_en_US,
151-
parser::ToUpperCaseLetters(dir.source.ToString()));
122+
123+
CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,
124+
parser::AccBeginLoopDirective>(x, doCons);
125+
CheckTileClauseRestriction<parser::OpenACCLoopConstruct,
126+
parser::AccBeginLoopDirective>(x, doCons);
152127
}
153128

154129
void RewriteOpenACCCombinedConstruct(parser::OpenACCCombinedConstruct &x,
155130
parser::Block &block, parser::Block::iterator it) {
156-
// Check the sequence of DoConstruct in the same iteration
157-
//
158-
// Original:
159-
// ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
160-
// ACCBeginCombinedDirective
161-
// ExecutableConstruct -> DoConstruct
162-
// ExecutableConstruct -> AccEndCombinedDirective (if available)
163-
//
164-
// After rewriting:
165-
// ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
166-
// ACCBeginCombinedDirective
167-
// DoConstruct
168-
// AccEndCombinedDirective (if available)
131+
// Check the sequence of DoConstruct in the same iteration.
169132
parser::Block::iterator nextIt;
170133
auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
171134
auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};
172-
auto &doConstruct{std::get<std::optional<parser::DoConstruct>>(x.t)};
135+
const auto &doConstruct{std::get<std::optional<parser::DoConstruct>>(x.t)};
173136

174137
if (doConstruct) {
175138
CheckDoConcurrentClauseRestriction<parser::OpenACCCombinedConstruct,
176-
parser::AccBeginCombinedDirective>(x);
139+
parser::AccBeginCombinedDirective>(x, *doConstruct);
177140
CheckTileClauseRestriction<parser::OpenACCCombinedConstruct,
178-
parser::AccBeginCombinedDirective>(x);
141+
parser::AccBeginCombinedDirective>(x, *doConstruct);
179142
if (!doConstruct->GetLoopControl()) {
180143
messages_.Say(dir.source,
181144
"DO loop after the %s directive must have loop control"_err_en_US,

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,8 +1088,8 @@ void AccAttributeVisitor::PrivatizeAssociatedLoopIndex(
10881088
return nullptr;
10891089
};
10901090

1091-
const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
1092-
for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) {
1091+
const auto &outer{std::get<parser::DoConstruct>(x.t)};
1092+
for (const parser::DoConstruct *loop{&outer}; loop && level > 0; --level) {
10931093
// go through all the nested do-loops and resolve index variables
10941094
const parser::Name *iv{GetLoopIndex(*loop)};
10951095
if (iv) {

flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ program openacc_clause_validity
1515
real(8) :: a(256)
1616
real(8) :: aa(256, 256)
1717

18-
!ERROR: A DO loop must follow the LOOP directive
19-
!$acc loop
20-
i = 1
18+
i = 0
2119

2220
!ERROR: DO loop after the LOOP directive must have loop control
2321
!$acc loop
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
! RUN: %python %S/../test_errors.py %s %flang -fopenacc
2+
3+
program openacc_clause_validity
4+
5+
implicit none
6+
7+
integer :: i
8+
9+
i = 0
10+
11+
!$acc loop
12+
!ERROR: A DO loop must follow the loop construct
13+
i = 1
14+
15+
end

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,9 @@ program openacc_loop_validity
263263
do i = 1, N
264264
end do
265265

266+
!$acc loop
267+
do i = 1, N
268+
end do
269+
!$acc end loop
270+
266271
end program openacc_loop_validity

0 commit comments

Comments
 (0)