[llvm] r327121 - TableGen: Add a defset statement

Nicolai Haehnle via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 9 04:24:42 PST 2018


Author: nha
Date: Fri Mar  9 04:24:42 2018
New Revision: 327121

URL: http://llvm.org/viewvc/llvm-project?rev=327121&view=rev
Log:
TableGen: Add a defset statement

Allows capturing a list of concrete instantiated defs.

This can be combined with foreach to create parallel sets of def
instantiations with less repetition in the source. This purpose is
largely also served by multiclasses, but in some cases multiclasses
can't be used.

The motivating example for this change is having a large set of
intrinsics, which are generated from the IntrinsicsBackend.td file
included by Intrinsics.td, and a corresponding set of instruction
selection patterns, which are generated via the backend's .td files.

Multiclasses cannot be used to eliminate the redundancy in this case,
because a multiclass cannot span both LLVM's common .td files and
the backend .td files at the same time.

Change-Id: I879e35042dceea542a5e6776fad23c5e0e69e76b

Differential revision: https://reviews.llvm.org/D44109

Added:
    llvm/trunk/test/TableGen/defset-typeerror.td
    llvm/trunk/test/TableGen/defset.td
Modified:
    llvm/trunk/docs/TableGen/LangRef.rst
    llvm/trunk/include/llvm/TableGen/Record.h
    llvm/trunk/lib/TableGen/TGLexer.cpp
    llvm/trunk/lib/TableGen/TGLexer.h
    llvm/trunk/lib/TableGen/TGParser.cpp
    llvm/trunk/lib/TableGen/TGParser.h

Modified: llvm/trunk/docs/TableGen/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/TableGen/LangRef.rst?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/docs/TableGen/LangRef.rst (original)
+++ llvm/trunk/docs/TableGen/LangRef.rst Fri Mar  9 04:24:42 2018
@@ -116,7 +116,8 @@ TableGen's top-level production consists
 
 .. productionlist::
    TableGenFile: `Object`*
-   Object: `Class` | `Def` | `Defm` | `Let` | `MultiClass` | `Foreach`
+   Object: `Class` | `Def` | `Defm` | `Defset` | `Let` | `MultiClass` |
+           `Foreach`
 
 ``class``\es
 ------------
@@ -356,6 +357,21 @@ a ``foreach``.
 Note that in the :token:`BaseClassList`, all of the ``multiclass``'s must
 precede any ``class``'s that appear.
 
+``defset``
+----------
+.. productionlist::
+   Defset: "defset" `Type` `TokIdentifier` "=" "{" `Object`* "}"
+
+All records defined inside the braces via ``def`` and ``defm`` are collected
+in a globally accessible list of the given name (in addition to being added
+to the global collection of records as usual). Anonymous records created inside
+initializier expressions using the ``Class<args...>`` syntax are never collected
+in a defset.
+
+The given type must be ``list<A>``, where ``A`` is some class. It is an error
+to define a record (via ``def`` or ``defm``) inside the braces which doesn't
+derive from ``A``.
+
 ``foreach``
 -----------
 

Modified: llvm/trunk/include/llvm/TableGen/Record.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/TableGen/Record.h?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/include/llvm/TableGen/Record.h (original)
+++ llvm/trunk/include/llvm/TableGen/Record.h Fri Mar  9 04:24:42 2018
@@ -1612,6 +1612,7 @@ class RecordKeeper {
   using RecordMap = std::map<std::string, std::unique_ptr<Record>>;
   RecordMap Classes, Defs;
   FoldingSet<RecordRecTy> RecordTypePool;
+  std::map<std::string, Init *> ExtraGlobals;
   unsigned AnonCounter = 0;
 
 public:
@@ -1628,6 +1629,13 @@ public:
     return I == Defs.end() ? nullptr : I->second.get();
   }
 
+  Init *getGlobal(StringRef Name) const {
+    if (Record *R = getDef(Name))
+      return R->getDefInit();
+    auto It = ExtraGlobals.find(Name);
+    return It == ExtraGlobals.end() ? nullptr : It->second;
+  }
+
   void addClass(std::unique_ptr<Record> R) {
     bool Ins = Classes.insert(std::make_pair(R->getName(),
                                              std::move(R))).second;
@@ -1642,6 +1650,13 @@ public:
     assert(Ins && "Record already exists");
   }
 
