Skip to content

[OpenACC] Implement enter data/exit data construct parsing #72916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1362,7 +1362,7 @@ def warn_pragma_acc_unimplemented_clause_parsing
: Warning<"OpenACC clause parsing not yet implemented">,
InGroup<SourceUsesOpenACC>;
def err_acc_invalid_directive
: Error<"invalid OpenACC directive '%0'">;
: Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">;
def err_acc_missing_directive : Error<"expected OpenACC directive">;

// OpenMP support.
Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ enum class OpenACCDirectiveKind {
Serial,
Kernels,

// Data Environment.
// Data Environment. "enter data" and "exit data" are also referred to in the
// Executable Directives section, but just as a back reference to the Data
// Environment.
Data,
// FIXME: 'enter data', 'exit data'.
EnterData,
ExitData,
HostData,

// Misc.
Expand Down
109 changes: 88 additions & 21 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,45 @@ using namespace clang;
using namespace llvm;

namespace {

/// This doesn't completely comprehend 'Compound Constructs' (as it just
/// identifies the first token) just the first token of each. So
/// this should only be used by `ParseOpenACCDirectiveKind`.
OpenACCDirectiveKind getOpenACCDirectiveKind(StringRef Name) {
return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
.Case("parallel", OpenACCDirectiveKind::Parallel)
.Case("serial", OpenACCDirectiveKind::Serial)
.Case("kernels", OpenACCDirectiveKind::Kernels)
.Case("data", OpenACCDirectiveKind::Data)
.Case("host_data", OpenACCDirectiveKind::HostData)
.Case("loop", OpenACCDirectiveKind::Loop)
.Case("declare", OpenACCDirectiveKind::Declare)
.Case("init", OpenACCDirectiveKind::Init)
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
.Case("set", OpenACCDirectiveKind::Shutdown)
.Case("update", OpenACCDirectiveKind::Update)
.Default(OpenACCDirectiveKind::Invalid);
// An enum that contains the extended 'partial' parsed variants. This type
// should never escape the initial parse functionality, but is useful for
// simplifying the implementation.
enum class OpenACCDirectiveKindEx {
Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
// 'enter data' and 'exit data'
Enter,
Exit,
// FIXME: Atomic Variants
};

// Translate single-token string representations to the OpenACC Directive Kind.
// This doesn't completely comprehend 'Compound Constructs' (as it just
// identifies the first token), and doesn't fully handle 'enter data', 'exit
// data', nor any of the 'atomic' variants, just the first token of each. So
// this should only be used by `ParseOpenACCDirectiveKind`.
OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
OpenACCDirectiveKind DirKind =
llvm::StringSwitch<OpenACCDirectiveKind>(Name)
.Case("parallel", OpenACCDirectiveKind::Parallel)
.Case("serial", OpenACCDirectiveKind::Serial)
.Case("kernels", OpenACCDirectiveKind::Kernels)
.Case("data", OpenACCDirectiveKind::Data)
.Case("host_data", OpenACCDirectiveKind::HostData)
.Case("loop", OpenACCDirectiveKind::Loop)
.Case("declare", OpenACCDirectiveKind::Declare)
.Case("init", OpenACCDirectiveKind::Init)
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
.Case("set", OpenACCDirectiveKind::Shutdown)
.Case("update", OpenACCDirectiveKind::Update)
.Default(OpenACCDirectiveKind::Invalid);

if (DirKind != OpenACCDirectiveKind::Invalid)
return static_cast<OpenACCDirectiveKindEx>(DirKind);

return llvm::StringSwitch<OpenACCDirectiveKindEx>(Name)
.Case("enter", OpenACCDirectiveKindEx::Enter)
.Case("exit", OpenACCDirectiveKindEx::Exit)
.Default(OpenACCDirectiveKindEx::Invalid);
}

bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
Expand All @@ -59,6 +80,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
case OpenACCDirectiveKind::EnterData:
case OpenACCDirectiveKind::ExitData:
return false;

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

OpenACCDirectiveKind
ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
StringRef FirstTokSpelling,
OpenACCDirectiveKindEx ExtDirKind) {
Token SecondTok = P.getCurToken();

if (SecondTok.isAnnotation()) {
P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling;
return OpenACCDirectiveKind::Invalid;
}

std::string SecondTokSpelling = P.getPreprocessor().getSpelling(SecondTok);

if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTokSpelling)) {
P.Diag(FirstTok, diag::err_acc_invalid_directive)
<< 1 << FirstTokSpelling << SecondTokSpelling;
return OpenACCDirectiveKind::Invalid;
}

P.ConsumeToken();

return ExtDirKind == OpenACCDirectiveKindEx::Enter
? OpenACCDirectiveKind::EnterData
: OpenACCDirectiveKind::ExitData;
}

// Parse and consume the tokens for OpenACC Directive/Construct kinds.
OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
Token FirstTok = P.getCurToken();
Expand All @@ -91,10 +140,28 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
P.ConsumeToken();
std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);

OpenACCDirectiveKind DirKind = getOpenACCDirectiveKind(FirstTokSpelling);
OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTokSpelling);

// OpenACCDirectiveKindEx is meant to be an extended list
// over OpenACCDirectiveKind, so any value below Invalid is one of the
// OpenACCDirectiveKind values. This switch takes care of all of the extra
// parsing required for the Extended values. At the end of this block,
// ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
// immediately cast it and use it as that.
if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
switch (ExDirKind) {
case OpenACCDirectiveKindEx::Invalid:
P.Diag(FirstTok, diag::err_acc_invalid_directive)
<< 0 << FirstTokSpelling;
return OpenACCDirectiveKind::Invalid;
case OpenACCDirectiveKindEx::Enter:
case OpenACCDirectiveKindEx::Exit:
return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling,
ExDirKind);
}
}

if (DirKind == OpenACCDirectiveKind::Invalid)
P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);

// Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
// other attempt at a combined construct will be diagnosed as an invalid
Expand Down
27 changes: 27 additions & 0 deletions clang/test/ParserOpenACC/parse-constructs.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ void func() {
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc enter data clause list
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc exit data clause list
for(;;){}
// expected-error@+3{{invalid OpenACC directive 'enter invalid'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc enter invalid
for(;;){}
// expected-error@+3{{invalid OpenACC directive 'exit invalid'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc exit invalid
for(;;){}
// expected-error@+2{{invalid OpenACC directive 'enter'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc enter
for(;;){}
// expected-error@+3{{invalid OpenACC directive 'exit }'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc exit }
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc host_data clause list
for(;;){}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
Expand Down