Skip to content

Commit cac6b1a

Browse files
authored
[OpenACC] Implement 'var' parsing correctly, support array sections (#77617)
While investigating implementing 'var-list' generically for the variety of clauses that support this syntax (an extensive list!) I discovered that it includes 'compound types' and members of compound types, as well as array sections. This patch genericizes that function, and implements it in terms of an assignment expression, and enables a simplified version of OMP Array Sections for it. OpenACC only supports a startidx + length, so this patch implements that parsing. However, it is currently still being represented as an OpenMP Array Section, which is semantically very similar. It is my intent to come back and genericize the OMP Array Sections types (or create a similar expression node) in the future when dealing with Sema. At the moment, the only obvious problem with it is that the diagnostic for using it in the 'wrong' place says OpenMP instead of OpenACC, which I intend to fix when I deal with the AST node changes.
1 parent 1c20932 commit cac6b1a

File tree

6 files changed

+166
-61
lines changed

6 files changed

+166
-61
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,26 @@ class Parser : public CodeCompletionHandler {
234234
/// Parsing OpenACC directive mode.
235235
bool OpenACCDirectiveParsing = false;
236236

237+
/// Currently parsing a situation where an OpenACC array section could be
238+
/// legal, such as a 'var-list'.
239+
bool AllowOpenACCArraySections = false;
240+
241+
/// RAII object to set reset OpenACC parsing a context where Array Sections
242+
/// are allowed.
243+
class OpenACCArraySectionRAII {
244+
Parser &P;
245+
246+
public:
247+
OpenACCArraySectionRAII(Parser &P) : P(P) {
248+
assert(!P.AllowOpenACCArraySections);
249+
P.AllowOpenACCArraySections = true;
250+
}
251+
~OpenACCArraySectionRAII() {
252+
assert(P.AllowOpenACCArraySections);
253+
P.AllowOpenACCArraySections = false;
254+
}
255+
};
256+
237257
/// When true, we are directly inside an Objective-C message
238258
/// send expression.
239259
///
@@ -3546,8 +3566,8 @@ class Parser : public CodeCompletionHandler {
35463566
ExprResult ParseOpenACCIDExpression();
35473567
/// Parses the variable list for the `cache` construct.
35483568
void ParseOpenACCCacheVarList();
3549-
/// Parses a single variable in a variable list for the 'cache' construct.
3550-
bool ParseOpenACCCacheVar();
3569+
/// Parses a single variable in a variable list for OpenACC.
3570+
bool ParseOpenACCVar();
35513571
bool ParseOpenACCWaitArgument();
35523572

35533573
private:

clang/lib/AST/ASTContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,13 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
13181318
InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping);
13191319
InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator);
13201320
}
1321+
// Placeholder type for OpenACC array sections.
1322+
if (LangOpts.OpenACC) {
1323+
// FIXME: Once we implement OpenACC array sections in Sema, this will either
1324+
// be combined with the OpenMP type, or given its own type. In the meantime,
1325+
// just use the OpenMP type so that parsing can work.
1326+
InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection);
1327+
}
13211328
if (LangOpts.MatrixTypes)
13221329
InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx);
13231330

clang/lib/Parse/ParseExpr.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,10 +1974,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
19741974
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
19751975

