[llvm] 3060894 - [flang][directives] Use TableGen to generate clause unparsing

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 17 11:22:33 PDT 2020


Author: Valentin Clement
Date: 2020-08-17T14:22:25-04:00
New Revision: 3060894bbb34937707d7db4d30485ecc98e62497

URL: https://github.com/llvm/llvm-project/commit/3060894bbb34937707d7db4d30485ecc98e62497
DIFF: https://github.com/llvm/llvm-project/commit/3060894bbb34937707d7db4d30485ecc98e62497.diff

LOG: [flang][directives] Use TableGen to generate clause unparsing

Use the TableGen directive back-end to generate code for the clauses unparsing.

Reviewed By: sscalpone, kiranchandramohan

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

Added: 
    

Modified: 
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/openmp-parsers.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    llvm/include/llvm/Frontend/Directive/DirectiveBase.td
    llvm/include/llvm/Frontend/OpenACC/ACC.td
    llvm/include/llvm/Frontend/OpenMP/OMP.td
    llvm/include/llvm/TableGen/DirectiveEmitter.h
    llvm/test/TableGen/directive1.td
    llvm/test/TableGen/directive2.td
    llvm/utils/TableGen/DirectiveEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 185a514e648f..e8c6244d7474 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -457,9 +457,9 @@ class ParseTreeDumper {
   NODE(parser, OmpCancelType)
   NODE_ENUM(OmpCancelType, Type)
   NODE(parser, OmpClause)
-  NODE(parser, OmpClauseList)
 #define GEN_FLANG_DUMP_PARSE_TREE_CLAUSES
 #include "llvm/Frontend/OpenMP/OMP.cpp.inc"
+  NODE(parser, OmpClauseList)
   NODE(parser, OmpCriticalDirective)
   NODE(OmpCriticalDirective, Hint)
   NODE(parser, OmpDeclareTargetSpecifier)
@@ -478,6 +478,7 @@ class ParseTreeDumper {
   NODE_ENUM(OmpDependenceType, Type)
   NODE(parser, OmpDependSinkVec)
   NODE(parser, OmpDependSinkVecLength)
+  NODE(parser, OmpDistScheduleClause)
   NODE(parser, OmpEndAtomic)
   NODE(parser, OmpEndBlockDirective)
   NODE(parser, OmpEndCriticalDirective)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 695121f83959..49e91789fdce 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3460,6 +3460,10 @@ struct OmpDependClause {
 // 2.7.1 nowait-clause -> NOWAIT
 EMPTY_CLASS(OmpNowait);
 
+// dist_schedule clause does not fit in generic clause class for tablegen.
+// Therefore it is declared separatly here.
+WRAPPER_CLASS(OmpDistScheduleClause, std::optional<ScalarIntExpr>);
+
 // OpenMP Clauses
 struct OmpClause {
   UNION_CLASS_BOILERPLATE(OmpClause);

diff  --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 2f0765617077..cd5ee0de556d 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -169,7 +169,7 @@ TYPE_PARSER("ALIGNED" >>
     "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
                     parenthesized(scalarIntExpr))) ||
     "DIST_SCHEDULE" >>
-        construct<OmpClause>(construct<OmpClause::DistSchedule>(
+        construct<OmpClause>(construct<OmpDistScheduleClause>(
             parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
                    parenthesized(scalarLogicalExpr))) ||

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 85ed1a2bd60b..3dbf8fb8d961 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1830,211 +1830,8 @@ class UnparseVisitor {
   void Unparse(const llvm::acc::Directive &x) {
     Word(llvm::acc::getOpenACCDirectiveName(x).str());
   }
-  void Before(const AccClause::Auto &) { Word("AUTO"); }
-  void Before(const AccClause::Capture &) { Word("CAPTURE"); }
-  void Before(const AccClause::Finalize &) { Word("FINALIZE"); }
-  void Before(const AccClause::IfPresent &) { Word("IF_PRESENT"); }
-  void Before(const AccClause::Independent &) { Word("INDEPENDENT"); }
-  void Before(const AccClause::Nohost &) { Word("NOHOST"); }
-  void Before(const AccClause::Read &) { Word("READ"); }
-  void Before(const AccClause::Seq &) { Word("SEQ"); }
-  void Before(const AccClause::Write &) { Word("WRITE"); }
-  void Before(const AccClause::Unknown &) { Word("UNKNOWN"); }
-  void Unparse(const AccClause::Attach &x) {
-    Word("ATTACH");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Bind &x) {
-    Word("BIND");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Collapse &x) {
-    Word("COLLAPSE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Copy &x) {
-    Word("COPY");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Copyin &x) {
-    Word("COPYIN");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Copyout &x) {
-    Word("COPYOUT");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Create &x) {
-    Word("CREATE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Default &x) {
-    Word("DEFAULT");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Delete &x) {
-    Word("DELETE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Detach &x) {
-    Word("DETACH");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Device &x) {
-    Word("DEVICE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Deviceptr &x) {
-    Word("DEVICEPTR");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::DeviceResident &x) {
-    Word("DEVICE_RESIDENT");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Firstprivate &x) {
-    Word("FIRSTPRIVATE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Host &x) {
-    Word("HOST");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::If &x) {
-    Word("IF");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Link &x) {
-    Word("LINK");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::NumGangs &x) {
-    Word("NUM_GANGS");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::NumWorkers &x) {
-    Word("NUM_WORKERS");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Present &x) {
-    Word("PRESENT");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Private &x) {
-    Word("PRIVATE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Reduction &x) {
-    Word("REDUCTION");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::VectorLength &x) {
-    Word("VECTOR_LENGTH");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Async &x) {
-    Word("ASYNC");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::DefaultAsync &x) {
-    Word("DEFAULT_ASYNC");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::DeviceNum &x) {
-    Word("DEVICE_NUM");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Gang &x) {
-    Word("GANG");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::NoCreate &x) {
-    Word("NO_CREATE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::UseDevice &x) {
-    Word("USE_DEVICE");
-    Put("(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const AccClause::Self &x) {
-    Word("SELF");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::Vector &x) {
-    Word("VECTOR");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::Wait &x) {
-    Word("WAIT");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::Worker &x) {
-    Word("WORKER");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const AccClause::DeviceType &x) {
-    Word("DEVICE_TYPE");
-    Put("(");
-    if (x.v.has_value())
-      Walk(x.v);
-    else
-      Put("*");
-    Put(")");
-  }
+#define GEN_FLANG_CLAUSE_UNPARSE
+#include "llvm/Frontend/OpenACC/ACC.cpp.inc"
   void Unparse(const AccObjectListWithModifier &x) {
     Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
     Walk(std::get<AccObjectList>(x.t));
@@ -2263,138 +2060,14 @@ class UnparseVisitor {
         std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
     Word(")");
   }
-  void Before(const OmpClause::Inbranch &) { Word("INBRANCH"); }
-  void Before(const OmpClause::Mergeable &) { Word("MERGEABLE"); }
-  void Before(const OmpClause::Nogroup &) { Word("NOGROUP"); }
-  void Before(const OmpClause::Notinbranch &) { Word("NOTINBRANCH"); }
-  void Before(const OmpClause::Untied &) { Word("UNTIED"); }
-  void Before(const OmpClause::Threads &) { Word("THREADS"); }
-  void Before(const OmpClause::Simd &) { Word("SIMD"); }
   void Unparse(const OmpNowait &) { Word("NOWAIT"); }
-  void Unparse(const OmpClause::Collapse &x) {
-    Word("COLLAPSE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Copyin &x) {
-    Word("COPYIN(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Copyprivate &x) {
-    Word("COPYPRIVATE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Device &x) {
-    Word("DEVICE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::DistSchedule &x) {
+  void Unparse(const OmpDistScheduleClause &x) {
     Word("DIST_SCHEDULE(STATIC");
     Walk(", ", x.v);
     Put(")");
   }
-  void Unparse(const OmpClause::Final &x) {
-    Word("FINAL(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Firstprivate &x) {
-    Word("FIRSTPRIVATE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::From &x) {
-    Word("FROM(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Grainsize &x) {
-    Word("GRAINSIZE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Lastprivate &x) {
-    Word("LASTPRIVATE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::NumTasks &x) {
-    Word("NUM_TASKS(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::NumTeams &x) {
-    Word("NUM_TEAMS(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::NumThreads &x) {
-    Word("NUM_THREADS(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Ordered &x) {
-    Word("ORDERED");
-    Walk("(", x.v, ")");
-  }
-  void Unparse(const OmpClause::Priority &x) {
-    Word("PRIORITY(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Private &x) {
-    Word("PRIVATE(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Safelen &x) {
-    Word("SAFELEN(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Simdlen &x) {
-    Word("SIMDLEN(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::ThreadLimit &x) {
-    Word("THREAD_LIMIT(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Shared &x) {
-    Word("SHARED(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::To &x) {
-    Word("TO(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Link &x) {
-    Word("LINK(");
-    Walk(x.v);
-    Put(")");
-  }
-  void Unparse(const OmpClause::Uniform &x) {
-    Word("UNIFORM(");
-    Walk(x.v, ",");
-    Put(")");
-  }
-  void Unparse(const OmpClause::UseDevicePtr &x) {
-    Word("USE_DEVICE_PTR(");
-    Walk(x.v, ",");
-    Put(")");
-  }
-  void Unparse(const OmpClause::IsDevicePtr &x) {
-    Word("IS_DEVICE_PTR(");
-    Walk(x.v, ",");
-    Put(")");
-  }
+#define GEN_FLANG_CLAUSE_UNPARSE
+#include "llvm/Frontend/OpenMP/OMP.cpp.inc"
   void Unparse(const OmpLoopDirective &x) {
     switch (x.v) {
     case llvm::omp::Directive::OMPD_distribute:

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index b4e4ad46ef95..6a4980ebcd54 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -355,7 +355,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &) {
 void OmpStructureChecker::Enter(const parser::OmpClause::Device &) {
   CheckAllowed(llvm::omp::Clause::OMPC_device);
 }
-void OmpStructureChecker::Enter(const parser::OmpClause::DistSchedule &) {
+void OmpStructureChecker::Enter(const parser::OmpDistScheduleClause &) {
   CheckAllowed(llvm::omp::Clause::OMPC_dist_schedule);
 }
 void OmpStructureChecker::Enter(const parser::OmpClause::Final &) {

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 4dc318429890..9a0c1e2c0a2d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -128,7 +128,6 @@ class OmpStructureChecker
   void Enter(const parser::OmpClause::Copyin &);
   void Enter(const parser::OmpClause::Copyprivate &);
   void Enter(const parser::OmpClause::Device &);
-  void Enter(const parser::OmpClause::DistSchedule &);
   void Enter(const parser::OmpClause::Final &);
   void Enter(const parser::OmpClause::Firstprivate &);
   void Enter(const parser::OmpClause::From &);
@@ -154,6 +153,7 @@ class OmpStructureChecker
   void Enter(const parser::OmpDefaultClause &);
   void Enter(const parser::OmpDefaultmapClause &);
   void Enter(const parser::OmpDependClause &);
+  void Enter(const parser::OmpDistScheduleClause &);
   void Enter(const parser::OmpIfClause &);
   void Enter(const parser::OmpLinearClause &);
   void Enter(const parser::OmpMapClause &);

diff  --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index b691bf8c3a7b..aa415b3f0abc 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -95,6 +95,11 @@ class Clause<string c> {
 
   // List of allowed clause values
   list<ClauseVal> allowedClauseValues = [];
+  // If set to 1, value class is part of a list. Single class by default.
+  bit isValueList = 0;
+
+  // Define a default value such as "*".
+  string defaultValue = "";
 
   // Is clause implicit? If clause is set as implicit, the default kind will
   // be return in get<LanguageName>ClauseKind instead of their own kind.

diff  --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td
index 4c686aad050b..d6ed93374013 100644
--- a/llvm/include/llvm/Frontend/OpenACC/ACC.td
+++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td
@@ -121,9 +121,10 @@ def ACCC_DeviceResident : Clause<"device_resident"> {
 
 // 2.4
 def ACCC_DeviceType : Clause<"device_type"> {
-  // (DeviceType, "*"
-  let flangClassValue = "std::list<Name>";
+  let flangClassValue = "Name";
+  let defaultValue = "*";
   let isValueOptional = 1;
+  let isValueList = 1;
 }
 
 // 2.6.6

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 2e392156766c..de1651369ebc 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -184,6 +184,7 @@ def OMPC_Hint : Clause<"hint"> {
 }
 def OMPC_DistSchedule : Clause<"dist_schedule"> {
   let clangClass = "OMPDistScheduleClause";
+  let flangClass = "OmpDistScheduleClause";
   let flangClassValue = "ScalarIntExpr";
   let isValueOptional = 1;
 }
@@ -201,11 +202,13 @@ def OMPC_From : Clause<"from"> {
 }
 def OMPC_UseDevicePtr : Clause<"use_device_ptr"> {
   let clangClass = "OMPUseDevicePtrClause";
-  let flangClassValue = "std::list<Name>";
+  let flangClassValue = "Name";
+  let isValueList = 1;
 }
 def OMPC_IsDevicePtr : Clause<"is_device_ptr"> {
   let clangClass = "OMPIsDevicePtrClause";
-  let flangClassValue = "std::list<Name>";
+  let flangClassValue = "Name";
+  let isValueList = 1;
 }
 def OMPC_TaskReduction : Clause<"task_reduction"> {
   let clangClass = "OMPTaskReductionClause";
@@ -260,7 +263,8 @@ def OMPC_UseDeviceAddr : Clause<"use_device_addr"> {
   let clangClass = "OMPUseDeviceAddrClause";
 }
 def OMPC_Uniform : Clause<"uniform"> {
-  let flangClassValue = "std::list<Name>";
+  let flangClassValue = "Name";
+  let isValueList = 1;
 }
 def OMPC_DeviceType : Clause<"device_type"> {}
 def OMPC_Match : Clause<"match"> {}

diff  --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 8a7664afa98b..0964e7b144c8 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -154,6 +154,12 @@ class Clause : public BaseRecord {
 
   bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); }
 
+  bool isValueList() const { return Def->getValueAsBit("isValueList"); }
+
+  StringRef getDefaultValue() const {
+    return Def->getValueAsString("defaultValue");
+  }
+
   bool isImplict() const { return Def->getValueAsBit("isImplicit"); }
 };
 

diff  --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index 268999e3f0ce..5d9be74e9fce 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -231,5 +231,13 @@ def TDL_DirA : Directive<"dira"> {
 // GEN-NEXT:  NODE(TdlClause, Clauseb)
 // GEN-EMPTY:
 // GEN-NEXT:  #endif // GEN_FLANG_DUMP_PARSE_TREE_CLAUSES
-
-
+// GEN-EMPTY:
+// GEN-NEXT:  #ifdef GEN_FLANG_CLAUSE_UNPARSE
+// GEN-NEXT:  #undef GEN_FLANG_CLAUSE_UNPARSE
+// GEN-EMPTY:
+// GEN-NEXT:  void Unparse(const TdlClause::Clauseb &x) {
+// GEN-NEXT:    Word("CLAUSEB");
+// GEN-NEXT:    Walk("(", x.v, ")");
+// GEN-NEXT:  }
+// GEN-EMPTY:
+// GEN-NEXT:  #endif // GEN_FLANG_CLAUSE_UNPARSE

diff  --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 685fa6a351bf..bf5ec02d5f0c 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -20,6 +20,12 @@ def TDLC_ClauseA : Clause<"clausea"> {
 def TDLC_ClauseB : Clause<"clauseb"> {
   let isDefault = 1;
   let flangClassValue = "IntExpr";
+  let isValueList = 1;
+}
+def TDLC_ClauseC : Clause<"clausec"> {
+  let flangClassValue = "Name";
+  let defaultValue = "*";
+  let isValueOptional = 1;
 }
 
 def TDL_DirA : Directive<"dira"> {
@@ -46,9 +52,10 @@ def TDL_DirA : Directive<"dira"> {
 // CHECK-NEXT:  enum class Clause {
 // CHECK-NEXT:    TDLC_clausea,
 // CHECK-NEXT:    TDLC_clauseb,
+// CHECK-NEXT:    TDLC_clausec,
 // CHECK-NEXT:  };
 // CHECK-EMPTY:
-// CHECK-NEXT:  static constexpr std::size_t Clause_enumSize = 2;
+// CHECK-NEXT:  static constexpr std::size_t Clause_enumSize = 3;
 // CHECK-EMPTY:
 // CHECK-NEXT:  // Enumeration helper functions
 // CHECK-NEXT:  Directive getTdlDirectiveKind(llvm::StringRef Str);
@@ -93,6 +100,7 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:    return llvm::StringSwitch<Clause>(Str)
 // IMPL-NEXT:      .Case("clausea",TDLC_clauseb)
 // IMPL-NEXT:      .Case("clauseb",TDLC_clauseb)
+// IMPL-NEXT:      .Case("clausec",TDLC_clausec)
 // IMPL-NEXT:      .Default(TDLC_clauseb);
 // IMPL-NEXT:  }
 // IMPL-EMPTY:
@@ -102,6 +110,8 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:        return "clausea";
 // IMPL-NEXT:      case TDLC_clauseb:
 // IMPL-NEXT:        return "clauseb";
+// IMPL-NEXT:      case TDLC_clausec:
+// IMPL-NEXT:        return "clausec";
 // IMPL-NEXT:    }
 // IMPL-NEXT:    llvm_unreachable("Invalid Tdl Clause kind");
 // IMPL-NEXT:  }
@@ -171,7 +181,8 @@ def TDL_DirA : Directive<"dira"> {
 // GEN-NEXT:  #undef GEN_FLANG_CLAUSE_PARSER_CLASSES
 // GEN-EMPTY:
 // GEN-NEXT:  EMPTY_CLASS(Clausea);
-// GEN-NEXT:  WRAPPER_CLASS(Clauseb, IntExpr);
+// GEN-NEXT:  WRAPPER_CLASS(Clauseb, std::list<IntExpr>);
+// GEN-NEXT:  WRAPPER_CLASS(Clausec, std::optional<Name>);
 // GEN-EMPTY:
 // GEN-NEXT:  #endif // GEN_FLANG_CLAUSE_PARSER_CLASSES
 // GEN-EMPTY:
@@ -180,6 +191,7 @@ def TDL_DirA : Directive<"dira"> {
 // GEN-EMPTY:
 // GEN-NEXT:  Clausea
 // GEN-NEXT:  , Clauseb
+// GEN-NEXT:  , Clausec
 // GEN-EMPTY:
 // GEN-NEXT:  #endif // GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST
 // GEN-EMPTY:
@@ -188,5 +200,28 @@ def TDL_DirA : Directive<"dira"> {
 // GEN-EMPTY:
 // GEN-NEXT:  NODE(TdlClause, Clausea)
 // GEN-NEXT:  NODE(TdlClause, Clauseb)
-// GEN-EMPTY:
-// GEN-NEXT:  #endif // GEN_FLANG_DUMP_PARSE_TREE_CLAUSES
\ No newline at end of file
+// GEN-NEXT:  NODE(TdlClause, Clausec)
+// GEN-EMPTY:
+// GEN-NEXT:  #endif // GEN_FLANG_DUMP_PARSE_TREE_CLAUSES
+// GEN-EMPTY:
+// GEN-NEXT:  #ifdef GEN_FLANG_CLAUSE_UNPARSE
+// GEN-NEXT:  #undef GEN_FLANG_CLAUSE_UNPARSE
+// GEN-EMPTY:
+// GEN-NEXT:  void Before(const TdlClause::Clausea &) { Word("CLAUSEA"); }
+// GEN-NEXT:  void Unparse(const TdlClause::Clauseb &x) {
+// GEN-NEXT:    Word("CLAUSEB");
+// GEN-NEXT:    Put("(");
+// GEN-NEXT:    Walk(x.v, ",");
+// GEN-NEXT:    Put(")");
+// GEN-NEXT:  }
+// GEN-NEXT:  void Unparse(const TdlClause::Clausec &x) {
+// GEN-NEXT:  Word("CLAUSEC");
+// GEN-NEXT:    Put("(");
+// GEN-NEXT:    if (x.v.has_value())
+// GEN-NEXT:    Walk(x.v);
+// GEN-NEXT:    else
+// GEN-NEXT:    Put("*");
+// GEN-NEXT:    Put(")");
+// GEN-NEXT:  }
+// GEN-EMPTY:
+// GEN-NEXT:  #endif // GEN_FLANG_CLAUSE_UNPARSE

diff  --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index d89b17510113..426a2c76b50e 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -471,18 +471,22 @@ void GenerateFlangClauseParserClass(const std::vector<Record *> &Clauses,
     // Clause has a non generic class.
     if (!Clause.getFlangClass().empty())
       continue;
-    // G
     if (!Clause.getFlangClassValue().empty()) {
-      if (Clause.isValueOptional()) {
-        OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName()
-           << ", std::optional<" << Clause.getFlangClassValue() << ">);\n";
+      OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
+      if (Clause.isValueOptional() && Clause.isValueList()) {
+        OS << "std::optional<std::list<" << Clause.getFlangClassValue()
+           << ">>";
+      } else if (Clause.isValueOptional()) {
+        OS << "std::optional<" << Clause.getFlangClassValue() << ">";
+      } else if (Clause.isValueList()) {
+        OS << "std::list<" << Clause.getFlangClassValue() << ">";
       } else {
-        OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "
-           << Clause.getFlangClassValue() << ");\n";
+        OS << Clause.getFlangClassValue();
       }
     } else {
-      OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName() << ");\n";
+      OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
     }
+    OS << ");\n";
   }
 }
 
@@ -521,6 +525,63 @@ void GenerateFlangClauseDump(const std::vector<Record *> &Clauses,
   }
 }
 
+// Generate Unparse functions for clauses classes in the Flang parse-tree
+// If the clause is a non-generic class, no entry is generated.
+void GenerateFlangClauseUnparse(const std::vector<Record *> &Clauses,
+                                const DirectiveLanguage &DirLang,
+                                raw_ostream &OS) {
+
+  IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
+
+  OS << "\n";
+
+  for (const auto &C : Clauses) {
+    Clause Clause{C};
+    // Clause has a non generic class.
+    if (!Clause.getFlangClass().empty())
+      continue;
+    if (!Clause.getFlangClassValue().empty()) {
+      if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
+        OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+           << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+        OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
+
+        OS << "  Walk(\"(\", x.v, \")\");\n";
+        OS << "}\n";
+      } else if (Clause.isValueOptional()) {
+        OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+           << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+        OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
+        OS << "  Put(\"(\");\n";
+        OS << "  if (x.v.has_value())\n";
+        if (Clause.isValueList())
+          OS << "    Walk(x.v, \",\");\n";
+        else
+          OS << "    Walk(x.v);\n";
+        OS << "  else\n";
+        OS << "    Put(\"" << Clause.getDefaultValue() << "\");\n";
+        OS << "  Put(\")\");\n";
+        OS << "}\n";
+      } else {
+        OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
+           << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
+        OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
+        OS << "  Put(\"(\");\n";
+        if (Clause.isValueList())
+          OS << "  Walk(x.v, \",\");\n";
+        else
+          OS << "  Walk(x.v);\n";
+        OS << "  Put(\")\");\n";
+        OS << "}\n";
+      }
+    } else {
+      OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
+         << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
+         << Clause.getName().upper() << "\"); }\n";
+    }
+  }
+}
+
 // Generate the implemenation section for the enumeration in the directive
 // language
 void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives,
@@ -537,6 +598,8 @@ void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives,
   GenerateFlangClauseParserClassList(Clauses, OS);
 
   GenerateFlangClauseDump(Clauses, DirectiveLanguage, OS);
+
+  GenerateFlangClauseUnparse(Clauses, DirectiveLanguage, OS);
 }
 
 // Generate the implemenation section for the enumeration in the directive


        


More information about the llvm-commits mailing list