Skip to content

Commit 147b38b

Browse files
authored
[OpenACC] Implement enter data/exit data construct parsing (#72916)
These two constructs, 'enter data' and 'exit data', are novel compared to what is currently in the parser, as this is the first set implemented where the first token is itself not a valid construct. Because of this, it requires some additional work to do the first keyword parsing.
1 parent 7ffabb6 commit 147b38b

File tree

4 files changed

+121
-24
lines changed

4 files changed

+121
-24
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,7 @@ def warn_pragma_acc_unimplemented_clause_parsing
13621362
: Warning<"OpenACC clause parsing not yet implemented">,
13631363
InGroup<SourceUsesOpenACC>;
13641364
def err_acc_invalid_directive
1365-
: Error<"invalid OpenACC directive '%0'">;
1365+
: Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">;
13661366
def err_acc_missing_directive : Error<"expected OpenACC directive">;
13671367

13681368
// OpenMP support.

clang/include/clang/Basic/OpenACCKinds.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ enum class OpenACCDirectiveKind {
2424
Serial,
2525
Kernels,
2626

27-
// Data Environment.
27+
// Data Environment. "enter data" and "exit data" are also referred to in the
28+
// Executable Directives section, but just as a back reference to the Data
29+
// Environment.
2830
Data,
29-
// FIXME: 'enter data', 'exit data'.
31+
EnterData,
32+
ExitData,
3033
HostData,
3134

3235
// Misc.

clang/lib/Parse/ParseOpenACC.cpp

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,45 @@ using namespace clang;
2121
using namespace llvm;
2222

2323
namespace {
24-
25-
/// This doesn't completely comprehend 'Compound Constructs' (as it just
26-
/// identifies the first token) just the first token of each. So
27-
/// this should only be used by `ParseOpenACCDirectiveKind`.
28-
OpenACCDirectiveKind getOpenACCDirectiveKind(StringRef Name) {
29-
return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
30-
.Case("parallel", OpenACCDirectiveKind::Parallel)
31-
.Case("serial", OpenACCDirectiveKind::Serial)
32-
.Case("kernels", OpenACCDirectiveKind::Kernels)
33-
.Case("data", OpenACCDirectiveKind::Data)
34-
.Case("host_data", OpenACCDirectiveKind::HostData)
35-
.Case("loop", OpenACCDirectiveKind::Loop)
36-
.Case("declare", OpenACCDirectiveKind::Declare)
37-
.Case("init", OpenACCDirectiveKind::Init)
38-
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
39-
.Case("set", OpenACCDirectiveKind::Shutdown)
40-
.Case("update", OpenACCDirectiveKind::Update)
41-
.Default(OpenACCDirectiveKind::Invalid);
24+
// An enum that contains the extended 'partial' parsed variants. This type
25+
// should never escape the initial parse functionality, but is useful for
26+
// simplifying the implementation.
27+
enum class OpenACCDirectiveKindEx {
28+
Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
29+
// 'enter data' and 'exit data'
30+
Enter,
31+
Exit,
32+
// FIXME: Atomic Variants
33+
};
34+
35+
// Translate single-token string representations to the OpenACC Directive Kind.
36+
// This doesn't completely comprehend 'Compound Constructs' (as it just
37+
// identifies the first token), and doesn't fully handle 'enter data', 'exit
38+
// data', nor any of the 'atomic' variants, just the first token of each. So
39+
// this should only be used by `ParseOpenACCDirectiveKind`.
40+
OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
41+
OpenACCDirectiveKind DirKind =
42+
llvm::StringSwitch<OpenACCDirectiveKind>(Name)
43+
.Case("parallel", OpenACCDirectiveKind::Parallel)
44+
.Case("serial", OpenACCDirectiveKind::Serial)
45+
.Case("kernels", OpenACCDirectiveKind::Kernels)
46+
.Case("data", OpenACCDirectiveKind::Data)
47+
.Case("host_data", OpenACCDirectiveKind::HostData)
48+
.Case("loop", OpenACCDirectiveKind::Loop)
49+
.Case("declare", OpenACCDirectiveKind::Declare)
50+
.Case("init", OpenACCDirectiveKind::Init)
51+
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
52+
.Case("set", OpenACCDirectiveKind::Shutdown)
53+
.Case("update", OpenACCDirectiveKind::Update)
54+
.Default(OpenACCDirectiveKind::Invalid);
55+
56+
if (DirKind != OpenACCDirectiveKind::Invalid)
57+
return static_cast<OpenACCDirectiveKindEx>(DirKind);
58+
59+
return llvm::StringSwitch<OpenACCDirectiveKindEx>(Name)
60+
.Case("enter", OpenACCDirectiveKindEx::Enter)
61+
.Case("exit", OpenACCDirectiveKindEx::Exit)
62+
.Default(OpenACCDirectiveKindEx::Invalid);
4263
}
4364

4465
bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
@@ -59,6 +80,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
5980
case OpenACCDirectiveKind::ParallelLoop:
6081
case OpenACCDirectiveKind::SerialLoop:
6182
case OpenACCDirectiveKind::KernelsLoop:
83+
case OpenACCDirectiveKind::EnterData:
84+
case OpenACCDirectiveKind::ExitData:
6285
return false;
6386

6487
case OpenACCDirectiveKind::Declare:
@@ -77,6 +100,32 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
77100
llvm_unreachable("Unknown 'Kind' Passed");
78101
}
79102

103+
OpenACCDirectiveKind
104+
ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
105+
StringRef FirstTokSpelling,
106+
OpenACCDirectiveKindEx ExtDirKind) {
107+
Token SecondTok = P.getCurToken();
108+
109+
if (SecondTok.isAnnotation()) {
110+
P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling;
111+
return OpenACCDirectiveKind::Invalid;
112+
}
113+
114+
std::string SecondTokSpelling = P.getPreprocessor().getSpelling(SecondTok);
115+
116+
if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTokSpelling)) {
117+
P.Diag(FirstTok, diag::err_acc_invalid_directive)
118+
<< 1 << FirstTokSpelling << SecondTokSpelling;
119+
return OpenACCDirectiveKind::Invalid;
120+
}
121+
122+
P.ConsumeToken();
123+
124+
return ExtDirKind == OpenACCDirectiveKindEx::Enter
125+
? OpenACCDirectiveKind::EnterData
126+
: OpenACCDirectiveKind::ExitData;
127+
}
128+
80129
// Parse and consume the tokens for OpenACC Directive/Construct kinds.
81130
OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
82131
Token FirstTok = P.getCurToken();
@@ -91,10 +140,28 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
91140
P.ConsumeToken();
92141
std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);
93142

