Skip to content

Commit a527248

Browse files
authored
[flang][acc] allow and ignore DIR between ACC and loops (#106522)
The current pattern was failing OpenACC semantics in acc parse tree canonicalization: ``` !acc loop !dir vector aligned do i=1,n ... ``` Fix it by moving the directive before the OpenACC construct node. Note that I think it could make sense to propagate the $dir info to the acc.loop, at least with classic flang, the $dir seems to make a difference. This is not done here since few directives are supported anyway.
1 parent b65fc7e commit a527248

File tree

5 files changed

+116
-12
lines changed

5 files changed

+116
-12
lines changed

flang/lib/Lower/OpenACC.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,13 @@ static mlir::acc::LoopOp createLoopOp(
20802080
loopOp.setCombinedAttr(mlir::acc::CombinedConstructsTypeAttr::get(
20812081
builder.getContext(), *combinedConstructs));
20822082

2083+
// TODO: retrieve directives from NonLabelDoStmt pft::Evaluation, and add them
2084+
// as attribute to the acc.loop as an extra attribute. It is not quite clear
2085+
// how useful these $dir are in acc contexts, but they could still provide
2086+
// more information about the loop acc codegen. They can be obtained by
2087+
// looking for the first lexicalSuccessor of eval that is a NonLabelDoStmt,
2088+
// and using the related `dirs` member.
2089+
20832090
return loopOp;
20842091
}
20852092

flang/lib/Semantics/canonicalize-acc.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ class CanonicalizationOfAcc {
107107
}
108108
}
109109

