[flang-commits] [flang] 048aaab - [flang][openacc] Use TableGen to generate the clause parser

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Mon Jul 18 00:27:20 PDT 2022


Author: Valentin Clement
Date: 2022-07-18T09:26:57+02:00
New Revision: 048aaab19420a67c5b4075726233f73b37ed177c

URL: https://github.com/llvm/llvm-project/commit/048aaab19420a67c5b4075726233f73b37ed177c
DIFF: https://github.com/llvm/llvm-project/commit/048aaab19420a67c5b4075726233f73b37ed177c.diff

LOG: [flang][openacc] Use TableGen to generate the clause parser

This patch introduce an automatic generation of the clause parser from the TableGen
information.

New information can be stored directly in the TableGen file:
- The different aliases that a clause support.
- prefix before a value.
- whether a prefix is optional or not.

Makes it easier to add new clauses and also avoid some error (`write` clause incorrect until now).

This patch is updating only the OpenACC part. A patch with a modification of the OpenMP clause parser will follow.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D106968

Added: 
    

Modified: 
    flang/lib/Parser/openacc-parsers.cpp
    llvm/include/llvm/Frontend/Directive/DirectiveBase.td
    llvm/include/llvm/Frontend/OpenACC/ACC.td
    llvm/include/llvm/TableGen/DirectiveEmitter.h
    llvm/test/TableGen/directive1.td
    llvm/utils/TableGen/DirectiveEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp
