Skip to content

Commit

Permalink
[OpenACC] Implement 'wait' construct parsing (#74752)
Browse files Browse the repository at this point in the history
The 'wait' construct comes in two forms: one with no parens, the second
with a 'wait-argument'. This implements both forms for constructs.

Additionally, the 'wait-argument' parsing is split into its own function
because the 'wait clause' can also take the same 'wait-argument'.
  • Loading branch information
erichkeane committed Dec 8, 2023
1 parent 2cd43e9 commit df3db03
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 1 deletion.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum class OpenACCDirectiveKind {
Shutdown,
Set,
Update,
// FIXME: wait construct.
Wait,

// Procedure Calls in Compute Regions.
Routine,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3544,6 +3544,7 @@ class Parser : public CodeCompletionHandler {
void ParseOpenACCCacheVarList();
/// Parses a single variable in a variable list for the 'cache' construct.
bool ParseOpenACCCacheVar();
bool ParseOpenACCWaitArgument();

private:
//===--------------------------------------------------------------------===//
Expand Down
89 changes: 89 additions & 0 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
.Case("set", OpenACCDirectiveKind::Shutdown)
.Case("update", OpenACCDirectiveKind::Update)
.Case("wait", OpenACCDirectiveKind::Wait)
.Default(OpenACCDirectiveKind::Invalid);

if (DirKind != OpenACCDirectiveKind::Invalid)
Expand All @@ -82,6 +83,24 @@ OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
.Default(OpenACCAtomicKind::Invalid);
}

enum class OpenACCSpecialTokenKind {
DevNum,
Queues,
};

bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
if (!Tok.is(tok::identifier))
return false;

switch (Kind) {
case OpenACCSpecialTokenKind::DevNum:
return Tok.getIdentifierInfo()->isStr("devnum");
case OpenACCSpecialTokenKind::Queues:
return Tok.getIdentifierInfo()->isStr("queues");
}
llvm_unreachable("Unknown 'Kind' Passed");
}

bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
if (!Tok.is(tok::identifier))
return false;
Expand Down Expand Up @@ -123,6 +142,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
return Tok.getIdentifierInfo()->isStr("set");
case OpenACCDirectiveKind::Update:
return Tok.getIdentifierInfo()->isStr("update");
case OpenACCDirectiveKind::Wait:
return Tok.getIdentifierInfo()->isStr("wait");
case OpenACCDirectiveKind::Invalid:
return false;
}
Expand Down Expand Up @@ -251,6 +272,67 @@ void ParseOpenACCClauseList(Parser &P) {

} // namespace

/// OpenACC 3.3, section 2.16:
/// In this section and throughout the specification, the term wait-argument
/// means:
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
bool Parser::ParseOpenACCWaitArgument() {
// [devnum : int-expr : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
NextToken().is(tok::colon)) {
// Consume devnum.
ConsumeToken();
// Consume colon.
ConsumeToken();

ExprResult IntExpr =
getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (IntExpr.isInvalid())
return true;

if (ExpectAndConsume(tok::colon))
return true;
}

// [ queues : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
NextToken().is(tok::colon)) {
// Consume queues.
ConsumeToken();
// Consume colon.
ConsumeToken();
}

// OpenACC 3.3, section 2.16:
// the term 'async-argument' means a nonnegative scalar integer expression, or
// one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
// in the C header file and the Fortran opacc module.
//
// We are parsing this simply as list of assignment expressions (to avoid
// comma being troublesome), and will ensure it is an integral type. The
// 'special' types are defined as macros, so we can't really check those
// (other than perhaps as values at one point?), but the standard does say it
// is implementation-defined to use any other negative value.
//
//
bool FirstArg = true;
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
if (!FirstArg) {
if (ExpectAndConsume(tok::comma))
return true;
}
FirstArg = false;

ExprResult CurArg =
getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());

if (CurArg.isInvalid())
return true;
}

return false;
}

ExprResult Parser::ParseOpenACCIDExpression() {
ExprResult Res;
if (getLangOpts().CPlusPlus) {
Expand Down Expand Up @@ -399,6 +481,13 @@ void Parser::ParseOpenACCDirective() {
// so we can always consume the close.
T.consumeClose();
break;
case OpenACCDirectiveKind::Wait:
// OpenACC has an optional paren-wrapped 'wait-argument'.
if (ParseOpenACCWaitArgument())
T.skipToEnd();
else
T.consumeClose();
break;
}
} else if (DirKind == OpenACCDirectiveKind::Cache) {
// Cache's paren var-list is required, so error here if it isn't provided.
Expand Down
157 changes: 157 additions & 0 deletions clang/test/ParserOpenACC/parse-wait-construct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// RUN: %clang_cc1 %s -verify -fopenacc

void func() {
int i, j;

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait ()

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait () clause-list

// expected-error@+4{{expected expression}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum:

// expected-error@+2{{expected expression}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum:)

// expected-error@+3{{expected expression}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum:) clause-list

// expected-error@+4{{expected ':'}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j

// expected-error@+2{{expected ':'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j)

// expected-error@+3{{expected ':'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:)

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j:queues:

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j:queues:)

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (devnum: i + j:queues:) clause-list

// expected-error@+4{{use of undeclared identifier 'devnum'}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:devnum: i + j

// expected-error@+2{{use of undeclared identifier 'devnum'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:devnum: i + j)

// expected-error@+3{{use of undeclared identifier 'devnum'}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait (queues:devnum: i + j) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(i, j, 1+1, 3.3

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(i, j, 1+1, 3.3)
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(i, j, 1+1, 3.3) clause-list

// expected-error@+4{{expected expression}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(,

// expected-error@+2{{expected expression}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(,)

// expected-error@+3{{expected expression}}
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(,) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(queues:i, j, 1+1, 3.3

// expected-error@+4{{expected expression}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(queues:i, j, 1+1, 3.3,

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(queues:i, j, 1+1, 3.3)

// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(queues:i, j, 1+1, 3.3) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:i, j, 1+1, 3.3
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:i, j, 1+1, 3.3)
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list

// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3)
// expected-warning@+2{{OpenACC clause parsing not yet implemented}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
}

0 comments on commit df3db03

Please sign in to comment.