[Lldb-commits] [lld] [libc] [lldb] [compiler-rt] [flang] [clang] [llvm] [clang-tools-extra] [libcxx] [OpenACC] Implement 'default' clause parsing. (PR #77002)

Erich Keane via lldb-commits lldb-commits at lists.llvm.org
Fri Jan 5 07:56:06 PST 2024


https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/77002

>From d9f62a6d6b5a66a2e425f5c33f18c4a13c8b88ca Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 4 Jan 2024 12:19:00 -0800
Subject: [PATCH 1/4] [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 at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc loop seq,
 
+}
+
+void DefaultClause() {
+  // expected-error at +2{{expected '('}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial loop default
+  for(;;){}
+
+  // expected-error at +2{{expected '('}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default seq
+  for(;;){}
+
+  // expected-error at +2{{expected '('}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default, seq
+  for(;;){}
+
+  // expected-error at +4{{expected identifier}}
+  // 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 default(
+  for(;;){}
+
+  // expected-error at +4{{invalid value for 'default' clause; expected 'present' or 'none'}}
+  // 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 default( seq
+  for(;;){}
+
+  // expected-error at +4{{expected identifier}}
+  // 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 default(, seq
+  for(;;){}
+
+  // 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 default)
+  for(;;){}
+
+  // 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 default) seq
+  for(;;){}
+
+  // 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 default), seq
+  for(;;){}
+
+  // expected-error at +2{{expected identifier}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default()
+  for(;;){}
+
+  // expected-error at +2{{expected identifier}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default() seq
+  for(;;){}
+
+  // expected-error at +2{{expected identifier}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(), seq
+  for(;;){}
+
+  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(invalid)
+  for(;;){}
+
+  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(auto) seq
+  for(;;){}
+
+  // expected-error at +2{{invalid value for 'default' clause; expected 'present' or 'none'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(invalid), seq
+  for(;;){}
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(none)
+  for(;;){}
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial default(present), seq
+  for(;;){}
+
+
 }
 
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}

>From 467f18d5d9f40152837f8a7d3e6a05c0f0b6be81 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 5 Jan 2024 06:06:09 -0800
Subject: [PATCH 2/4] 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 <ekeane at nvidia.com>
Date: Fri, 5 Jan 2024 06:47:13 -0800
Subject: [PATCH 3/4] 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)

>From 35956eaed399efadc03625fed06fe6e0de8ab3b5 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 5 Jan 2024 07:50:19 -0800
Subject: [PATCH 4/4] Change behavior of expect function to no longer consume

---
 clang/lib/Parse/ParseOpenACC.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 8677bb04caf21b..94c3d0c4e164cd 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -197,16 +197,12 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
 bool expectIdentifierOrKeyword(Parser &P) {
   Token Tok = P.getCurToken();
 
-  if (Tok.is(tok::identifier)) {
-    P.ConsumeToken();
+  if (Tok.is(tok::identifier))
     return false;
-  }
 
   if (!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
-      Tok.getIdentifierInfo()->isKeyword(P.getLangOpts())) {
-    P.ConsumeToken();
+      Tok.getIdentifierInfo()->isKeyword(P.getLangOpts()))
     return false;
-  }
 
   P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
   return true;
@@ -352,6 +348,8 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
       if (expectIdentifierOrKeyword(P))
         break;
 
+      P.ConsumeToken();
+
       if (getOpenACCDefaultClauseKind(DefKindTok) ==
           OpenACCDefaultClauseKind::Invalid)
         P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);



More information about the lldb-commits mailing list