110+
// Utility to move all parser::CompilerDirective right after it to right
111+
// before it. This allows preserving loop directives $DIR that may lie
112+
// between an $acc directive and loop and leave lowering decide if it should
113+
// ignore them or lower/apply them to the acc loops.
114+
void moveCompilerDirectivesBefore(
115+
parser::Block &block, parser::Block::iterator it) {
116+
parser::Block::iterator nextIt = std::next(it);
117+
while (nextIt != block.end() &&
118+
parser::Unwrap<parser::CompilerDirective>(*nextIt)) {
119+
block.emplace(it, std::move(*nextIt));
120+
nextIt = block.erase(nextIt);
121+
}
122+
}
123+
110124
void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x,
111125
parser::Block &block, parser::Block::iterator it) {
112126
parser::Block::iterator nextIt;
@@ -115,6 +129,7 @@ class CanonicalizationOfAcc {
115129
auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};
116130

117131
if (!nestedDo) {
132+
moveCompilerDirectivesBefore(block, it);
118133
nextIt = it;
119134
if (++nextIt != block.end()) {
120135
if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
@@ -151,6 +166,7 @@ class CanonicalizationOfAcc {
151166
auto &nestedDo{std::get<std::optional<parser::DoConstruct>>(x.t)};
152167

153168
if (!nestedDo) {
169+
moveCompilerDirectivesBefore(block, it);
154170
nextIt = it;
155171
if (++nextIt != block.end()) {
156172
if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {

flang/lib/Semantics/canonicalize-directives.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "canonicalize-directives.h"
1010
#include "flang/Parser/parse-tree-visitor.h"
11+
#include "flang/Semantics/tools.h"
1112

1213
namespace Fortran::semantics {
1314

@@ -82,25 +83,19 @@ bool CanonicalizationOfDirectives::Pre(parser::ExecutionPart &x) {
8283
return true;
8384
}
8485

85-
template <typename T> T *GetConstructIf(parser::ExecutionPartConstruct &x) {
86-
if (auto *y{std::get_if<parser::ExecutableConstruct>(&x.u)}) {
87-
if (auto *z{std::get_if<common::Indirection<T>>(&y->u)}) {
88-
return &z->value();
89-
}
90-
}
91-
return nullptr;
92-
}
93-
9486
void CanonicalizationOfDirectives::CheckLoopDirective(
9587
parser::CompilerDirective &dir, parser::Block &block,
9688
std::list<parser::ExecutionPartConstruct>::iterator it) {
9789

9890
// Skip over this and other compiler directives
99-
while (GetConstructIf<parser::CompilerDirective>(*it)) {
91+
while (it != block.end() && parser::Unwrap<parser::CompilerDirective>(*it)) {
10092
++it;
10193
}
10294

103-
if (it == block.end() || !GetConstructIf<parser::DoConstruct>(*it)) {
95+
if (it == block.end() ||
96+
(!parser::Unwrap<parser::DoConstruct>(*it) &&
97+
!parser::Unwrap<parser::OpenACCLoopConstruct>(*it) &&
98+
!parser::Unwrap<parser::OpenACCCombinedConstruct>(*it))) {
10499
std::string s{parser::ToUpperCaseLetters(dir.source.ToString())};
105100
s.pop_back(); // Remove trailing newline from source string
106101
messages_.Say(
@@ -110,7 +105,7 @@ void CanonicalizationOfDirectives::CheckLoopDirective(
110105

111106
void CanonicalizationOfDirectives::Post(parser::Block &block) {
112107
for (auto it{block.begin()}; it != block.end(); ++it) {
113-
if (auto *dir{GetConstructIf<parser::CompilerDirective>(*it)}) {
108+
if (auto *dir{parser::Unwrap<parser::CompilerDirective>(*it)}) {
114109
std::visit(
115110
common::visitors{[&](parser::CompilerDirective::VectorAlways &) {
116111
CheckLoopDirective(*dir, block, it);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
! Test that $dir loop directives (known or unknown) are not clashing
2+
! with $acc lowering.
3+
4+
! RUN: %flang_fc1 -fopenacc -emit-hlfir %s -o - | FileCheck %s
5+
6+
subroutine test_before_acc_loop(a, b, c)
7+
real, dimension(10) :: a,b,c
8+
!dir$ myloop_directive_1
9+
!dir$ myloop_directive_2
10+
!$acc loop
11+
do i=1,N
12+
a(i) = b(i) + c(i)
13+
enddo
14+
end subroutine
15+
! CHECK-LABEL: test_before_acc_loop
16+
! CHECK: acc.loop
17+
18+
subroutine test_after_acc_loop(a, b, c)
19+
real, dimension(10) :: a,b,c
20+
!$acc loop
21+
!dir$ myloop_directive_1
22+
!dir$ myloop_directive_2
23+
do i=1,N
24+
a(i) = b(i) + c(i)
25+
enddo
26+
end subroutine
27+
! CHECK-LABEL: test_after_acc_loop
28+
! CHECK: acc.loop
29+
30+
subroutine test_before_acc_combined(a, b, c)
31+
real, dimension(10) :: a,b,c
32+
!dir$ myloop_directive_1
33+
!dir$ myloop_directive_2
34+
!$acc parallel loop
35+
do i=1,N
36+
a(i) = b(i) + c(i)
37+
enddo
38+
end subroutine
39+
! CHECK-LABEL: test_before_acc_combined
40+
! CHECK: acc.parallel combined(loop)
41+
42+
subroutine test_after_acc_combined(a, b, c)
43+
real, dimension(10) :: a,b,c
44+
!$acc parallel loop
45+
!dir$ myloop_directive_1
46+
!dir$ myloop_directive_2
47+
do i=1,N
48+
a(i) = b(i) + c(i)
49+
enddo
50+
end subroutine
51+
! CHECK-LABEL: test_after_acc_combined
52+
! CHECK: acc.parallel combined(loop)
53+
54+
55+
subroutine test_vector_always_after_acc(a, b, c)
56+
real, dimension(10) :: a,b,c
57+
!$acc loop
58+
!dir$ vector always
59+
do i=1,N
60+
a(i) = b(i) + c(i)
61+
enddo
62+
end subroutine
63+
! CHECK-LABEL: test_vector_always_after_acc
64+
! CHECK: acc.loop
65+
66+
subroutine test_vector_always_before_acc(a, b, c)
67+
real, dimension(10) :: a,b,c
68+
!dir$ vector always
69+
!$acc loop
70+
do i=1,N
71+
a(i) = b(i) + c(i)
72+
enddo
73+
end subroutine
74+
! CHECK-LABEL: test_vector_always_before_acc
75+
! CHECK: acc.loop

flang/test/Semantics/loop-directives.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
2+
! RUN: %python %S/test_errors.py %s %flang_fc1 -fopenacc -Werror
23

34
subroutine empty
45
! WARNING: A DO loop must follow the VECTOR ALWAYS directive
@@ -17,3 +18,13 @@ subroutine execution_part
1718
!dir$ vector always
1819
end do
1920
end subroutine execution_part
21+
22+
! OK
23+
subroutine test_vector_always_before_acc(a, b, c)
24+
real, dimension(10) :: a,b,c
25+
!dir$ vector always
26+
!$acc loop
27+
do i=1,N
28+
a(i) = b(i) + c(i)
29+
enddo
30+
end subroutine

0 commit comments

Comments
 (0)