[clang] [OpenACC] Implement 'wait' construct parsing (PR #74752)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 7 13:30:36 PST 2023


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

>From 8b7d70d55395d9a75968deeac8a13d88aae62a00 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 7 Dec 2023 08:55:46 -0800
Subject: [PATCH 1/2] [OpenACC] Implement 'wait' construct parsing

The 'wait' construct comes in two forms: one with no parens, the second
with a 'wait-argument'. This implements both forms for constructs.

Additionally, the 'wait-argument' parsing is split into its own function
because the 'wait clause' can also take the same 'wait-argument'.
---
 clang/include/clang/Basic/OpenACCKinds.h      |   2 +-
 clang/include/clang/Parse/Parser.h            |   1 +
 clang/lib/Parse/ParseOpenACC.cpp              |  71 ++++++++
 .../test/ParserOpenACC/parse-wait-construct.c | 157 ++++++++++++++++++
 4 files changed, 230 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/ParserOpenACC/parse-wait-construct.c

diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index 449a75638b43f..62c0a4c1a9dea 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -53,7 +53,7 @@ enum class OpenACCDirectiveKind {
   Shutdown,
   Set,
   Update,
-  // FIXME: wait construct.
+  Wait,
 
   // Procedure Calls in Compute Regions.
   Routine,
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 32d0b76c35b0d..0663498235164 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3544,6 +3544,7 @@ class Parser : public CodeCompletionHandler {
   void ParseOpenACCCacheVarList();
   /// Parses a single variable in a variable list for the 'cache' construct.
   bool ParseOpenACCCacheVar();
+  bool ParseOpenACCWaitArgument();
 
 private:
   //===--------------------------------------------------------------------===//
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 71cb665a56327..0bdf8da26bb01 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -56,6 +56,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
           .Case("shutdown", OpenACCDirectiveKind::Shutdown)
           .Case("set", OpenACCDirectiveKind::Shutdown)
           .Case("update", OpenACCDirectiveKind::Update)
+          .Case("wait", OpenACCDirectiveKind::Wait)
           .Default(OpenACCDirectiveKind::Invalid);
 
   if (DirKind != OpenACCDirectiveKind::Invalid)
@@ -123,6 +124,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
     return Tok.getIdentifierInfo()->isStr("set");
   case OpenACCDirectiveKind::Update:
     return Tok.getIdentifierInfo()->isStr("update");
+  case OpenACCDirectiveKind::Wait:
+    return Tok.getIdentifierInfo()->isStr("wait");
   case OpenACCDirectiveKind::Invalid:
     return false;
   }
@@ -251,6 +254,67 @@ void ParseOpenACCClauseList(Parser &P) {
 
 } // namespace
 
+/// OpenACC 3.3, section 2.16:
+/// In this section and throughout the specification, the term wait-argument
+/// means:
+/// [ devnum : int-expr : ] [ queues : ] async-argument-list
+bool Parser::ParseOpenACCWaitArgument() {
+  // [devnum : int-expr : ]
+  if (Tok.is(tok::identifier) && NextToken().is(tok::colon) &&
+      Tok.getIdentifierInfo()->isStr("devnum")) {
+    // Consume devnum.
+    ConsumeToken();
+    // Consume colon.
+    ConsumeToken();
+
+    ExprResult IntExpr =
+        getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+    if (IntExpr.isInvalid())
+      return true;
+
+    if (ExpectAndConsume(tok::colon))
+      return true;
+  }
+
+  // [ queues : ]
+  if (Tok.is(tok::identifier) && NextToken().is(tok::colon) &&
+      Tok.getIdentifierInfo()->isStr("queues")) {
+    // Consume queues.
+    ConsumeToken();
+    // Consume colon.
+    ConsumeToken();
+  }
+
+  // OpenACC 3.3, section 2.16:
+  // the term 'async-argument' means a nonnegative scalar integer expression, or
+  // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined
+  // in the C header file and the Fortran opacc module.
+  //
+  // We are parsing this simply as list of assignment expressions (to avoid
+  // comma being troublesome), and will ensure it is an integral type.  The
+  // 'special' types are defined as macros, so we can't really check those
+  // (other than perhaps as values at one point?), but the standard does say it
+  // is implementation-defined to use any other negative value.
+  //
+  //
+  bool FirstArg = true;
+  while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
+    if (!FirstArg) {
+      if (ExpectAndConsume(tok::comma))
+        return true;
+    }
+    FirstArg = false;
+
+    ExprResult CurArg =
+        getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
+
+    if (CurArg.isInvalid())
+      return true;
+  }
+
+  return false;
+}
+
 ExprResult Parser::ParseOpenACCIDExpression() {
   ExprResult Res;
   if (getLangOpts().CPlusPlus) {
@@ -399,6 +463,13 @@ void Parser::ParseOpenACCDirective() {
       // so we can always consume the close.
       T.consumeClose();
       break;
+    case OpenACCDirectiveKind::Wait:
+      // OpenACC has an optional paren-wrapped 'wait-argument'.
+      if (ParseOpenACCWaitArgument())
+        T.skipToEnd();
+      else
+        T.consumeClose();
+      break;
     }
   } else if (DirKind == OpenACCDirectiveKind::Cache) {
     // Cache's paren var-list is required, so error here if it isn't provided.
diff --git a/clang/test/ParserOpenACC/parse-wait-construct.c b/clang/test/ParserOpenACC/parse-wait-construct.c
new file mode 100644
index 0000000000000..9b210bc709421
--- /dev/null
+++ b/clang/test/ParserOpenACC/parse-wait-construct.c
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 %s -verify -fopenacc
+
+void func() {
+  int i, j;
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait clause-list
+
+  // 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 wait (
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait ()
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait () clause-list
+
+  // 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 wait (devnum:
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum:)
+
+  // expected-error at +3{{expected expression}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum:) clause-list
+
+  // expected-error at +4{{expected ':'}}
+  // 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 wait (devnum: i + j
+
+  // expected-error at +2{{expected ':'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j)
+
+  // expected-error at +3{{expected ':'}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j) clause-list
+
+  // 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 wait (queues:
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:)
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:) clause-list
+
+  // 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 wait (devnum: i + j:queues:
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j:queues:)
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j:queues:) clause-list
+
+  // expected-error at +4{{use of undeclared identifier 'devnum'}}
+  // 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 wait (queues:devnum: i + j
+
+  // expected-error at +2{{use of undeclared identifier 'devnum'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:devnum: i + j)
+
+  // expected-error at +3{{use of undeclared identifier 'devnum'}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:devnum: i + j) clause-list
+
+  // 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 wait(i, j, 1+1, 3.3
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(i, j, 1+1, 3.3)
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(i, j, 1+1, 3.3) clause-list
+
+  // 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 wait(,
+
+  // expected-error at +2{{expected expression}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(,)
+
+  // expected-error at +3{{expected expression}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(,) clause-list
+
+  // 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 wait(queues:i, j, 1+1, 3.3
+
+  // 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 wait(queues:i, j, 1+1, 3.3,
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(queues:i, j, 1+1, 3.3)
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(queues:i, j, 1+1, 3.3) clause-list
+
+  // 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 wait(devnum:3:i, j, 1+1, 3.3
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:i, j, 1+1, 3.3)
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list
+
+  // 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 wait(devnum:3:queues:i, j, 1+1, 3.3
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3)
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
+}

