Skip to content

[OpenACC] Implement 'default' clause parsing. #77002

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 5 commits into from
Jan 5, 2024
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: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,8 @@ def err_acc_invalid_clause : Error<"invalid OpenACC clause %0">;
def err_acc_missing_directive : Error<"expected OpenACC directive">;
def err_acc_invalid_open_paren
: Error<"expected clause-list or newline in OpenACC directive">;
def err_acc_invalid_default_clause_kind
: Error<"invalid value for 'default' clause; expected 'present' or 'none'">;

// OpenMP support.
def warn_pragma_omp_ignored : Warning<
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,21 @@ enum class OpenACCClauseKind {
Vector,
/// 'nohost' clause, allowed on 'routine' directives.
NoHost,
/// 'default' clause, allowed on parallel, serial, kernel (and compound)
/// constructs.
Default,
/// Represents an invalid clause, for the purposes of parsing.
Invalid,
};

enum class OpenACCDefaultClauseKind {
/// 'none' option.
None,
/// 'present' option.
Present,
/// Not a valid option.
Invalid,
};
} // namespace clang

#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H
84 changes: 79 additions & 5 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,17 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
if (Tok.is(tok::kw_auto))
return OpenACCClauseKind::Auto;

// default is a keyword, so make sure we parse it correctly.
if (Tok.is(tok::kw_default))
return OpenACCClauseKind::Default;

if (!Tok.is(tok::identifier))
return OpenACCClauseKind::Invalid;

return llvm::StringSwitch<OpenACCClauseKind>(
Tok.getIdentifierInfo()->getName())
.Case("auto", OpenACCClauseKind::Auto)
.Case("default", OpenACCClauseKind::Default)
.Case("finalize", OpenACCClauseKind::Finalize)
.Case("if_present", OpenACCClauseKind::IfPresent)
.Case("independent", OpenACCClauseKind::Independent)
Expand All @@ -106,6 +111,17 @@ OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
.Default(OpenACCAtomicKind::Invalid);
}

OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) {
if (!Tok.is(tok::identifier))
return OpenACCDefaultClauseKind::Invalid;

return llvm::StringSwitch<OpenACCDefaultClauseKind>(
Tok.getIdentifierInfo()->getName())
.Case("none", OpenACCDefaultClauseKind::None)
.Case("present", OpenACCDefaultClauseKind::Present)
.Default(OpenACCDefaultClauseKind::Invalid);
}

enum class OpenACCSpecialTokenKind {
ReadOnly,
DevNum,
Expand Down Expand Up @@ -176,6 +192,22 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
llvm_unreachable("Unknown 'Kind' Passed");
}

/// Used for cases where we expect an identifier-like token, but don't want to
/// give awkward error messages in cases where it is accidentially a keyword.
bool expectIdentifierOrKeyword(Parser &P) {
Token Tok = P.getCurToken();

if (Tok.is(tok::identifier))
return false;

if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
return false;

P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
return true;
}

OpenACCDirectiveKind
ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
OpenACCDirectiveKindEx ExtDirKind) {
Expand Down Expand Up @@ -291,13 +323,56 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
return DirKind;
}

bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
return Kind == OpenACCClauseKind::Default;
}

bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(P, tok::l_paren,
tok::annot_pragma_openacc_end);

if (ClauseHasRequiredParens(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
// clause.
P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
}

switch (Kind) {
case OpenACCClauseKind::Default: {
Token DefKindTok = P.getCurToken();

if (expectIdentifierOrKeyword(P))
break;

P.ConsumeToken();

if (getOpenACCDefaultClauseKind(DefKindTok) ==
OpenACCDefaultClauseKind::Invalid)
P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);

break;
}
default:
llvm_unreachable("Not a required parens type?");
}

return Parens.consumeClose();
}
// FIXME: Handle optional parens
return false;
}

// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto!) token,
// followed in some cases by either braces or parens.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool ParseOpenACCClause(Parser &P) {
if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto))
if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto, tok::kw_default))
return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;

OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());
Expand All @@ -309,8 +384,7 @@ bool ParseOpenACCClause(Parser &P) {
// Consume the clause name.
P.ConsumeToken();

// FIXME: For future clauses, we need to handle parens/etc below.
return false;
return ParseOpenACCClauseParams(P, Kind);
}

// Skip until we see the end of pragma token, but don't consume it. This is us
Expand Down
96 changes: 96 additions & 0 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,102 @@ void func() {
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc loop seq,

}

void DefaultClause() {
// expected-error@+2{{expected '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial loop default
for(;;){}

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

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

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

// expected-error@+4{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default( seq
for(;;){}

// expected-error@+4{{expected identifier}}
// expected-error@+3{{expected ')'}}
// expected-note@+2{{to match this '('}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(, seq
for(;;){}

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

// expected-error@+3{{expected '('}}
// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default) seq
for(;;){}

// expected-error@+3{{expected '('}}
// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default), seq
for(;;){}

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

// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default() seq
for(;;){}

// expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(), seq
for(;;){}

// expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(invalid)
for(;;){}

// expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(auto) seq
for(;;){}

// expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(invalid), seq
for(;;){}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(none)
for(;;){}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
#pragma acc serial default(present), seq
for(;;){}


}

// expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
Expand Down