[clang] [OpenACC] Implement enter data/exit data construct parsing (PR #72916)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 21 06:56:02 PST 2023


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

>From 5bdbe165e73eea4c01d0a02dec33afdd752a1858 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Mon, 20 Nov 2023 13:07:55 -0800
Subject: [PATCH 1/2] [OpenACC] Implement enter data/exit data construct
 parsing

These two constructs, 'enter data' and 'exit data', are novel compared
to what is currently in the parser, as this is the first set implemented
where the first token is itself not a valid construct.  Because of this,
it requires some additional work to do the first keyword parsing.
---
 .../clang/Basic/DiagnosticParseKinds.td       |   2 +-
 clang/include/clang/Basic/OpenACCKinds.h      |   7 +-
 clang/lib/Parse/ParseOpenACC.cpp              | 100 ++++++++++++++----
 clang/test/ParserOpenACC/parse-constructs.c   |  27 +++++
 4 files changed, 112 insertions(+), 24 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c3753ca2828e25e..54b5ba6e6414b2d 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1362,7 +1362,7 @@ def warn_pragma_acc_unimplemented_clause_parsing
     : Warning<"OpenACC clause parsing not yet implemented">,
       InGroup<SourceUsesOpenACC>;
 def err_acc_invalid_directive
-    : Error<"invalid OpenACC directive '%0'">;
+    : Error<"invalid OpenACC directive '%select{%1|%1 %2}0'">;
 def err_acc_missing_directive : Error<"expected OpenACC directive">;
 
 // OpenMP support.
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index d53b7223b5334b3..2a818638720abb0 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -24,9 +24,12 @@ enum class OpenACCDirectiveKind {
   Serial,
   Kernels,
 
-  // Data Environment.
+  // Data Environment. "enter data" and "exit data" are also referred to in the
+  // Executable Directives section, but just as a back reference to the Data
+  // Environment.
   Data,
-  // FIXME: 'enter data', 'exit data'.
+  EnterData,
+  ExitData,
   HostData,
 
   // Misc.
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index fdf0f24daf98548..a87cc92d4607ae0 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -21,24 +21,45 @@ using namespace clang;
 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) {
-  return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
-      .Case("parallel", OpenACCDirectiveKind::Parallel)
-      .Case("serial", OpenACCDirectiveKind::Serial)
-      .Case("kernels", OpenACCDirectiveKind::Kernels)
-      .Case("data", OpenACCDirectiveKind::Data)
-      .Case("host_data", OpenACCDirectiveKind::HostData)
-      .Case("loop", OpenACCDirectiveKind::Loop)
-      .Case("declare", OpenACCDirectiveKind::Declare)
-      .Case("init", OpenACCDirectiveKind::Init)
-      .Case("shutdown", OpenACCDirectiveKind::Shutdown)
-      .Case("set", OpenACCDirectiveKind::Shutdown)
-      .Case("update", OpenACCDirectiveKind::Update)
-      .Default(OpenACCDirectiveKind::Invalid);
+// An enum that contains the extended 'partial' parsed variants. This type
+// should never escape the initial parse functionality, but is useful for
+// simplifying the implementation.
+enum class OpenACCDirectiveKindEx {
+  Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid),
+  // 'enter data' and 'exit data'
+  Enter,
+  Exit,
+  // FIXME: Atomic Variants
+};
+
+// Translate single-token string representations to the OpenACC Directive Kind.
+// This doesn't completely comprehend 'Compound Constructs' (as it just
+// identifies the first token), and doesn't fully handle 'enter data', 'exit
+// data', nor any of the 'atomic' variants, just the first token of each.  So
+// this should only be used by `ParseOpenACCDirectiveKind`.
+OpenACCDirectiveKindEx getOpenACCDirectiveKind(StringRef Name) {
+  OpenACCDirectiveKind DirKind =
+      llvm::StringSwitch<OpenACCDirectiveKind>(Name)
+          .Case("parallel", OpenACCDirectiveKind::Parallel)
+          .Case("serial", OpenACCDirectiveKind::Serial)
+          .Case("kernels", OpenACCDirectiveKind::Kernels)
+          .Case("data", OpenACCDirectiveKind::Data)
+          .Case("host_data", OpenACCDirectiveKind::HostData)
+          .Case("loop", OpenACCDirectiveKind::Loop)
+          .Case("declare", OpenACCDirectiveKind::Declare)
+          .Case("init", OpenACCDirectiveKind::Init)
+          .Case("shutdown", OpenACCDirectiveKind::Shutdown)
+          .Case("set", OpenACCDirectiveKind::Shutdown)
+          .Case("update", OpenACCDirectiveKind::Update)
+          .Default(OpenACCDirectiveKind::Invalid);
+
+  if (DirKind != OpenACCDirectiveKind::Invalid)
+    return static_cast<OpenACCDirectiveKindEx>(DirKind);
+
+  return llvm::StringSwitch<OpenACCDirectiveKindEx>(Name)
+      .Case("enter", OpenACCDirectiveKindEx::Enter)
+      .Case("exit", OpenACCDirectiveKindEx::Exit)
+      .Default(OpenACCDirectiveKindEx::Invalid);
 }
 
 bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
@@ -59,6 +80,8 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
   case OpenACCDirectiveKind::ParallelLoop:
   case OpenACCDirectiveKind::SerialLoop:
   case OpenACCDirectiveKind::KernelsLoop:
+  case OpenACCDirectiveKind::EnterData:
+  case OpenACCDirectiveKind::ExitData:
     return false;
 
   case OpenACCDirectiveKind::Declare:
@@ -77,6 +100,32 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, StringRef Tok) {
   llvm_unreachable("Unknown 'Kind' Passed");
 }
 