94-
OpenACCDirectiveKind DirKind = getOpenACCDirectiveKind(FirstTokSpelling);
143+
OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTokSpelling);
144+
145+
// OpenACCDirectiveKindEx is meant to be an extended list
146+
// over OpenACCDirectiveKind, so any value below Invalid is one of the
147+
// OpenACCDirectiveKind values. This switch takes care of all of the extra
148+
// parsing required for the Extended values. At the end of this block,
149+
// ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
150+
// immediately cast it and use it as that.
151+
if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
152+
switch (ExDirKind) {
153+
case OpenACCDirectiveKindEx::Invalid:
154+
P.Diag(FirstTok, diag::err_acc_invalid_directive)
155+
<< 0 << FirstTokSpelling;
156+
return OpenACCDirectiveKind::Invalid;
157+
case OpenACCDirectiveKindEx::Enter:
158+
case OpenACCDirectiveKindEx::Exit:
159+
return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling,
160+
ExDirKind);
161+
}
162+
}
95163

96-
if (DirKind == OpenACCDirectiveKind::Invalid)
97-
P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
164+
OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
98165

99166
// Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
100167
// other attempt at a combined construct will be diagnosed as an invalid

clang/test/ParserOpenACC/parse-constructs.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,33 @@ void func() {
3434
for(;;){}
3535
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
3636
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
37+
#pragma acc enter data clause list
38+
for(;;){}
39+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
40+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
41+
#pragma acc exit data clause list
42+
for(;;){}
43+
// expected-error@+3{{invalid OpenACC directive 'enter invalid'}}
44+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
45+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
46+
#pragma acc enter invalid
47+
for(;;){}
48+
// expected-error@+3{{invalid OpenACC directive 'exit invalid'}}
49+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
50+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
51+
#pragma acc exit invalid
52+
for(;;){}
53+
// expected-error@+2{{invalid OpenACC directive 'enter'}}
54+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
55+
#pragma acc enter
56+
for(;;){}
57+
// expected-error@+3{{invalid OpenACC directive 'exit }'}}
58+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
59+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
60+
#pragma acc exit }
61+
for(;;){}
62+
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
63+
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
3764
#pragma acc host_data clause list
3865
for(;;){}
3966
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}

0 commit comments

Comments
 (0)