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

Conversation

erichkeane
Copy link
Collaborator

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.

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.
@erichkeane erichkeane added the clang:openacc Clang OpenACC Implementation label Jan 4, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 4, 2024

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/77002.diff

4 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+2)
  • (modified) clang/include/clang/Basic/OpenACCKinds.h (+12)
  • (modified) clang/lib/Parse/ParseOpenACC.cpp (+70-5)
  • (modified) clang/test/ParserOpenACC/parse-clauses.c (+96)
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}}

Copy link
Member

@alexey-bataev alexey-bataev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@erichkeane erichkeane merged commit 0e8b09c into llvm:main Jan 5, 2024
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openacc Clang OpenACC Implementation clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants