Skip to content

[OpenACC] Implement 'wait' construct parsing #74752

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 2 commits into from
Dec 8, 2023

Conversation

erichkeane
Copy link
Collaborator

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'.

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

llvmbot commented Dec 7, 2023

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

Changes

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'.


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

4 Files Affected:

  • (modified) clang/include/clang/Basic/OpenACCKinds.h (+1-1)
  • (modified) clang/include/clang/Parse/Parser.h (+1)
  • (modified) clang/lib/Parse/ParseOpenACC.cpp (+71)
  • (added) clang/test/ParserOpenACC/parse-wait-construct.c (+157)
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index 449a75638b43f5..62c0a4c1a9dea4 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 32d0b76c35b0d7..06634982351647 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 71cb665a563271..0bdf8da26bb01e 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 00000000000000..9b210bc7094210
--- /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@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait
+
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (
+
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait ()
+
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait () clause-list
+
+  // 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 wait (devnum:
+
+  // expected-error@+2{{expected expression}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum:)
+
+  // expected-error@+3{{expected expression}}
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum:) clause-list
+
+  // expected-error@+4{{expected ':'}}
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j
+
+  // expected-error@+2{{expected ':'}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j)
+
+  // expected-error@+3{{expected ':'}}
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:
+
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:)
+
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j:queues:
+
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j:queues:)
+
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (devnum: i + j:queues:) clause-list
+
+  // expected-error@+4{{use of undeclared identifier 'devnum'}}
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:devnum: i + j
+
+  // expected-error@+2{{use of undeclared identifier 'devnum'}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:devnum: i + j)
+
+  // expected-error@+3{{use of undeclared identifier 'devnum'}}
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait (queues:devnum: i + j) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(i, j, 1+1, 3.3
+
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(i, j, 1+1, 3.3)
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(i, j, 1+1, 3.3) clause-list
+
+  // 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 wait(,
+
+  // expected-error@+2{{expected expression}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(,)
+
+  // expected-error@+3{{expected expression}}
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(,) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(queues:i, j, 1+1, 3.3
+
+  // 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 wait(queues:i, j, 1+1, 3.3,
+
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(queues:i, j, 1+1, 3.3)
+
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(queues:i, j, 1+1, 3.3) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:i, j, 1+1, 3.3
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:i, j, 1+1, 3.3)
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list
+
+  // expected-error@+3{{expected ')'}}
+  // expected-note@+2{{to match this '('}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3)
+  // expected-warning@+2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}
+  #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list
+}

bool Parser::ParseOpenACCWaitArgument() {
// [devnum : int-expr : ]
if (Tok.is(tok::identifier) && NextToken().is(tok::colon) &&
Tok.getIdentifierInfo()->isStr("devnum")) {
Copy link
Member

Choose a reason for hiding this comment

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

I think better to introduce function, similar to isOpenACCDirectiveKind, something like isOpenACCStandardKind or something similar to check for some clauses-like tokens.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So I intended to do that for clauses themselves.

These are construct-specific 'key-token' things, which i see value in something like that, at least as far as simplification. I've chosen the name 'special token kind', as I don't think "StandardKind' really means what is being reflected here.

At the moment, we have 3 options for it (though only 2 for 'wait'), so once this patch goes in, I'll update the 'readonly' one from the last patch to use this infrastructure as well.

@erichkeane erichkeane merged commit df3db03 into llvm:main Dec 8, 2023
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.

3 participants