+OpenACCDirectiveKind
+ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
+                                   StringRef FirstTokSpelling,
+                                   OpenACCDirectiveKindEx ExtDirKind) {
+  Token SecondTok = P.getCurToken();
+
+  if (SecondTok.isAnnotation()) {
+    P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling;
+    return OpenACCDirectiveKind::Invalid;
+  }
+
+  std::string SecondTokSpelling = P.getPreprocessor().getSpelling(SecondTok);
+
+  if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTokSpelling)) {
+    P.Diag(FirstTok, diag::err_acc_invalid_directive)
+        << 1 << FirstTokSpelling << SecondTokSpelling;
+    return OpenACCDirectiveKind::Invalid;
+  }
+
+  P.ConsumeToken();
+
+  return ExtDirKind == OpenACCDirectiveKindEx::Enter
+             ? OpenACCDirectiveKind::EnterData
+             : OpenACCDirectiveKind::ExitData;
+}
+
 // Parse and consume the tokens for OpenACC Directive/Construct kinds.
 OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   Token FirstTok = P.getCurToken();
@@ -91,10 +140,19 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
   P.ConsumeToken();
   std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);
 
-  OpenACCDirectiveKind DirKind = getOpenACCDirectiveKind(FirstTokSpelling);
+  OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTokSpelling);
+
+  switch (ExDirKind) {
+  case OpenACCDirectiveKindEx::Invalid:
+    P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling;
+    return OpenACCDirectiveKind::Invalid;
+  case OpenACCDirectiveKindEx::Enter:
+  case OpenACCDirectiveKindEx::Exit:
+    return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling,
+                                              ExDirKind);
+  }
 
-  if (DirKind == OpenACCDirectiveKind::Invalid)
-    P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
+  OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);
 
   // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any
   // other attempt at a combined construct will be diagnosed as an invalid
diff --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c
index fcad4507e7c1da0..a5270daf6034cf8 100644
--- a/clang/test/ParserOpenACC/parse-constructs.c
+++ b/clang/test/ParserOpenACC/parse-constructs.c
@@ -34,6 +34,33 @@ void func() {
   for(;;){}
   // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
   // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc enter data clause list
+  for(;;){}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc exit data clause list
+  for(;;){}
+  // expected-error at +3{{invalid OpenACC directive 'enter invalid'}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc enter invalid
+  for(;;){}
+  // expected-error at +3{{invalid OpenACC directive 'exit invalid'}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc exit invalid
+  for(;;){}
+  // expected-error at +2{{invalid OpenACC directive 'enter'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc enter
+  for(;;){}
+  // expected-error at +3{{invalid OpenACC directive 'exit }'}}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc exit }
+  for(;;){}
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc host_data clause list
   for(;;){}
   // expected-warning at +2{{OpenACC clause parsing not yet implemented}}

>From c8fc00bdc81cbf965328ca9c764126230d91be65 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Tue, 21 Nov 2023 06:55:44 -0800
Subject: [PATCH 2/2] Wrap switch with an if and a comment

---
 clang/lib/Parse/ParseOpenACC.cpp | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index a87cc92d4607ae0..a0f8fa97f6fa701 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -142,14 +142,23 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
 
   OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTokSpelling);
 
-  switch (ExDirKind) {
-  case OpenACCDirectiveKindEx::Invalid:
-    P.Diag(FirstTok, diag::err_acc_invalid_directive) << 0 << FirstTokSpelling;
-    return OpenACCDirectiveKind::Invalid;
-  case OpenACCDirectiveKindEx::Enter:
-  case OpenACCDirectiveKindEx::Exit:
-    return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling,
-                                              ExDirKind);
+  // OpenACCDirectiveKindEx is meant to be an extended list
+  // over OpenACCDirectiveKind, so any value below Invalid is one of the
+  // OpenACCDirectiveKind values.  This switch takes care of all of the extra
+  // parsing required for the Extended values.  At the end of this block,
+  // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can
+  // immediately cast it and use it as that.
+  if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {
+    switch (ExDirKind) {
+    case OpenACCDirectiveKindEx::Invalid:
+      P.Diag(FirstTok, diag::err_acc_invalid_directive)
+          << 0 << FirstTokSpelling;
+      return OpenACCDirectiveKind::Invalid;
+    case OpenACCDirectiveKindEx::Enter:
+    case OpenACCDirectiveKindEx::Exit:
+      return ParseOpenACCEnterExitDataDirective(P, FirstTok, FirstTokSpelling,
+                                                ExDirKind);
+    }
   }
 
   OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind);



More information about the cfe-commits mailing list