https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/77002
>From d9f62a6d6b5a66a2e425f5c33f18c4a13c8b88ca Mon Sep 17 00:00:00 2001 From: erichkeane <eke...@nvidia.com> Date: Thu, 4 Jan 2024 12:19:00 -0800 Subject: [PATCH 1/3] [OpenACC] Implement 'default' clause parsing. A simple clause that is permitted on a few different constructs, 'default' takes a required parameter of either 'none' or 'present'. This patch implements parsing for it. --- .../clang/Basic/DiagnosticParseKinds.td | 2 + clang/include/clang/Basic/OpenACCKinds.h | 12 +++ clang/lib/Parse/ParseOpenACC.cpp | 75 ++++++++++++++- clang/test/ParserOpenACC/parse-clauses.c | 96 +++++++++++++++++++ 4 files changed, 180 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e4b1069cde1850..088f8b74983c86 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 3117d584d347b9..e507afe46a6540 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -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 diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 67325f0a286a99..27e6c29b546485 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -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) @@ -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, @@ -291,13 +307,63 @@ 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(); + // 'default' accepts 'present' or 'none'. Be a little liberal here to + // allow things like 'auto' or 'default'. + // TODO ERICH: Make 'keyword like tokens' via tok::getKeywordSpelling' + // or 'getIdentifierInfo' isKeyword + if (!DefKindTok.is(tok::identifier) && + (DefKindTok.isAnnotation() || !DefKindTok.getIdentifierInfo() || + !DefKindTok.getIdentifierInfo()->isKeyword(P.getLangOpts()))) { + P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + 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()); @@ -309,8 +375,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 diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 1e05d82906aedc..aedf0c711ad15b 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -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}} >From 467f18d5d9f40152837f8a7d3e6a05c0f0b6be81 Mon Sep 17 00:00:00 2001 From: erichkeane <eke...@nvidia.com> Date: Fri, 5 Jan 2024 06:06:09 -0800 Subject: [PATCH 2/3] change to /// comments --- clang/include/clang/Basic/OpenACCKinds.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index e507afe46a6540..cc03247db67745 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -98,11 +98,11 @@ enum class OpenACCClauseKind { }; enum class OpenACCDefaultClauseKind { - // 'none' option. + /// 'none' option. None, - // 'present' option. + /// 'present' option. Present, - // Not a valid option. + /// Not a valid option. Invalid, }; } // namespace clang >From 0dc823adb513d1dd3331140bbfe3cba98e6e0fe7 Mon Sep 17 00:00:00 2001 From: erichkeane <eke...@nvidia.com> Date: Fri, 5 Jan 2024 06:47:13 -0800 Subject: [PATCH 3/3] Extract identifier or kw function --- clang/lib/Parse/ParseOpenACC.cpp | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 27e6c29b546485..8677bb04caf21b 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -192,6 +192,26 @@ 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)) { + P.ConsumeToken(); + return false; + } + + if (!Tok.isAnnotation() && Tok.getIdentifierInfo() && + Tok.getIdentifierInfo()->isKeyword(P.getLangOpts())) { + P.ConsumeToken(); + return false; + } + + P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + return true; +} + OpenACCDirectiveKind ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, OpenACCDirectiveKindEx ExtDirKind) { @@ -328,18 +348,9 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { switch (Kind) { case OpenACCClauseKind::Default: { Token DefKindTok = P.getCurToken(); - // 'default' accepts 'present' or 'none'. Be a little liberal here to - // allow things like 'auto' or 'default'. - // TODO ERICH: Make 'keyword like tokens' via tok::getKeywordSpelling' - // or 'getIdentifierInfo' isKeyword - if (!DefKindTok.is(tok::identifier) && - (DefKindTok.isAnnotation() || !DefKindTok.getIdentifierInfo() || - !DefKindTok.getIdentifierInfo()->isKeyword(P.getLangOpts()))) { - P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; - break; - } - P.ConsumeToken(); + if (expectIdentifierOrKeyword(P)) + break; if (getOpenACCDefaultClauseKind(DefKindTok) == OpenACCDefaultClauseKind::Invalid) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits