[clang] [OpenACC] Implement compound construct parsing (PR #72692)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 20 07:49:38 PST 2023


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

>From 33ca88871b48fcfb16bdf7fa636a9ecfa4f38e08 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 17 Nov 2023 11:34:43 -0800
Subject: [PATCH 1/4] [OpenACC] Implement compound construct parsing

This patch implements the compound construct parsing, which allows
'parallel loop', 'serial loop', and 'kernel loop' to act as their own
constructs.

Note that this doesn't end up making any changes to the tests, as
previously these ended up being considered clauses, which are also not
implemented. However, the location of that diagnostic is now 1 token
further along.
---
 clang/include/clang/Basic/OpenACCKinds.h |  5 +++-
 clang/lib/Parse/ParseOpenACC.cpp         | 33 +++++++++++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index 8da02b93b2b974c..d53b7223b5334b3 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -33,7 +33,10 @@ enum class OpenACCDirectiveKind {
   Loop,
   // FIXME: 'cache'
 
-  // FIXME: Combined Constructs.
+  // Combined Constructs.
+  ParallelLoop,
+  SerialLoop,
+  KernelsLoop,
 
   // FIXME: atomic Construct variants.
 
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index ba29d75fe35a500..a3c802b1f829877 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -22,7 +22,9 @@ using namespace llvm;
 
 namespace {
 
-// Translate single-token string representations to the OpenACC Directive Kind.
+// This doesn't completely comprehend 'Compound Constructs' (as it just
+// identifies the first token) just the first token of each.  So
+// this should only be used by `ParseOpenACCDirectiveKind`.
 OpenACCDirectiveKind GetOpenACCDirectiveKind(StringRef Name) {
   return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
       .Case("parallel", OpenACCDirectiveKind::Parallel)
@@ -50,6 +52,35 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   if (DirKind == OpenACCDirectiveKind::Invalid)
     P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
 
+  // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
+  // other attempt at a combined construct will be diagnosed as an invalid
+  // clause.
+  Token SecondTok = P.getCurToken();
+  switch (DirKind) {
+  default:
+    // Nothing to do except in the below cases, as they should be diagnosed as
+    // a clause.
+    break;
+  case OpenACCDirectiveKind::Parallel:
+    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+      P.ConsumeToken();
+      return OpenACCDirectiveKind::ParallelLoop;
+    }
+    break;
+  case OpenACCDirectiveKind::Serial:
+    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+      P.ConsumeToken();
+      return OpenACCDirectiveKind::SerialLoop;
+    }
+    break;
+  case OpenACCDirectiveKind::Kernels:
+    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+      P.ConsumeToken();
+      return OpenACCDirectiveKind::KernelsLoop;
+    }
+    break;
+  }
+
   return DirKind;
 }
 