19761976
// We try to parse a list of indexes in all language mode first
1977-
// and, in we find 0 or one index, we try to parse an OpenMP array
1977+
// and, in we find 0 or one index, we try to parse an OpenMP/OpenACC array
19781978
// section. This allow us to support C++23 multi dimensional subscript and
1979-
// OpenMp sections in the same language mode.
1980-
if (!getLangOpts().OpenMP || Tok.isNot(tok::colon)) {
1979+
// OpenMP/OpenACC sections in the same language mode.
1980+
if ((!getLangOpts().OpenMP && !AllowOpenACCArraySections) ||
1981+
Tok.isNot(tok::colon)) {
19811982
if (!getLangOpts().CPlusPlus23) {
19821983
ExprResult Idx;
19831984
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
@@ -2001,7 +2002,18 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
20012002
}
20022003
}
20032004

2004-
if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
2005+
// Handle OpenACC first, since 'AllowOpenACCArraySections' is only enabled
2006+
// when actively parsing a 'var' in a 'var-list' during clause/'cache'
2007+
// parsing, so it is the most specific, and best allows us to handle
2008+
// OpenACC and OpenMP at the same time.
2009+
if (ArgExprs.size() <= 1 && AllowOpenACCArraySections) {
2010+
ColonProtectionRAIIObject RAII(*this);
2011+
if (Tok.is(tok::colon)) {
2012+
// Consume ':'
2013+
ColonLocFirst = ConsumeToken();
2014+
Length = Actions.CorrectDelayedTyposInExpr(ParseExpression());
2015+
}
2016+
} else if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
20052017
ColonProtectionRAIIObject RAII(*this);
20062018
if (Tok.is(tok::colon)) {
20072019
// Consume ':'
@@ -2031,6 +2043,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
20312043
if (!LHS.isInvalid() && !HasError && !Length.isInvalid() &&
20322044
!Stride.isInvalid() && Tok.is(tok::r_square)) {
20332045
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
2046+
// FIXME: OpenACC hasn't implemented Sema/Array section handling at a
2047+
// semantic level yet. For now, just reuse the OpenMP implementation
2048+
// as it gets the parsing/type management mostly right, and we can
2049+
// replace this call to ActOnOpenACCArraySectionExpr in the future.
2050+
// Eventually we'll genericize the OPenMPArraySectionExpr type as
2051+
// well.
20342052
LHS = Actions.ActOnOMPArraySectionExpr(
20352053
LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0],
20362054
ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc);

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -554,49 +554,17 @@ ExprResult Parser::ParseOpenACCIDExpression() {
554554
return getActions().CorrectDelayedTyposInExpr(Res);
555555
}
556556

557-
/// OpenACC 3.3, section 2.10:
558-
/// A 'var' in a cache directive must be a single array element or a simple
559-
/// subarray. In C and C++, a simple subarray is an array name followed by an
560-
/// extended array range specification in brackets, with a start and length such
561-
/// as:
562-
///
563-
/// arr[lower:length]
564-
///
565-
bool Parser::ParseOpenACCCacheVar() {
566-
ExprResult ArrayName = ParseOpenACCIDExpression();
567-
if (ArrayName.isInvalid())
568-
return true;
569-
570-
// If the expression is invalid, just continue parsing the brackets, there
571-
// is likely other useful diagnostics we can emit inside of those.
572-
573-
BalancedDelimiterTracker SquareBrackets(*this, tok::l_square,
574-
tok::annot_pragma_openacc_end);
575-
576-
// Square brackets are required, so error here, and try to recover by moving
577-
// until the next comma, or the close paren/end of pragma.
578-
if (SquareBrackets.expectAndConsume()) {
579-
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
580-
Parser::StopBeforeMatch);
581-
return true;
582-
}
583-
584-
ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression());
585-
if (Lower.isInvalid())
586-
return true;
587-
588-
// The 'length' expression is optional, as this could be a single array
589-
// element. If there is no colon, we can treat it as that.
590-
if (getCurToken().is(tok::colon)) {
591-
ConsumeToken();
592-
ExprResult Length =
593-
getActions().CorrectDelayedTyposInExpr(ParseExpression());
594-
if (Length.isInvalid())
595-
return true;
596-
}
597-
598-
// Diagnose the square bracket being in the wrong place and continue.
599-
return SquareBrackets.consumeClose();
557+
/// OpenACC 3.3, section 1.6:
558+
/// In this spec, a 'var' (in italics) is one of the following:
559+
/// - a variable name (a scalar, array, or compisite variable name)
560+
/// - a subarray specification with subscript ranges
561+
/// - an array element
562+
/// - a member of a composite variable
563+
/// - a common block name between slashes (fortran only)
564+
bool Parser::ParseOpenACCVar() {
565+
OpenACCArraySectionRAII ArraySections(*this);
566+
ExprResult Res = ParseAssignmentExpression();
567+
return Res.isInvalid();
600568
}
601569

602570
/// OpenACC 3.3, section 2.10:
@@ -627,7 +595,16 @@ void Parser::ParseOpenACCCacheVarList() {
627595
if (!FirstArray)
628596
ExpectAndConsume(tok::comma);
629597
FirstArray = false;
630-
if (ParseOpenACCCacheVar())
598+
599+
// OpenACC 3.3, section 2.10:
600+
// A 'var' in a cache directive must be a single array element or a simple
601+
// subarray. In C and C++, a simple subarray is an array name followed by
602+
// an extended array range specification in brackets, with a start and
603+
// length such as:
604+
//
605+
// arr[lower:length]
606+
//
607+
if (ParseOpenACCVar())
631608
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
632609
StopBeforeMatch);
633610
}