+  void addExtraGlobal(StringRef Name, Init *I) {
+    bool Ins = ExtraGlobals.insert(std::make_pair(Name, I)).second;
+    (void)Ins;
+    assert(!getDef(Name));
+    assert(Ins && "Global already exists");
+  }
+
   Init *getNewAnonymousName();
 
   //===--------------------------------------------------------------------===//

Modified: llvm/trunk/lib/TableGen/TGLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGLexer.cpp?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGLexer.cpp (original)
+++ llvm/trunk/lib/TableGen/TGLexer.cpp Fri Mar  9 04:24:42 2018
@@ -276,6 +276,7 @@ tgtok::TokKind TGLexer::LexIdentifier()
     .Case("def", tgtok::Def)
     .Case("foreach", tgtok::Foreach)
     .Case("defm", tgtok::Defm)
+    .Case("defset", tgtok::Defset)
     .Case("multiclass", tgtok::MultiClass)
     .Case("field", tgtok::Field)
     .Case("let", tgtok::Let)

Modified: llvm/trunk/lib/TableGen/TGLexer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGLexer.h?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGLexer.h (original)
+++ llvm/trunk/lib/TableGen/TGLexer.h Fri Mar  9 04:24:42 2018
@@ -44,7 +44,7 @@ namespace tgtok {
 
     // Keywords.
     Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List,
-    MultiClass, String,
+    MultiClass, String, Defset,
 
     // !keywords.
     XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast,

Modified: llvm/trunk/lib/TableGen/TGParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.cpp?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGParser.cpp (original)
+++ llvm/trunk/lib/TableGen/TGParser.cpp Fri Mar  9 04:24:42 2018
@@ -413,6 +413,8 @@ bool TGParser::ProcessForeachDefs(Record
   Records.addDef(std::move(IterRec));
   IterRecSave->resolveReferences();
   checkConcrete(*IterRecSave);
+  if (addToDefsets(*IterRecSave))
+    return true;
   return false;
 }
 
@@ -422,9 +424,9 @@ bool TGParser::ProcessForeachDefs(Record
 
 /// isObjectStart - Return true if this is a valid first token for an Object.
 static bool isObjectStart(tgtok::TokKind K) {
-  return K == tgtok::Class || K == tgtok::Def ||
-         K == tgtok::Defm || K == tgtok::Let ||
-         K == tgtok::MultiClass || K == tgtok::Foreach;
+  return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm ||
+         K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach ||
+         K == tgtok::Defset;
 }
 
 /// ParseObjectName - If an object name is specified, return it.  Otherwise,
@@ -724,6 +726,7 @@ RecTy *TGParser::ParseType() {
   case tgtok::Dag:    Lex.Lex(); return DagRecTy::get();
   case tgtok::Id:
     if (Record *R = ParseClassID()) return RecordRecTy::get(R);
+    TokError("unknown class name");
     return nullptr;
   case tgtok::Bits: {
     if (Lex.Lex() != tgtok::less) { // Eat 'bits'
@@ -805,8 +808,8 @@ Init *TGParser::ParseIDValue(Record *Cur
   if (Mode == ParseNameMode)
     return Name;
 
-  if (Record *D = Records.getDef(Name->getValue()))
-    return DefInit::get(D);
+  if (Init *I = Records.getGlobal(Name->getValue()))
+    return I;
 
   if (Mode == ParseValueMode) {
     Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
@@ -2323,8 +2326,11 @@ bool TGParser::ParseDef(MultiClass *CurM
     // for the def that might have been created when resolving
     // inheritance, values and arguments above.
     CurRec->resolveReferences();
-    if (Loops.empty())
+    if (Loops.empty()) {
       checkConcrete(*CurRec);
+      if (addToDefsets(*CurRec))
+        return true;
+    }
   }
 
   // If ObjectBody has template arguments, it's an error.
@@ -2346,6 +2352,68 @@ bool TGParser::ParseDef(MultiClass *CurM
   return false;
 }
 
+bool TGParser::addToDefsets(Record &R) {
+  for (DefsetRecord *Defset : Defsets) {
+    DefInit *I = R.getDefInit();
+    if (!I->getType()->typeIsA(Defset->EltTy)) {
+      PrintError(R.getLoc(),
+                 Twine("adding record of incompatible type '") +
+                 I->getType()->getAsString() + "' to defset");
+      PrintNote(Defset->Loc, "to this defset");
+      return true;
+    }
+    Defset->Elements.push_back(I);
+  }
+  return false;
+}
+
+/// ParseDefset - Parse a defset statement.
+///
+///   Defset ::= DEFSET Type Id '=' '{' ObjectList '}'
+///
+bool TGParser::ParseDefset() {
+  assert(Lex.getCode() == tgtok::Defset);
+  Lex.Lex(); // Eat the 'defset' token
+
+  DefsetRecord Defset;
+  Defset.Loc = Lex.getLoc();
+  RecTy *Type = ParseType();
+  if (!Type)
+    return true;
+  if (!isa<ListRecTy>(Type))
+    return Error(Defset.Loc, "expected list type");
+  Defset.EltTy = cast<ListRecTy>(Type)->getElementType();
+
+  if (Lex.getCode() != tgtok::Id)
+    return TokError("expected identifier");
+  StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
+  if (Records.getGlobal(DeclName->getValue()))
+    return TokError("def or global variable of this name already exists");
+
+  if (Lex.Lex() != tgtok::equal) // Eat the identifier
+    return TokError("expected '='");
+  if (Lex.Lex() != tgtok::l_brace) // Eat the '='
+    return TokError("expected '{'");
+  SMLoc BraceLoc = Lex.getLoc();
+  Lex.Lex(); // Eat the '{'
+
+  Defsets.push_back(&Defset);
+  bool Err = ParseObjectList(nullptr);
+  Defsets.pop_back();
+  if (Err)
+    return true;
+
+  if (Lex.getCode() != tgtok::r_brace) {
+    TokError("expected '}' at end of defset");
+    return Error(BraceLoc, "to match this '{'");
+  }
+  Lex.Lex();  // Eat the '}'
+
+  Records.addExtraGlobal(DeclName->getValue(),
+                         ListInit::get(Defset.Elements, Defset.EltTy));
+  return false;
+}
+
 /// ParseForeach - Parse a for statement.  Return the record corresponding
 /// to it.  This returns true on error.
 ///
@@ -2598,7 +2666,8 @@ bool TGParser::ParseMultiClass() {
     while (Lex.getCode() != tgtok::r_brace) {
       switch (Lex.getCode()) {
       default:
-        return TokError("expected 'let', 'def' or 'defm' in multiclass body");
+        return TokError("expected 'let', 'def', 'defm' or 'foreach' in "
+                        "multiclass body");
       case tgtok::Let:
       case tgtok::Def:
       case tgtok::Defm:
@@ -2919,6 +2988,8 @@ bool TGParser::ParseDefm(MultiClass *Cur
       // inheritance, values and arguments above.
       CurRec->resolveReferences();
       checkConcrete(*CurRec);
+      if (addToDefsets(*CurRec))
+        return true;
     }
   }
 
@@ -2939,11 +3010,16 @@ bool TGParser::ParseDefm(MultiClass *Cur
 bool TGParser::ParseObject(MultiClass *MC) {
   switch (Lex.getCode()) {
   default:
-    return TokError("Expected class, def, defm, multiclass or let definition");
+    return TokError("Expected class, def, defm, defset, multiclass, let or "
+                    "foreach");
   case tgtok::Let:   return ParseTopLevelLet(MC);
   case tgtok::Def:   return ParseDef(MC);
   case tgtok::Foreach:   return ParseForeach(MC);
   case tgtok::Defm:  return ParseDefm(MC);
+  case tgtok::Defset:
+    if (MC)
+      return TokError("defset is not allowed inside multiclass");
+    return ParseDefset();
   case tgtok::Class: return ParseClass();
   case tgtok::MultiClass: return ParseMultiClass();
   }

Modified: llvm/trunk/lib/TableGen/TGParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.h?rev=327121&r1=327120&r2=327121&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGParser.h (original)
+++ llvm/trunk/lib/TableGen/TGParser.h Fri Mar  9 04:24:42 2018
@@ -51,6 +51,12 @@ namespace llvm {
       : IterVar(IVar), ListValue(LValue) {}
   };
 
+  struct DefsetRecord {
+    SMLoc Loc;
+    RecTy *EltTy;
+    SmallVector<Init *, 16> Elements;
+  };
+
 class TGParser {
   TGLexer Lex;
   std::vector<SmallVector<LetRecord, 4>> LetStack;
@@ -61,6 +67,8 @@ class TGParser {
   typedef std::vector<ForeachLoop> LoopVector;
   LoopVector Loops;
 
+  SmallVector<DefsetRecord *, 2> Defsets;
+
   /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the
   /// current value.
   MultiClass *CurMultiClass;
@@ -121,6 +129,8 @@ private:  // Semantic analysis methods.
   bool ProcessForeachDefs(Record *CurRec, SMLoc Loc);
   bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals);
 
+  bool addToDefsets(Record &R);
+
 private:  // Parser methods.
   bool ParseObjectList(MultiClass *MC = nullptr);
   bool ParseObject(MultiClass *MC);
@@ -140,6 +150,7 @@ private:  // Parser methods.
                             SMLoc DefmPrefixLoc);
   bool ParseDefm(MultiClass *CurMultiClass);
   bool ParseDef(MultiClass *CurMultiClass);
+  bool ParseDefset();
   bool ParseForeach(MultiClass *CurMultiClass);
   bool ParseTopLevelLet(MultiClass *CurMultiClass);
   void ParseLetList(SmallVectorImpl<LetRecord> &Result);

Added: llvm/trunk/test/TableGen/defset-typeerror.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/defset-typeerror.td?rev=327121&view=auto
==============================================================================
--- llvm/trunk/test/TableGen/defset-typeerror.td (added)
+++ llvm/trunk/test/TableGen/defset-typeerror.td Fri Mar  9 04:24:42 2018
@@ -0,0 +1,14 @@
+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: error: adding record of incompatible type 'A' to defset
+
+class A<int a> {
+  int Num = a;
+}
+
+class B<int a> : A<a>;
+
+defset list<B> Bs = {
+  def A0 : A<1>;
+}

Added: llvm/trunk/test/TableGen/defset.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/defset.td?rev=327121&view=auto
==============================================================================
--- llvm/trunk/test/TableGen/defset.td (added)
+++ llvm/trunk/test/TableGen/defset.td Fri Mar  9 04:24:42 2018
@@ -0,0 +1,62 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: --- Defs ---
+
+// CHECK: def Sum {
+// CHECK:   int x = 712;
+// CHECK: }
+
+// CHECK: def yyy_A0
+// CHECK: def yyy_A1
+// CHECK: def yyy_A2
+// CHECK: def yyy_B0A0
+// CHECK: def yyy_B0A1
+// CHECK: def yyy_C0B0A0
+// CHECK: def yyy_C0B0A1
+// CHECK: def yyy_C0B1A0
+// CHECK: def yyy_C0B1A1
+// CHECK-NOT: def zzz_A0
+// CHECK: def zzz_B0A0
+// CHECK: def zzz_B0A1
+// CHECK: def zzz_C0B0A0
+// CHECK: def zzz_C0B0A1
+// CHECK: def zzz_C0B1A0
+// CHECK: def zzz_C0B1A1
+
+class A<int a> {
+  int Num = a;
+}
+
+multiclass B<int b> {
+  def A0 : A<!add(10, b)>;
+  def A1 : A<!add(20, b)>;
+}
+
+multiclass C<int c> {
+  defm B0 : B<!add(100, c)>;
+  defm B1 : B<!add(200, c)>;
+}
+
+defset list<A> As = {
+  def A0 : A<1>;
+  foreach i = 1-2 in {
+    def A#i : A<!add(i, 1)>;
+  }
+  defset list<A> SubAs = {
+    defm B0 : B<2>;
+    defm C0 : C<3>;
+  }
+}
+
+def Sum {
+  int x = !foldl(0, As, a, b, !add(a, b.Num));
+}
+
+foreach a = As in {
+  def yyy_ # !cast<string>(a);
+}
+
+foreach a = SubAs in {
+  def zzz_ # !cast<string>(a);
+}




More information about the llvm-commits mailing list