[clang] 923f039 - [OpenACC] Implement 'copy' Clause

via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 11 08:59:25 PST 2024


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 at +2{{expected '('}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy
+
+  // expected-error at +2{{expected '('}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy, seq
+
+  // expected-error at +3{{expected '('}}
+  // expected-error at +2{{expected identifier}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy)
+
+  // expected-error at +3{{expected '('}}
+  // expected-error at +2{{expected identifier}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy), seq
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(, seq
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy()
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(), seq
+
+  struct Members s;
+  struct HasMembersArray HasMem;
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(s.array[s.value]), seq
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(s.array[s.value : 5]), seq
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[3].array[1]), seq
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[3].array[1:4]), seq
+
+  // expected-error at +2{{OpenMP array section is not allowed here}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[1:3].array[1]), seq
+
+  // expected-error at +2{{OpenMP array section is not allowed here}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[1:3].array[1:2]), seq
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[:]), seq
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[::]), seq
+
+  // expected-error at +4{{expected expression}}
+  // expected-error at +3{{expected ']'}}
+  // expected-note at +2{{to match this '['}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[: :]), seq
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial copy(HasMem.MemArr[3:]), seq
+}
+
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc routine worker, vector, seq, nohost
 void bar();


        


More information about the cfe-commits mailing list