clang/test/ParserOpenACC/parse-cache-construct.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
// RUN: %clang_cc1 %s -verify -fopenacc
22

3+
struct S {
4+
int foo;
5+
char Array[1];
6+
};
37
char *getArrayPtr();
48
void func() {
59
char Array[10];
610
char *ArrayPtr = getArrayPtr();
711
int *readonly;
12+
struct S s;
813

914
for (int i = 0; i < 10; ++i) {
1015
// expected-error@+2{{expected '('}}
@@ -46,7 +51,6 @@ void func() {
4651
}
4752

4853
for (int i = 0; i < 10; ++i) {
49-
// expected-error@+4{{expected '['}}
5054
// expected-error@+3{{expected ')'}}
5155
// expected-note@+2{{to match this '('}}
5256
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
@@ -60,27 +64,32 @@ void func() {
6064
}
6165

6266
for (int i = 0; i < 10; ++i) {
63-
// expected-error@+2{{expected '['}}
6467
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
6568
#pragma acc cache(ArrayPtr)
6669
}
6770

6871
for (int i = 0; i < 10; ++i) {
69-
// expected-error@+4{{expected expression}}
72+
// expected-error@+6{{expected expression}}
73+
// expected-error@+5{{expected ']'}}
74+
// expected-note@+4{{to match this '['}}
7075
// expected-error@+3{{expected ')'}}
7176
// expected-note@+2{{to match this '('}}
7277
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
7378
#pragma acc cache(ArrayPtr[
7479
}
7580

7681
for (int i = 0; i < 10; ++i) {
77-
// expected-error@+2{{expected expression}}
82+
// expected-error@+4{{expected expression}}
83+
// expected-error@+3{{expected ']'}}
84+
// expected-note@+2{{to match this '['}}
7885
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
7986
#pragma acc cache(ArrayPtr[, 5)
8087
}
8188

8289
for (int i = 0; i < 10; ++i) {
83-
// expected-error@+2{{expected expression}}
90+
// expected-error@+4{{expected expression}}
91+
// expected-error@+3{{expected ']'}}
92+
// expected-note@+2{{to match this '['}}
8493
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
8594
#pragma acc cache(Array[)
8695
}
@@ -91,21 +100,21 @@ void func() {
91100
}
92101

93102
for (int i = 0; i < 10; ++i) {
94-
// expected-error@+4{{expected expression}}
103+
// expected-error@+6{{expected expression}}
104+
// expected-error@+5{{expected ']'}}
105+
// expected-note@+4{{to match this '['}}
95106
// expected-error@+3{{expected ')'}}
96107
// expected-note@+2{{to match this '('}}
97108
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
98109
#pragma acc cache(Array[*readonly:
99110
}
100111

101112
for (int i = 0; i < 10; ++i) {
102-
// expected-error@+2{{expected '['}}
103113
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
104114
#pragma acc cache(readonly)
105115
}
106116

107117
for (int i = 0; i < 10; ++i) {
108-
// expected-error@+2{{expected '['}}
109118
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
110119
#pragma acc cache(readonly:ArrayPtr)
111120
}
@@ -122,7 +131,6 @@ void func() {
122131
}
123132

124133
for (int i = 0; i < 10; ++i) {
125-
// expected-error@+2{{expected '['}}
126134
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
127135
#pragma acc cache(readonly:ArrayPtr[5:*readonly], Array)
128136
}
@@ -138,15 +146,15 @@ void func() {
138146
}
139147

140148
for (int i = 0; i < 10; ++i) {
141-
// expected-error@+4{{expected identifier}}
149+
// expected-error@+4{{expected expression}}
142150
// expected-error@+3{{expected ')'}}
143151
// expected-note@+2{{to match this '('}}
144152
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
145153
#pragma acc cache(readonly:ArrayPtr[5:*readonly],
146154
}
147155

148156
for (int i = 0; i < 10; ++i) {
149-
// expected-error@+2{{expected identifier}}
157+
// expected-error@+2{{expected expression}}
150158
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
151159
#pragma acc cache(readonly:ArrayPtr[5:*readonly],)
152160
}
@@ -163,4 +171,14 @@ void func() {
163171
#pragma acc cache(readonly:ArrayPtr[5:3, *readonly], ArrayPtr[0])
164172
}
165173

174+
for (int i = 0; i < 10; ++i) {
175+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
176+
#pragma acc cache(readonly:s.foo)
177+
}
178+
179+
for (int i = 0; i < 10; ++i) {
180+
// expected-warning@+2{{left operand of comma operator has no effect}}
181+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
182+
#pragma acc cache(readonly:s.Array[1,2])
183+
}
166184
}

clang/test/ParserOpenACC/parse-cache-construct.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,71 @@ struct S {
4646
static constexpr char array[] ={1,2,3,4,5};
4747
};
4848

49+
struct Members {
50+
int value = 5;
51+
char array[5] ={1,2,3,4,5};
52+
};
53+
struct HasMembersArray {
54+
Members MemArr[4];
55+
};
56+
57+
4958
void use() {
59+
60+
Members s;
61+
for (int i = 0; i < 10; ++i) {
62+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
63+
#pragma acc cache(s.array[s.value])
64+
}
65+
HasMembersArray Arrs;
66+
for (int i = 0; i < 10; ++i) {
67+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
68+
#pragma acc cache(Arrs.MemArr[3].array[4])
69+
}
70+
for (int i = 0; i < 10; ++i) {
71+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
72+
#pragma acc cache(Arrs.MemArr[3].array[1:4])
73+
}
74+
for (int i = 0; i < 10; ++i) {
75+
// FIXME: Once we have a new array-section type to represent OpenACC as
76+
// well, change this error message.
77+
// expected-error@+2{{OpenMP array section is not allowed here}}
78+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
79+
#pragma acc cache(Arrs.MemArr[3:4].array[1:4])
80+
}
81+
for (int i = 0; i < 10; ++i) {
82+
// expected-error@+2{{OpenMP array section is not allowed here}}
83+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
84+
#pragma acc cache(Arrs.MemArr[3:4].array[4])
85+
}
86+
for (int i = 0; i < 10; ++i) {
87+
// expected-error@+3{{expected ']'}}
88+
// expected-note@+2{{to match this '['}}
89+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
90+
#pragma acc cache(Arrs.MemArr[3:4:].array[4])
91+
}
92+
for (int i = 0; i < 10; ++i) {
93+
// expected-error@+2{{expected expression}}
94+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
95+
#pragma acc cache(Arrs.MemArr[:].array[4])
96+
}
97+
for (int i = 0; i < 10; ++i) {
98+
// expected-error@+2{{expected unqualified-id}}
99+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
100+
#pragma acc cache(Arrs.MemArr[::].array[4])
101+
}
102+
for (int i = 0; i < 10; ++i) {
103+
// expected-error@+4{{expected expression}}
104+
// expected-error@+3{{expected ']'}}
105+
// expected-note@+2{{to match this '['}}
106+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
107+
#pragma acc cache(Arrs.MemArr[: :].array[4])
108+
}
109+
for (int i = 0; i < 10; ++i) {
110+
// expected-error@+2{{expected expression}}
111+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
112+
#pragma acc cache(Arrs.MemArr[3:].array[4])
113+
}
50114
func<S, 5>();
51115
}
116+

0 commit comments

Comments
 (0)