>From 9fbfe112f4420777a0c0ff8837ce929a31457a17 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 7 Dec 2023 13:30:13 -0800
Subject: [PATCH 2/2] Add isSpecialTokenKind

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

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 0bdf8da26bb01..40b53dd180c79 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -83,6 +83,24 @@ OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
       .Default(OpenACCAtomicKind::Invalid);
 }
 
+enum class OpenACCSpecialTokenKind {
+  DevNum,
+  Queues,
+};
+
+bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {
+  if (!Tok.is(tok::identifier))
+    return false;
+
+  switch (Kind) {
+  case OpenACCSpecialTokenKind::DevNum:
+    return Tok.getIdentifierInfo()->isStr("devnum");
+  case OpenACCSpecialTokenKind::Queues:
+    return Tok.getIdentifierInfo()->isStr("queues");
+  }
+  llvm_unreachable("Unknown 'Kind' Passed");
+}
+
 bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) {
   if (!Tok.is(tok::identifier))
     return false;
@@ -260,8 +278,8 @@ void ParseOpenACCClauseList(Parser &P) {
 /// [ devnum : int-expr : ] [ queues : ] async-argument-list
 bool Parser::ParseOpenACCWaitArgument() {
   // [devnum : int-expr : ]
-  if (Tok.is(tok::identifier) && NextToken().is(tok::colon) &&
-      Tok.getIdentifierInfo()->isStr("devnum")) {
+  if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
+      NextToken().is(tok::colon)) {
     // Consume devnum.
     ConsumeToken();
     // Consume colon.
@@ -277,8 +295,8 @@ bool Parser::ParseOpenACCWaitArgument() {
   }
 
   // [ queues : ]
-  if (Tok.is(tok::identifier) && NextToken().is(tok::colon) &&
-      Tok.getIdentifierInfo()->isStr("queues")) {
+  if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
+      NextToken().is(tok::colon)) {
     // Consume queues.
     ConsumeToken();
     // Consume colon.



More information about the cfe-commits mailing list