>From bb2020318ec35858293f4c7a42e3fb2904a3013f Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 17 Nov 2023 13:35:53 -0800
Subject: [PATCH 2/4] Fix Alexeys comments

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

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index a3c802b1f829877..7a29c825c146f6b 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -22,10 +22,10 @@ using namespace llvm;
 
 namespace {
 
-// This doesn't completely comprehend 'Compound Constructs' (as it just
-// identifies the first token) just the first token of each.  So
-// this should only be used by `ParseOpenACCDirectiveKind`.
-OpenACCDirectiveKind GetOpenACCDirectiveKind(StringRef Name) {
+/// This doesn't completely comprehend 'Compound Constructs' (as it just
+/// identifies the first token) just the first token of each.  So
+/// this should only be used by `ParseOpenACCDirectiveKind`.
+OpenACCDirectiveKind getOpenACCDirectiveKind(StringRef Name) {
   return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
       .Case("parallel", OpenACCDirectiveKind::Parallel)
       .Case("serial", OpenACCDirectiveKind::Serial)
@@ -47,7 +47,7 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   P.ConsumeToken();
   std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);
 
-  OpenACCDirectiveKind DirKind = GetOpenACCDirectiveKind(FirstTokSpelling);
+  OpenACCDirectiveKind DirKind = getOpenACCDirectiveKind(FirstTokSpelling);
 
   if (DirKind == OpenACCDirectiveKind::Invalid)
     P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
@@ -56,29 +56,25 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   // other attempt at a combined construct will be diagnosed as an invalid
   // clause.
   Token SecondTok = P.getCurToken();
-  switch (DirKind) {
-  default:
-    // Nothing to do except in the below cases, as they should be diagnosed as
-    // a clause.
-    break;
-  case OpenACCDirectiveKind::Parallel:
-    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+  if (!SecondTok.isAnnotation() &&
+      P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+    OpenACCDirectiveKind ReturnKind;
+    switch (DirKind) {
+    default:
+      // Nothing to do except in the below cases, as they should be diagnosed as
+      // a clause.
+      break;
+    case OpenACCDirectiveKind::Parallel:
+      ReturnKind = OpenACCDirectiveKind::ParallelLoop;
+      LLVM_FALLTHROUGH;
+    case OpenACCDirectiveKind::Serial:
+      ReturnKind = OpenACCDirectiveKind::SerialLoop;
+      LLVM_FALLTHROUGH;
+    case OpenACCDirectiveKind::Kernels:
+      ReturnKind = OpenACCDirectiveKind::KernelsLoop;
       P.ConsumeToken();
-      return OpenACCDirectiveKind::ParallelLoop;
+      return ReturnKind;
     }
-    break;
-  case OpenACCDirectiveKind::Serial:
-    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
-      P.ConsumeToken();
-      return OpenACCDirectiveKind::SerialLoop;
-    }
-    break;
-  case OpenACCDirectiveKind::Kernels:
-    if (P.getPreprocessor().getSpelling(SecondTok) == "loop") {
-      P.ConsumeToken();
-      return OpenACCDirectiveKind::KernelsLoop;
-    }
-    break;
   }
 
   return DirKind;

>From cf6c14ec1d9609d0ef60aa35ae5a16c8b16ce928 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 17 Nov 2023 13:43:41 -0800
Subject: [PATCH 3/4] Remove misguided Returnkind variable, which does the
 wrong thing

---
 clang/lib/Parse/ParseOpenACC.cpp | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 7a29c825c146f6b..8a02a317d7b4b10 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -58,22 +58,20 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   Token SecondTok = P.getCurToken();
   if (!SecondTok.isAnnotation() &&
       P.getPreprocessor().getSpelling(SecondTok) == "loop") {
-    OpenACCDirectiveKind ReturnKind;
     switch (DirKind) {
     default:
       // Nothing to do except in the below cases, as they should be diagnosed as
       // a clause.
       break;
     case OpenACCDirectiveKind::Parallel:
-      ReturnKind = OpenACCDirectiveKind::ParallelLoop;
-      LLVM_FALLTHROUGH;
+      P.ConsumeToken();
+      return OpenACCDirectiveKind::ParallelLoop;
     case OpenACCDirectiveKind::Serial:
-      ReturnKind = OpenACCDirectiveKind::SerialLoop;
-      LLVM_FALLTHROUGH;
+      P.ConsumeToken();
+      return OpenACCDirectiveKind::SerialLoop;
     case OpenACCDirectiveKind::Kernels:
-      ReturnKind = OpenACCDirectiveKind::KernelsLoop;
       P.ConsumeToken();
-      return ReturnKind;
+      return OpenACCDirectiveKind::KernelsLoop;
     }
   }
 

>From fd5141de44e9fc1dc69ca2c3b8070c35429c8e6a Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Mon, 20 Nov 2023 07:49:08 -0800
Subject: [PATCH 4/4] Move the token check to its own function

---
 clang/lib/Parse/ParseOpenACC.cpp            | 39 ++++++++++++++++++++-
 clang/test/ParserOpenACC/parse-constructs.c | 10 ++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index 8a02a317d7b4b10..f60b1e93d437ada 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -41,6 +41,42 @@ OpenACCDirectiveKind getOpenACCDirectiveKind(StringRef Name) {
       .Default(OpenACCDirectiveKind::Invalid);
 }
 
+bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
+  switch (Kind) {
+  case OpenACCDirectiveKind::Parallel:
+    return Tok == "parallel";
+  case OpenACCDirectiveKind::Serial:
+    return Tok == "serial";
+  case OpenACCDirectiveKind::Kernels:
+    return Tok == "kernels";
+  case OpenACCDirectiveKind::Data:
+    return Tok == "data";
+  case OpenACCDirectiveKind::HostData:
+    return Tok == "host_data";
+  case OpenACCDirectiveKind::Loop:
+    return Tok == "loop";
+
+  case OpenACCDirectiveKind::ParallelLoop:
+  case OpenACCDirectiveKind::SerialLoop:
+  case OpenACCDirectiveKind::KernelsLoop:
+    return false;
+
+  case OpenACCDirectiveKind::Declare:
+    return Tok == "declare";
+  case OpenACCDirectiveKind::Init:
+    return Tok == "init";
+  case OpenACCDirectiveKind::Shutdown:
+    return Tok == "shutdown";
+  case OpenACCDirectiveKind::Set:
+    return Tok == "set";
+  case OpenACCDirectiveKind::Update:
+    return Tok == "update";
+  case OpenACCDirectiveKind::Invalid:
+    return false;
+  }
+  llvm_unreachable("Unknown 'Kind' Passed");
+}
+
 // Parse and consume the tokens for OpenACC Directive/Construct kinds.
 OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   Token FirstTok = P.getCurToken();
@@ -57,7 +93,8 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   // clause.
   Token SecondTok = P.getCurToken();
   if (!SecondTok.isAnnotation() &&
-      P.getPreprocessor().getSpelling(SecondTok) == "loop") {
+      isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop,
+                             P.getPreprocessor().getSpelling(SecondTok))) {
     switch (DirKind) {
     default:
       // Nothing to do except in the below cases, as they should be diagnosed as
diff --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c
index e0607e7cfe316ab..63f0d02b6726d0f 100644
--- a/clang/test/ParserOpenACC/parse-constructs.c
+++ b/clang/test/ParserOpenACC/parse-constructs.c
@@ -42,14 +42,24 @@ void func() {
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc parallel loop clause list
   for(;;){}
+
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc parallel loop
+  for(;;){}
   // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc serial loop clause list
+  for(;;){}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc serial loop
   for(;;){}
   // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc kernels loop clause list
   for(;;){}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc kernels loop
+  for(;;){}
 
   // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}



More information about the cfe-commits mailing list