Skip to content

Commit

Permalink
[OpenACC] Implement 'self' clause parsing on 'update'.
Browse files Browse the repository at this point in the history
The update directive has its own version of 'self' that has a 'var-list'
instead of a 'condition' (like the serial/parallel/kernel/combined
constructs).  This patch special cases it on 'update' to make sure we
parse this correctly.
  • Loading branch information
erichkeane committed Jan 16, 2024
1 parent d6ee91b commit 9c4e7a1
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 17 deletions.
7 changes: 4 additions & 3 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3574,11 +3574,12 @@ class Parser : public CodeCompletionHandler {
bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind);
/// Parses any parameters for an OpenACC Clause, including required/optional
/// parens.
bool ParseOpenACCClauseParams(OpenACCClauseKind Kind);
bool ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind,
OpenACCClauseKind Kind);
/// Parses a single clause in a clause-list for OpenACC.
bool ParseOpenACCClause();
bool ParseOpenACCClause(OpenACCDirectiveKind DirKind);
/// Parses the clause-list for an OpenACC directive.
void ParseOpenACCClauseList();
void ParseOpenACCClauseList(OpenACCDirectiveKind DirKind);
bool ParseOpenACCWaitArgument();

private:
Expand Down
40 changes: 26 additions & 14 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,12 @@ enum ClauseParensKind {
Required
};

ClauseParensKind getClauseParensKind(OpenACCClauseKind Kind) {
ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind,
OpenACCClauseKind Kind) {
switch (Kind) {
case OpenACCClauseKind::Self:
return ClauseParensKind::Optional;
return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required
: ClauseParensKind::Optional;

case OpenACCClauseKind::Default:
case OpenACCClauseKind::If:
Expand Down Expand Up @@ -433,12 +435,14 @@ ClauseParensKind getClauseParensKind(OpenACCClauseKind Kind) {
llvm_unreachable("Unhandled clause kind");
}

bool ClauseHasOptionalParens(OpenACCClauseKind Kind) {
return getClauseParensKind(Kind) == ClauseParensKind::Optional;
bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind,
OpenACCClauseKind Kind) {
return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;
}

bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
return getClauseParensKind(Kind) == ClauseParensKind::Required;
bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind,
OpenACCClauseKind Kind) {
return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;
}

ExprResult ParseOpenACCConditionalExpr(Parser &P) {
Expand All @@ -465,7 +469,7 @@ void SkipUntilEndOfDirective(Parser &P) {
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void Parser::ParseOpenACCClauseList() {
void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
bool FirstClause = true;
while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
Expand All @@ -475,7 +479,7 @@ void Parser::ParseOpenACCClauseList() {

// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause()) {
if (ParseOpenACCClause(DirKind)) {
SkipUntilEndOfDirective(*this);
return;
}
Expand Down Expand Up @@ -508,7 +512,7 @@ bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool Parser::ParseOpenACCClause() {
bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) {
// A number of clause names are actually keywords, so accept a keyword that
// can be converted to a name.
if (expectIdentifierOrKeyword(*this))
Expand All @@ -523,14 +527,15 @@ bool Parser::ParseOpenACCClause() {
// Consume the clause name.
ConsumeToken();

return ParseOpenACCClauseParams(Kind);
return ParseOpenACCClauseParams(DirKind, Kind);
}

bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind,
OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(*this, tok::l_paren,
tok::annot_pragma_openacc_end);

if (ClauseHasRequiredParens(Kind)) {
if (ClauseHasRequiredParens(DirKind, Kind)) {
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
Expand Down Expand Up @@ -576,6 +581,12 @@ bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
if (ParseOpenACCClauseVarList(Kind))
return true;
break;
case OpenACCClauseKind::Self:
// The 'self' clause is a var-list instead of a 'condition' in the case of
// the 'update' clause, so we have to handle it here. U se an assert to
// make sure we get the right differentiator.
assert(DirKind == OpenACCDirectiveKind::Update);
LLVM_FALLTHROUGH;
case OpenACCClauseKind::Attach:
case OpenACCClauseKind::Copy:
case OpenACCClauseKind::Delete:
Expand All @@ -598,10 +609,11 @@ bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
}

return Parens.consumeClose();
} else if (ClauseHasOptionalParens(Kind)) {
} else if (ClauseHasOptionalParens(DirKind, Kind)) {
if (!Parens.consumeOpen()) {
switch (Kind) {
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.
Expand Down Expand Up @@ -817,7 +829,7 @@ void Parser::ParseOpenACCDirective() {
}

// Parses the list of clauses, if present.
ParseOpenACCClauseList();
ParseOpenACCClauseList(DirKind);

Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
assert(Tok.is(tok::annot_pragma_openacc_end) &&
Expand Down
24 changes: 24 additions & 0 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,11 @@ void SyncClause() {
#pragma acc serial self(i > j, seq
for(;;){}

// expected-warning@+2{{left operand of comma operator has no effect}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial self(i, j)
for(;;){}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial self(i > j)
for(;;){}
Expand All @@ -323,6 +328,25 @@ struct HasMembersArray {
struct Members MemArr[4];
};

// On 'update', self behaves differently and requires parens, plus takes a var-list instead.
void SelfUpdate() {
struct Members s;

// expected-error@+2{{expected '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc update self
for(;;){}

// expected-error@+2{{use of undeclared identifier 'zero'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc update self(zero : s.array[s.value : 5], s.value), seq
for(;;){}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc update self(s.array[s.value : 5], s.value), seq
for(;;){}
}

void VarListClauses() {
// expected-error@+2{{expected '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
Expand Down

0 comments on commit 9c4e7a1

Please sign in to comment.