index f11f6530951a3..fa5e41562d409 100644
--- a/flang/lib/Parser/openacc-parsers.cpp
+++ b/flang/lib/Parser/openacc-parsers.cpp
@@ -22,97 +22,12 @@ namespace Fortran::parser {
 constexpr auto startAccLine = skipStuffBeforeStatement >> "!$ACC "_sptok;
 constexpr auto endAccLine = space >> endOfLine;
 
-// Basic clauses
-TYPE_PARSER("AUTO" >> construct<AccClause>(construct<AccClause::Auto>()) ||
-    "ASYNC" >> construct<AccClause>(construct<AccClause::Async>(
-                   maybe(parenthesized(scalarIntExpr)))) ||
-    "ATTACH" >> construct<AccClause>(construct<AccClause::Attach>(
-                    parenthesized(Parser<AccObjectList>{}))) ||
-    "BIND" >> construct<AccClause>(
-                  construct<AccClause::Bind>(Parser<AccBindClause>{})) ||
-    "CAPTURE" >> construct<AccClause>(construct<AccClause::Capture>()) ||
-    "COLLAPSE" >> construct<AccClause>(construct<AccClause::Collapse>(
-                      parenthesized(scalarIntConstantExpr))) ||
-    ("COPY"_tok || "PRESENT_OR_COPY"_tok || "PCOPY"_tok) >>
-        construct<AccClause>(construct<AccClause::Copy>(
-            parenthesized(Parser<AccObjectList>{}))) ||
-    ("COPYIN"_tok || "PRESENT_OR_COPYIN"_tok || "PCOPYIN"_tok) >>
-        construct<AccClause>(construct<AccClause::Copyin>(
-            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
-    ("COPYOUT"_tok || "PRESENT_OR_COPYOUT"_tok || "PCOPYOUT"_tok) >>
-        construct<AccClause>(construct<AccClause::Copyout>(
-            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
-    ("CREATE"_tok || "PRESENT_OR_CREATE"_tok || "PCREATE"_tok) >>
-        construct<AccClause>(construct<AccClause::Create>(
-            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
-    "DEFAULT" >> construct<AccClause>(construct<AccClause::Default>(
-                     Parser<AccDefaultClause>{})) ||
-    "DEFAULT_ASYNC" >> construct<AccClause>(construct<AccClause::DefaultAsync>(
-                           parenthesized(scalarIntExpr))) ||
-    "DELETE" >> construct<AccClause>(construct<AccClause::Delete>(
-                    parenthesized(Parser<AccObjectList>{}))) ||
-    "DETACH" >> construct<AccClause>(construct<AccClause::Detach>(
-                    parenthesized(Parser<AccObjectList>{}))) ||
-    "DEVICE" >> construct<AccClause>(construct<AccClause::Device>(
-                    parenthesized(Parser<AccObjectList>{}))) ||
-    "DEVICEPTR" >> construct<AccClause>(construct<AccClause::Deviceptr>(
-                       parenthesized(Parser<AccObjectList>{}))) ||
-    "DEVICE_NUM" >> construct<AccClause>(construct<AccClause::DeviceNum>(
-                        parenthesized(scalarIntExpr))) ||
-    "DEVICE_RESIDENT" >>
-        construct<AccClause>(construct<AccClause::DeviceResident>(
-            parenthesized(Parser<AccObjectList>{}))) ||
-    ("DEVICE_TYPE"_tok || "DTYPE"_tok) >>
-        construct<AccClause>(construct<AccClause::DeviceType>(
-            parenthesized(Parser<AccDeviceTypeExprList>{}))) ||
-    "FINALIZE" >> construct<AccClause>(construct<AccClause::Finalize>()) ||
-    "FIRSTPRIVATE" >> construct<AccClause>(construct<AccClause::Firstprivate>(
-                          parenthesized(Parser<AccObjectList>{}))) ||
-    "GANG" >> construct<AccClause>(construct<AccClause::Gang>(
-                  maybe(parenthesized(Parser<AccGangArgument>{})))) ||
-    "HOST" >> construct<AccClause>(construct<AccClause::Host>(
-                  parenthesized(Parser<AccObjectList>{}))) ||
-    "IF" >> construct<AccClause>(
-                construct<AccClause::If>(parenthesized(scalarLogicalExpr))) ||
-    "IF_PRESENT" >> construct<AccClause>(construct<AccClause::IfPresent>()) ||
-    "INDEPENDENT" >>
-        construct<AccClause>(construct<AccClause::Independent>()) ||
-    "LINK" >> construct<AccClause>(construct<AccClause::Link>(
-                  parenthesized(Parser<AccObjectList>{}))) ||
-    "NO_CREATE" >> construct<AccClause>(construct<AccClause::NoCreate>(
-                       parenthesized(Parser<AccObjectList>{}))) ||
-    "NOHOST" >> construct<AccClause>(construct<AccClause::Nohost>()) ||
-    "NUM_GANGS" >> construct<AccClause>(construct<AccClause::NumGangs>(
-                       parenthesized(scalarIntExpr))) ||
-    "NUM_WORKERS" >> construct<AccClause>(construct<AccClause::NumWorkers>(
-                         parenthesized(scalarIntExpr))) ||
-    "PRESENT" >> construct<AccClause>(construct<AccClause::Present>(
-                     parenthesized(Parser<AccObjectList>{}))) ||
-    "PRIVATE" >> construct<AccClause>(construct<AccClause::Private>(
-                     parenthesized(Parser<AccObjectList>{}))) ||
-    "READ" >> construct<AccClause>(construct<AccClause::Read>()) ||
-    "REDUCTION" >> construct<AccClause>(construct<AccClause::Reduction>(
-                       parenthesized(construct<AccObjectListWithReduction>(
-                           Parser<AccReductionOperator>{} / ":",
-                           Parser<AccObjectList>{})))) ||
-    "SELF" >> construct<AccClause>(construct<AccClause::Self>(
-                  maybe(parenthesized(Parser<AccSelfClause>{})))) ||
-    "SEQ" >> construct<AccClause>(construct<AccClause::Seq>()) ||
-    "TILE" >> construct<AccClause>(construct<AccClause::Tile>(
-                  parenthesized(Parser<AccTileExprList>{}))) ||
-    "USE_DEVICE" >> construct<AccClause>(construct<AccClause::UseDevice>(
-                        parenthesized(Parser<AccObjectList>{}))) ||
-    "VECTOR_LENGTH" >> construct<AccClause>(construct<AccClause::VectorLength>(
-                           parenthesized(scalarIntExpr))) ||
-    "VECTOR" >>
-        construct<AccClause>(construct<AccClause::Vector>(maybe(
-            parenthesized(("LENGTH:" >> scalarIntExpr || scalarIntExpr))))) ||
-    "WAIT" >> construct<AccClause>(construct<AccClause::Wait>(
-                  maybe(parenthesized(Parser<AccWaitArgument>{})))) ||
-    "WORKER" >>
-        construct<AccClause>(construct<AccClause::Worker>(maybe(
-            parenthesized(("NUM:" >> scalarIntExpr || scalarIntExpr))))) ||
-    "WRITE" >> construct<AccClause>(construct<AccClause::Auto>()))
+// Autogenerated clauses parser. Information is taken from ACC.td and the
+// parser is generated by tablegen.
+// Scalar value parsers are provided by Flang directly. Specific value parsers
+// are provided below.
+#define GEN_FLANG_CLAUSES_PARSER
+#include "llvm/Frontend/OpenACC/ACC.inc"
 
 TYPE_PARSER(
     construct<AccObject>(designator) || construct<AccObject>("/" >> name / "/"))
@@ -122,6 +37,9 @@ TYPE_PARSER(construct<AccObjectList>(nonemptyList(Parser<AccObject>{})))
 TYPE_PARSER(construct<AccObjectListWithModifier>(
     maybe(Parser<AccDataModifier>{}), Parser<AccObjectList>{}))
 
+TYPE_PARSER(construct<AccObjectListWithReduction>(
+    Parser<AccReductionOperator>{} / ":", Parser<AccObjectList>{}))
+
 // 2.16.3 (2485) wait-argument is:
 //   [devnum : int-expr :] [queues :] int-expr-list
 TYPE_PARSER(construct<AccWaitArgument>(maybe("DEVNUM:" >> scalarIntExpr / ":"),
@@ -170,13 +88,13 @@ TYPE_PARSER(sourced(construct<AccReductionOperator>(
         ".NEQV." >> pure(AccReductionOperator::Operator::Neqv)))))
 
 // 2.15.1 Bind clause
-TYPE_PARSER(sourced(construct<AccBindClause>(parenthesized(name))) ||
-    sourced(construct<AccBindClause>(parenthesized(scalarDefaultCharExpr))))
+TYPE_PARSER(sourced(construct<AccBindClause>(name)) ||
+    sourced(construct<AccBindClause>(scalarDefaultCharExpr)))
 
 // 2.5.14 Default clause
-TYPE_PARSER(construct<AccDefaultClause>(parenthesized(
+TYPE_PARSER(construct<AccDefaultClause>(
     first("NONE" >> pure(llvm::acc::DefaultValue::ACC_Default_none),
-        "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present)))))
+        "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present))))
 
 // SELF clause is either a simple optional condition for compute construct
 // or a synonym of the HOST clause for the update directive 2.14.4 holding

diff  --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index e40f40f74c73f..4269a966a988d 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -74,6 +74,9 @@ class Clause<string c> {
   // Define an alternative name return in get<LanguageName>ClauseName function.
   string alternativeName = "";
 
+  // Define aliases used in the parser.
+  list<string> aliases = [];
+
   // Optional class holding value of the clause in clang AST.
   string clangClass = "";
 
@@ -88,6 +91,7 @@ class Clause<string c> {
 
   // List of allowed clause values
   list<ClauseVal> allowedClauseValues = [];
+
   // If set to true, value class is part of a list. Single class by default.
   bit isValueList = false;
 
@@ -101,6 +105,14 @@ class Clause<string c> {
   // Set clause used by default when unknown. Function returning the kind
   // of enumeration will use this clause as the default.
   bit isDefault = false;
+
+  // Prefix before the actual value. Used in the parser generation.
+  // `clause(prefix: value)`
+  string prefix = "";
+
+  // Set the prefix as optional.
+  // `clause([prefix]: value)`
+  bit isPrefixOptional = true;
 }
 
 // Hold information about clause validity by version.

diff  --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td
index 45d8158944549..e5f0632f59f50 100644
--- a/llvm/include/llvm/Frontend/OpenACC/ACC.td
+++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td
@@ -62,20 +62,24 @@ def ACCC_Collapse : Clause<"collapse"> {
 // 2.7.6
 def ACCC_Copy : Clause<"copy"> {
   let flangClass = "AccObjectList";
+  let aliases = ["present_or_copy", "pcopy"];
 }
 // 2.7.7
 def ACCC_Copyin : Clause<"copyin"> {
   let flangClass = "AccObjectListWithModifier";
+  let aliases = ["present_or_copyin", "pcopyin"];
 }
 
 // 2.7.8
 def ACCC_Copyout : Clause<"copyout"> {
   let flangClass = "AccObjectListWithModifier";
+  let aliases = ["present_or_copyout", "pcopyout"];
 }
 
 // 2.7.9
 def ACCC_Create : Clause<"create"> {
   let flangClass = "AccObjectListWithModifier";
+  let aliases = ["present_or_create", "pcreate"];
 }
 
 // 2.5.15
@@ -130,6 +134,7 @@ def ACCC_DeviceResident : Clause<"device_resident"> {
 def ACCC_DeviceType : Clause<"device_type"> {
   let flangClass = "AccDeviceTypeExprList";
   let defaultValue = "*";
+  let aliases = ["dtype"];
 }
 
 // 2.6.6
@@ -226,6 +231,7 @@ def ACCC_Seq : Clause<"seq"> {}
 def ACCC_Vector : Clause<"vector"> {
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
+  let prefix = "length";
 }
 
 // 2.5.11
@@ -243,6 +249,7 @@ def ACCC_Wait : Clause<"wait"> {
 def ACCC_Worker: Clause<"worker"> {
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
+  let prefix = "num";
 }
 
 // 2.12

diff  --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index d73b9ae49235f..e85c13f4b7cce 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -174,6 +174,16 @@ class Clause : public BaseRecord {
   }
 
   bool isImplicit() const { return Def->getValueAsBit("isImplicit"); }
+
+  std::vector<StringRef> getAliases() const {
+    return Def->getValueAsListOfStrings("aliases");
+  }
+
+  StringRef getPrefix() const { return Def->getValueAsString("prefix"); }
+
+  bool isPrefixOptional() const {
+    return Def->getValueAsBit("isPrefixOptional");
+  }
 };
 
 // Wrapper class that contains VersionedClause's information defined in

diff  --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index b5fc08c15a5d9..bc36b5f09ef9b 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -196,6 +196,16 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-EMPTY:
 // IMPL-NEXT:  #endif // GEN_FLANG_CLAUSE_PARSER_KIND_MAP
 // IMPL-EMPTY:
+// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSES_PARSER
+// IMPL-NEXT: #undef GEN_FLANG_CLAUSES_PARSER
+// IMPL-EMPTY:
+// IMPL-NEXT:  TYPE_PARSER(
+// IMPL-NEXT:    "clauseb" >> construct<TdlClause>(construct<TdlClause::Clauseb>(maybe(parenthesized(Parser<IntExpr>{})))) ||
+// IMPL-NEXT:    "clausea" >> construct<TdlClause>(construct<TdlClause::Clausea>())
+// IMPL-NEXT:  )
+// IMPL-EMPTY:
+// IMPL-NEXT:  #endif // GEN_FLANG_CLAUSES_PARSER
+// IMPL-EMPTY:
 // IMPL-NEXT:  #ifdef GEN_CLANG_CLAUSE_CLASS
 // IMPL-NEXT:  #undef GEN_CLANG_CLAUSE_CLASS
 // IMPL-EMPTY:

diff  --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index f3751591f3d95..be35baf4e809f 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -15,6 +15,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 
@@ -668,6 +669,85 @@ void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
      << " Parser clause\");\n";
 }
 
+bool compareClauseName(Record *R1, Record *R2) {
+  Clause C1{R1};
+  Clause C2{R2};
+  return (C1.getName() > C2.getName());
+}
+
+// Generate the parser for the clauses.
+void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
+                                raw_ostream &OS) {
+  std::vector<Record *> Clauses = DirLang.getClauses();
+  // Sort clauses in reverse alphabetical order so with clauses with same
+  // beginning, the longer option is tried before.
+  std::sort(Clauses.begin(), Clauses.end(), compareClauseName);
+  IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
+  OS << "\n";
+  unsigned index = 0;
+  unsigned lastClauseIndex = DirLang.getClauses().size() - 1;
+  OS << "TYPE_PARSER(\n";
+  for (const auto &C : Clauses) {
+    Clause Clause{C};
+    if (Clause.getAliases().empty()) {
+      OS << "  \"" << Clause.getName() << "\"";
+    } else {
+      OS << "  ("
+         << "\"" << Clause.getName() << "\"_tok";
+      for (StringRef alias : Clause.getAliases()) {
+        OS << " || \"" << alias << "\"_tok";
+      }
+      OS << ")";
+    }
+
+    OS << " >> construct<" << DirLang.getFlangClauseBaseClass()
+       << ">(construct<" << DirLang.getFlangClauseBaseClass()
+       << "::" << Clause.getFormattedParserClassName() << ">(";
+    if (Clause.getFlangClass().empty()) {
+      OS << "))";
+      if (index != lastClauseIndex)
+        OS << " ||";
+      OS << "\n";
+      ++index;
+      continue;
+    }
+
+    if (Clause.isValueOptional())
+      OS << "maybe(";
+    OS << "parenthesized(";
+
+    if (!Clause.getPrefix().empty())
+      OS << "\"" << Clause.getPrefix() << ":\" >> ";
+
+    // The common Flang parser are used directly. Their name is identical to
+    // the Flang class with first letter as lowercase. If the Flang class is
+    // not a common class, we assume there is a specific Parser<>{} with the
+    // Flang class name provided.
+    llvm::SmallString<128> Scratch;
+    StringRef Parser =
+        llvm::StringSwitch<StringRef>(Clause.getFlangClass())
+            .Case("Name", "name")
+            .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
+            .Case("ScalarIntExpr", "scalarIntExpr")
+            .Case("ScalarLogicalExpr", "scalarLogicalExpr")
+            .Default(("Parser<" + Clause.getFlangClass() + ">{}")
+                         .toStringRef(Scratch));
+    OS << Parser;
+    if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
+      OS << " || " << Parser;
+    OS << ")"; // close parenthesized(.
+
+    if (Clause.isValueOptional()) // close maybe(.
+      OS << ")";
+    OS << "))";
+    if (index != lastClauseIndex)
+      OS << " ||";
+    OS << "\n";
+    ++index;
+  }
+  OS << ")\n";
+}
+
 // Generate the implementation section for the enumeration in the directive
 // language
 void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
@@ -688,6 +768,8 @@ void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
   GenerateFlangClauseCheckPrototypes(DirLang, OS);
 
   GenerateFlangClauseParserKindMap(DirLang, OS);
+
+  GenerateFlangClausesParser(DirLang, OS);
 }
 
 void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,


        


More information about the flang-commits mailing list