Author: erichkeane Date: 2024-01-11T08:58:07-08:00 New Revision: 923f0392bf050e2e17caa93778e90cf429905694
URL: https://github.com/llvm/llvm-project/commit/923f0392bf050e2e17caa93778e90cf429905694 DIFF: https://github.com/llvm/llvm-project/commit/923f0392bf050e2e17caa93778e90cf429905694.diff LOG: [OpenACC] Implement 'copy' Clause The copy clause takes a var-list, similar to cache. This patch implements the parsing in terms of how we did cache, and does some infrastructure for future clause parsing. As a part of this, many functions needed to become members of Parser, which I anticipated needing to happen in the future anyway. Added: Modified: clang/include/clang/Basic/OpenACCKinds.h clang/include/clang/Parse/Parser.h clang/lib/Parse/ParseOpenACC.cpp clang/test/ParserOpenACC/parse-clauses.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index b0c157e0023600..1e260cfde30b9e 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -98,6 +98,9 @@ enum class OpenACCClauseKind { If, /// 'self' clause, allowed on Compute and Combined Constructs, plus 'update'. Self, + /// 'copy' clause, allowed on Compute and Combined Constructs, plus 'data' and + /// 'declare'. + Copy, /// Represents an invalid clause, for the purposes of parsing. Invalid, }; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 186dbb77085856..e50a4d05b45991 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_PARSE_PARSER_H #define LLVM_CLANG_PARSE_PARSER_H +#include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/Preprocessor.h" @@ -3568,6 +3569,16 @@ class Parser : public CodeCompletionHandler { void ParseOpenACCCacheVarList(); /// Parses a single variable in a variable list for OpenACC. bool ParseOpenACCVar(); + /// Parses the variable list for the variety of clauses that take a var-list, + /// including the optional Special Token listed for some,based on clause type. + bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind); + /// Parses any parameters for an OpenACC Clause, including required/optional + /// parens. + bool ParseOpenACCClauseParams(OpenACCClauseKind Kind); + /// Parses a single clause in a clause-list for OpenACC. + bool ParseOpenACCClause(); + /// Parses the clause-list for an OpenACC directive. + void ParseOpenACCClauseList(); bool ParseOpenACCWaitArgument(); private: diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index fc82324e235d7a..0594a77aa77ac0 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -90,6 +90,7 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { return llvm::StringSwitch<OpenACCClauseKind>( Tok.getIdentifierInfo()->getName()) .Case("auto", OpenACCClauseKind::Auto) + .Case("copy", OpenACCClauseKind::Copy) .Case("default", OpenACCClauseKind::Default) .Case("finalize", OpenACCClauseKind::Finalize) .Case("if", OpenACCClauseKind::If) @@ -334,7 +335,8 @@ bool ClauseHasOptionalParens(OpenACCClauseKind Kind) { } bool ClauseHasRequiredParens(OpenACCClauseKind Kind) { - return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If; + return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If || + Kind == OpenACCClauseKind::Copy; } ExprResult ParseOpenACCConditionalExpr(Parser &P) { @@ -345,8 +347,85 @@ ExprResult ParseOpenACCConditionalExpr(Parser &P) { return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); } -bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { - BalancedDelimiterTracker Parens(P, tok::l_paren, +// Skip until we see the end of pragma token, but don't consume it. This is us +// just giving up on the rest of the pragma so we can continue executing. We +// have to do this because 'SkipUntil' considers paren balancing, which isn't +// what we want. +void SkipUntilEndOfDirective(Parser &P) { + while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) + P.ConsumeAnyToken(); +} + +} // namespace + +// OpenACC 3.3, section 1.7: +// To simplify the specification and convey appropriate constraint information, +// 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() { + bool FirstClause = true; + while (getCurToken().isNot(tok::annot_pragma_openacc_end)) { + // Comma is optional in a clause-list. + if (!FirstClause && getCurToken().is(tok::comma)) + ConsumeToken(); + FirstClause = false; + + // Recovering from a bad clause is really diff icult, so we just give up on + // error. + if (ParseOpenACCClause()) { + SkipUntilEndOfDirective(*this); + return; + } + } +} + +bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) { + // FIXME: Future clauses will require 'special word' parsing, check for one, + // then parse it based on whether it is a clause that requires a 'special + // word'. + (void)Kind; + + // If the var parsing fails, skip until the end of the directive as this is + // an expression and gets messy if we try to continue otherwise. + if (ParseOpenACCVar()) + return true; + + while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { + ExpectAndConsume(tok::comma); + + // If the var parsing fails, skip until the end of the directive as this is + // an expression and gets messy if we try to continue otherwise. + if (ParseOpenACCVar()) + return true; + } + 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/default!) +// token, followed in some cases by either braces or parens. +bool Parser::ParseOpenACCClause() { + // A number of clause names are actually keywords, so accept a keyword that + // can be converted to a name. + if (expectIdentifierOrKeyword(*this)) + return true; + + OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken()); + + if (Kind == OpenACCClauseKind::Invalid) + return Diag(getCurToken(), diag::err_acc_invalid_clause) + << getCurToken().getIdentifierInfo(); + + // Consume the clause name. + ConsumeToken(); + + return ParseOpenACCClauseParams(Kind); +} + +bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) { + BalancedDelimiterTracker Parens(*this, tok::l_paren, tok::annot_pragma_openacc_end); if (ClauseHasRequiredParens(Kind)) { @@ -354,34 +433,38 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { // 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); + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, + Parser::StopBeforeMatch); return false; } switch (Kind) { case OpenACCClauseKind::Default: { - Token DefKindTok = P.getCurToken(); + Token DefKindTok = getCurToken(); - if (expectIdentifierOrKeyword(P)) + if (expectIdentifierOrKeyword(*this)) break; - P.ConsumeToken(); + ConsumeToken(); if (getOpenACCDefaultClauseKind(DefKindTok) == OpenACCDefaultClauseKind::Invalid) - P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); + Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); break; } case OpenACCClauseKind::If: { - ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); // An invalid expression can be just about anything, so just give up on // this clause list. if (CondExpr.isInvalid()) return true; break; } + case OpenACCClauseKind::Copy: + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; default: llvm_unreachable("Not a required parens type?"); } @@ -391,7 +474,7 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { if (!Parens.consumeOpen()) { switch (Kind) { case OpenACCClauseKind::Self: { - ExprResult CondExpr = ParseOpenACCConditionalExpr(P); + ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); // An invalid expression can be just about anything, so just give up on // this clause list. if (CondExpr.isInvalid()) @@ -407,62 +490,6 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { 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/default!) -// token, followed in some cases by either braces or parens. -bool ParseOpenACCClause(Parser &P) { - // A number of clause names are actually keywords, so accept a keyword that - // can be converted to a name. - if (expectIdentifierOrKeyword(P)) - return true; - - OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken()); - - if (Kind == OpenACCClauseKind::Invalid) - return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause) - << P.getCurToken().getIdentifierInfo(); - - // Consume the clause name. - P.ConsumeToken(); - - return ParseOpenACCClauseParams(P, Kind); -} - -// Skip until we see the end of pragma token, but don't consume it. This is us -// just giving up on the rest of the pragma so we can continue executing. We -// have to do this because 'SkipUntil' considers paren balancing, which isn't -// what we want. -void SkipUntilEndOfDirective(Parser &P) { - while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) - P.ConsumeAnyToken(); -} - -// OpenACC 3.3, section 1.7: -// To simplify the specification and convey appropriate constraint information, -// 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 ParseOpenACCClauseList(Parser &P) { - bool FirstClause = true; - while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) { - // Comma is optional in a clause-list. - if (!FirstClause && P.getCurToken().is(tok::comma)) - P.ConsumeToken(); - FirstClause = false; - - // Recovering from a bad clause is really diff icult, so we just give up on - // error. - if (ParseOpenACCClause(P)) { - SkipUntilEndOfDirective(P); - return; - } - } -} - -} // namespace - /// OpenACC 3.3, section 2.16: /// In this section and throughout the specification, the term wait-argument /// means: @@ -664,7 +691,7 @@ void Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present. - ParseOpenACCClauseList(*this); + ParseOpenACCClauseList(); Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); assert(Tok.is(tok::annot_pragma_openacc_end) && diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 11e89d420e6b08..8f2206ff247ec4 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -315,6 +315,91 @@ void SyncClause() { for(;;){} } +struct Members { + int value; + char array[5]; +}; +struct HasMembersArray { + struct Members MemArr[4]; +}; + +void VarListClauses() { + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy + + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy, seq + + // expected-error@+3{{expected '('}} + // expected-error@+2{{expected identifier}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy) + + // expected-error@+3{{expected '('}} + // expected-error@+2{{expected identifier}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy), seq + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy( + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(, seq + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy() + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(), seq + + struct Members s; + struct HasMembersArray HasMem; + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(s.array[s.value]), seq + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(s.array[s.value : 5]), seq + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[3].array[1]), seq + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[3].array[1:4]), seq + + // expected-error@+2{{OpenMP array section is not allowed here}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[1:3].array[1]), seq + + // expected-error@+2{{OpenMP array section is not allowed here}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[1:3].array[1:2]), seq + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[:]), seq + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[::]), seq + + // 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 serial copy(HasMem.MemArr[: :]), seq + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial copy(HasMem.MemArr[3:]), seq +} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc routine worker, vector, seq, nohost void bar(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits