[clang] 64b6ef0 - [OpenACC] Implement initial parsing for `parallel` construct (#72661)

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 17 10:47:46 PST 2023


Author: Erich Keane
Date: 2023-11-17T10:47:42-08:00
New Revision: 64b6ef02e263a8ee48bd91f8b06dd3945eb9be44

URL: https://github.com/llvm/llvm-project/commit/64b6ef02e263a8ee48bd91f8b06dd3945eb9be44
DIFF: https://github.com/llvm/llvm-project/commit/64b6ef02e263a8ee48bd91f8b06dd3945eb9be44.diff

LOG: [OpenACC] Implement initial parsing for `parallel` construct (#72661)

As the first real parsing effort for the OpenACC implementation effort,
this implements the parsing for first construct/directive name. This
does not do any semantic analysis, nor any of the clauses. Those will
come in a future patch.

For the time being, we warn when we hit a point that we don't implement
the parsing for either of these situations.

Added: 
    clang/include/clang/Basic/OpenACCKinds.h
    clang/test/ParserOpenACC/parse-constructs.c

Modified: 
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Parse/RAIIObjectsForParser.h
    clang/lib/Parse/ParseOpenACC.cpp
    clang/lib/Parse/Parser.cpp
    clang/test/ParserOpenACC/unimplemented.c
    clang/test/ParserOpenACC/unimplemented.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c3d06053caa5eea..1beddb5808fa2d6 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1343,13 +1343,20 @@ def err_openclcxx_virtual_function : Error<
   "virtual functions are not supported in C++ for OpenCL">;
 
 // OpenACC Support.
-def warn_pragma_acc_ignored : Warning<
-  "unexpected '#pragma acc ...' in program">, InGroup<SourceUsesOpenACC>, DefaultIgnore;
-def err_acc_unexpected_directive : Error<
-  "unexpected OpenACC directive %select{|'#pragma acc %1'}0">;
+def warn_pragma_acc_ignored
+    : Warning<"unexpected '#pragma acc ...' in program">,
+      InGroup<SourceUsesOpenACC>,
+      DefaultIgnore;
+def err_acc_unexpected_directive
+    : Error<"unexpected OpenACC directive %select{|'#pragma acc %1'}0">;
 def warn_pragma_acc_unimplemented
     : Warning<"OpenACC directives not yet implemented, pragma ignored">,
       InGroup<SourceUsesOpenACC>;
+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'">;
 
 // OpenMP support.
 def warn_pragma_omp_ignored : Warning<

diff  --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
new file mode 100644
index 000000000000000..79780b7fe6835f3
--- /dev/null
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -0,0 +1,30 @@
+//===--- OpenACCKinds.h - OpenACC Enums -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines some OpenACC-specific enums and functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_OPENACCKINDS_H
+#define LLVM_CLANG_BASIC_OPENACCKINDS_H
+
+namespace clang {
+// Represents the Construct/Directive kind of a pragma directive. Note the
+// OpenACC standard is inconsistent between calling these Construct vs
+// Directive, but we're calling it a Directive to be consistent with OpenMP.
+enum class OpenACCDirectiveKind {
+  // Compute Constructs.
+  Parallel,
+
+  // Invalid.
+  Invalid,
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 2f56da8439d07ee..d20a26dbf2562a7 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -53,6 +53,7 @@ namespace clang {
 class Parser : public CodeCompletionHandler {
   friend class ColonProtectionRAIIObject;
   friend class ParsingOpenMPDirectiveRAII;
+  friend class ParsingOpenACCDirectiveRAII;
   friend class InMessageExpressionRAIIObject;
   friend class OffsetOfStateRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
@@ -230,6 +231,9 @@ class Parser : public CodeCompletionHandler {
   /// Parsing OpenMP directive mode.
   bool OpenMPDirectiveParsing = false;
 
+  /// Parsing OpenACC directive mode.
+  bool OpenACCDirectiveParsing = false;
+
   /// When true, we are directly inside an Objective-C message
   /// send expression.
   ///

diff  --git a/clang/include/clang/Parse/RAIIObjectsForParser.h b/clang/include/clang/Parse/RAIIObjectsForParser.h
index cb525c9d0edd6bc..e1626a7870bb7ae 100644
--- a/clang/include/clang/Parse/RAIIObjectsForParser.h
+++ b/clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -309,6 +309,25 @@ namespace clang {
     ~ParsingOpenMPDirectiveRAII() { restore(); }
   };
 
+  /// Activates OpenACC parsing mode to preseve OpenACC specific annotation
+  /// tokens.
+  class ParsingOpenACCDirectiveRAII {
+    Parser &P;
+    bool OldVal;
+
+  public:
+    ParsingOpenACCDirectiveRAII(Parser &P, bool Value = true)
+        : P(P), OldVal(P.OpenACCDirectiveParsing) {
+      P.OpenACCDirectiveParsing = Value;
+    }
+
+    /// This can be used to restore the state early, before the dtor
+    /// is run.
+    void restore() { P.OpenMPDirectiveParsing = OldVal; }
+
+    ~ParsingOpenACCDirectiveRAII() { restore(); }
+  };
+
   /// RAII object that makes '>' behave either as an operator
   /// or as the closing angle bracket for a template argument list.
   class GreaterThanIsOperatorScope {

diff  --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index ab790515caa7e38..9f13aadf92e4f66 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -10,18 +10,79 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Basic/OpenACCKinds.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
+using namespace llvm;
 
+namespace {
+
+// Translate single-token string representations to the OpenACC Directive Kind.
+OpenACCDirectiveKind GetOpenACCDirectiveKind(StringRef Name) {
+  return llvm::StringSwitch<OpenACCDirectiveKind>(Name)
+      .Case("parallel", OpenACCDirectiveKind::Parallel)
+      .Default(OpenACCDirectiveKind::Invalid);
+}
+
+// Parse and consume the tokens for OpenACC Directive/Construct kinds.
+OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
+  Token FirstTok = P.getCurToken();
+  P.ConsumeToken();
+  std::string FirstTokSpelling = P.getPreprocessor().getSpelling(FirstTok);
+
+  OpenACCDirectiveKind DirKind = GetOpenACCDirectiveKind(FirstTokSpelling);
+
+  if (DirKind == OpenACCDirectiveKind::Invalid)
+    P.Diag(FirstTok, diag::err_acc_invalid_directive) << FirstTokSpelling;
+
+  return DirKind;
+}
+
+void ParseOpenACCClauseList(Parser &P) {
+  // FIXME: In the future, we'll start parsing the clauses here, but for now we
+  // haven't implemented that, so just emit the unimplemented diagnostic and
+  // fail reasonably.
+  if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
+    P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
+}
+
+void ParseOpenACCDirective(Parser &P) {
+  ParseOpenACCDirectiveKind(P);
+
+  // Parses the list of clauses, if present.
+  ParseOpenACCClauseList(P);
+
+  P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented);
+  P.SkipUntil(tok::annot_pragma_openacc_end);
+}
+
+} // namespace
+
+// Parse OpenACC directive on a declaration.
 Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() {
-  Diag(Tok, diag::warn_pragma_acc_unimplemented);
-  SkipUntil(tok::annot_pragma_openacc_end);
+  assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
+
+  ParsingOpenACCDirectiveRAII DirScope(*this);
+  ConsumeAnnotationToken();
+
+  ParseOpenACCDirective(*this);
+
   return nullptr;
 }
+
+// Parse OpenACC Directive on a Statement.
 StmtResult Parser::ParseOpenACCDirectiveStmt() {
-  Diag(Tok, diag::warn_pragma_acc_unimplemented);
-  SkipUntil(tok::annot_pragma_openacc_end);
+  assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");
+
+  ParsingOpenACCDirectiveRAII DirScope(*this);
+  ConsumeAnnotationToken();
+
+  ParseOpenACCDirective(*this);
+
   return StmtEmpty();
 }

diff  --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 9eed08820887115..1baeb2aeb021faa 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -320,8 +320,9 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
       break;
     case tok::annot_pragma_openacc:
     case tok::annot_pragma_openacc_end:
-      // FIXME: Like OpenMP above, we should not be doing this if we're parsing
-      // an OpenACC Directive.
+      // Stop before an OpenACC pragma boundary.
+      if (OpenACCDirectiveParsing)
+        return false;
       ConsumeAnnotationToken();
       break;
     case tok::annot_module_begin:

diff  --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c
new file mode 100644
index 000000000000000..4c2188cc3cef11b
--- /dev/null
+++ b/clang/test/ParserOpenACC/parse-constructs.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -verify -fopenacc
+
+void func() {
+  // expected-error at +2{{invalid OpenACC directive 'invalid'}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc invalid
+  for(;;){}
+
+  // expected-warning at +2{{OpenACC clause parsing not yet implemented}}
+  // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
+#pragma acc parallel 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 parallel() clause list
+}

diff  --git a/clang/test/ParserOpenACC/unimplemented.c b/clang/test/ParserOpenACC/unimplemented.c
index c1228c8f2b97fc5..dd2e8bea7470918 100644
--- a/clang/test/ParserOpenACC/unimplemented.c
+++ b/clang/test/ParserOpenACC/unimplemented.c
@@ -1,12 +1,16 @@
 // RUN: %clang_cc1 %s -verify -fopenacc
 
 // Parser::ParseExternalDeclaration
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
 int foo;
 
 struct S {
 // Parser::ParseStructUnionBody
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
   int foo;
@@ -14,6 +18,8 @@ struct S {
 
 void func() {
 // Parser::ParseStmtOrDeclarationAfterAttributes
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
   while(0) {}

diff  --git a/clang/test/ParserOpenACC/unimplemented.cpp b/clang/test/ParserOpenACC/unimplemented.cpp
index 095cbf570a41a06..4f6c5a649065ec9 100644
--- a/clang/test/ParserOpenACC/unimplemented.cpp
+++ b/clang/test/ParserOpenACC/unimplemented.cpp
@@ -1,12 +1,16 @@
 // RUN: %clang_cc1 %s -verify -fopenacc
 
 // Parser::ParseExternalDeclaration
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
 int foo;
 
 struct S {
 // Parser::ParseCXXClassMemberDeclarationWithPragmas
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
   int foo;
@@ -14,6 +18,8 @@ struct S {
 
 void func() {
 // Parser::ParseStmtOrDeclarationAfterAttributes
+// expected-error at +3{{invalid OpenACC directive 'not'}}
+// expected-warning at +2{{OpenACC clause parsing not yet implemented}}
 // expected-warning at +1{{OpenACC directives not yet implemented, pragma ignored}}
 #pragma acc not yet implemented
   while(false) {}


        


More information about the cfe-commits mailing list