[llvm] dc5d663 - [TableGen] Enhance !empty and !size to handle strings and DAGs.

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 19 06:23:45 PDT 2020


Author: Paul C. Anagnostopoulos
Date: 2020-10-19T09:22:20-04:00
New Revision: dc5d6632b0c25cc5c057325c517f28575452d602

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

LOG: [TableGen] Enhance !empty and !size to handle strings and DAGs.
Fix bug in the type checking for !empty, !head, !size, !tail.

Added: 
    llvm/test/TableGen/empty.td

Modified: 
    llvm/docs/TableGen/ProgRef.rst
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TGParser.cpp
    llvm/test/TableGen/size.td

Removed: 
    


################################################################################
diff  --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index a70f54c0706b..fa9989d77a24 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -274,7 +274,7 @@ wide range of records conveniently and compactly.
     the programmer's intention.
 
 ``bits<``\ *n*\ ``>``
-    The ``bits`` type is a fixed-size integer of arbitrary length *n* that
+    The ``bits`` type is a fixed-sized integer of arbitrary length *n* that
     is treated as separate bits. These bits can be accessed individually.
     A field of this type is useful for representing an instruction operation
     code, register number, or address mode/register/displacement.  The bits of
@@ -1242,8 +1242,8 @@ a name is to tag an operator or argument in a DAG with a particular meaning,
 or to associate an argument in one DAG with a like-named argument in another
 DAG.
 
-The following bang operators manipulate DAGs: ``!con``, ``!dag``, ``!foreach``, 
-``!getop``, ``!setop``.
+The following bang operators are useful for working with DAGs:
+``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getop``, ``!setop``, ``!size``.
 
 Defvar in a record body
 -----------------------
@@ -1509,8 +1509,9 @@ and non-0 as true.
     Example: ``!dag(op, [a1, a2, ?], ["name1", "name2", "name3"])`` results in
     ``(op a1:$name1, a2:$name2, ?:$name3)``.
 
-``!empty(``\ *list*\ ``)``
-    This operator produces 1 if the *list* is empty; 0 otherwise.
+``!empty(``\ *a*\ ``)``
+    This operator produces 1 if the string, list, or DAG *a* is empty; 0 otherwise.
+    A dag is empty if it has no arguments; the operator does not count.
 
 ``!eq(`` *a*\ `,` *b*\ ``)``
     This operator produces 1 if *a* is equal to *b*; 0 otherwise.
@@ -1631,7 +1632,8 @@ and non-0 as true.
     is undefined for shift counts outside 0...63.
 
 ``!size(``\ *a*\ ``)``
-    This operator produces the number of elements in the list *a*.
+    This operator produces the size of the string, list, or dag *a*.
+    The size of a DAG is the number of arguments; the operator does not count.
 
 ``!sra(``\ *a*\ ``,`` *count*\ ``)``
     This operator shifts *a* right arithmetically by *count* bits and produces the resulting

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index f191638083c4..d404a42134f5 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -786,11 +786,17 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
   case SIZE:
     if (ListInit *LHSl = dyn_cast<ListInit>(LHS))
       return IntInit::get(LHSl->size());
+    if (DagInit *LHSd = dyn_cast<DagInit>(LHS))
+      return IntInit::get(LHSd->arg_size());
+    if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
+      return IntInit::get(LHSs->getValue().size());
     break;
 
   case EMPTY:
     if (ListInit *LHSl = dyn_cast<ListInit>(LHS))
       return IntInit::get(LHSl->empty());
+    if (DagInit *LHSd = dyn_cast<DagInit>(LHS))
+      return IntInit::get(LHSd->arg_empty());
     if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
       return IntInit::get(LHSs->getValue().empty());
     break;

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 98443c97a159..83a2ba19f810 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -986,56 +986,58 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     Init *LHS = ParseValue(CurRec);
     if (!LHS) return nullptr;
 
-    if (Code == UnOpInit::HEAD ||
-        Code == UnOpInit::TAIL ||
-        Code == UnOpInit::EMPTY) {
+    if (Code == UnOpInit::EMPTY || Code == UnOpInit::SIZE) {
       ListInit *LHSl = dyn_cast<ListInit>(LHS);
       StringInit *LHSs = dyn_cast<StringInit>(LHS);
+      DagInit *LHSd = dyn_cast<DagInit>(LHS);
       TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
-      if (!LHSl && !LHSs && !LHSt) {
-        TokError("expected list or string type argument in unary operator");
+      if (!LHSl && !LHSs && !LHSd && !LHSt) {
+        TokError("expected string, list, or dag type argument in unary operator");
         return nullptr;
       }
       if (LHSt) {
         ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
         StringRecTy *SType = dyn_cast<StringRecTy>(LHSt->getType());
-        if (!LType && !SType) {
-          TokError("expected list or string type argument in unary operator");
+        DagRecTy *DType = dyn_cast<DagRecTy>(LHSt->getType());
+        if (!LType && !SType && !DType) {
+          TokError("expected string, list, or dag type argument in unary operator");
           return nullptr;
         }
       }
+    }
 
-      if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL ||
-          Code == UnOpInit::SIZE) {
-        if (!LHSl && !LHSt) {
+    if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) {
+      ListInit *LHSl = dyn_cast<ListInit>(LHS);
+      TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
+      if (!LHSl && !LHSt) {
+        TokError("expected list type argument in unary operator");
+        return nullptr;
+      }
+      if (LHSt) {
+        ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
+        if (!LType) {
           TokError("expected list type argument in unary operator");
           return nullptr;
         }
       }
 
-      if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) {
-        if (LHSl && LHSl->empty()) {
-          TokError("empty list argument in unary operator");
+      if (LHSl && LHSl->empty()) {
+        TokError("empty list argument in unary operator");
+        return nullptr;
+      }
+      if (LHSl) {
+        Init *Item = LHSl->getElement(0);
+        TypedInit *Itemt = dyn_cast<TypedInit>(Item);
+        if (!Itemt) {
+          TokError("untyped list element in unary operator");
           return nullptr;
         }
-        if (LHSl) {
-          Init *Item = LHSl->getElement(0);
-          TypedInit *Itemt = dyn_cast<TypedInit>(Item);
-          if (!Itemt) {
-            TokError("untyped list element in unary operator");
-            return nullptr;
-          }
-          Type = (Code == UnOpInit::HEAD) ? Itemt->getType()
-                                          : ListRecTy::get(Itemt->getType());
-        } else {
-          assert(LHSt && "expected list type argument in unary operator");
-          ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
-          if (!LType) {
-            TokError("expected list type argument in unary operator");
-            return nullptr;
-          }
-          Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType;
-        }
+        Type = (Code == UnOpInit::HEAD) ? Itemt->getType()
+                                        : ListRecTy::get(Itemt->getType());
+      } else {
+        assert(LHSt && "expected list type argument in unary operator");
+        ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
+        Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType;
       }
     }
 

diff  --git a/llvm/test/TableGen/empty.td b/llvm/test/TableGen/empty.td
new file mode 100644
index 000000000000..f751c2777d0d
--- /dev/null
+++ b/llvm/test/TableGen/empty.td
@@ -0,0 +1,71 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+defvar LongList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+defvar EmptyStr = "";
+
+// Test !empty(dag).
+
+// CHECK: def Drec1 {
+// CHECK:   bit Empty = 1;
+// CHECK:   bit NotEmpty = 0;
+// CHECK: def Drec2 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+// CHECK: def Drec3 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+
+class D<dag ADag> {
+  bit Empty = !empty(ADag);
+  bit NotEmpty = !not(!empty(ADag));
+}
+
+def op;
+
+def Drec1 : D<(op)>;
+def Drec2 : D<(op "string")>;
+def Drec3 : D<(op "string", 42)>;
+
+// Test !empty(list).
+
+// CHECK: def Lrec1 {
+// CHECK:   bit Empty = 1;
+// CHECK:   bit NotEmpty = 0;
+// CHECK: def Lrec2 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+// CHECK: def Lrec3 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+
+class L<list<int> Ints> {
+  bit Empty = !empty(Ints);
+  bit NotEmpty = !not(!empty(Ints));
+}
+
+def Lrec1 : L<[]>;
+def Lrec2 : L<[1]>;
+def Lrec3 : L<LongList>;
+
+// Test !empty(string).
+
+// CHECK: def Srec1 {
+// CHECK:   bit Empty = 1;
+// CHECK:   bit NotEmpty = 0;
+// CHECK: def Srec2 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+// CHECK: def Srec3 {
+// CHECK:   bit Empty = 0;
+// CHECK:   bit NotEmpty = 1;
+
+class S<string Str> {
+  bit Empty = !empty(Str);
+  bit NotEmpty = !not(!empty(Str));
+}
+
+def Srec1 : S<EmptyStr>;
+def Srec2 : S<"a">;
+def Srec3 : S<"ab">;
+

diff  --git a/llvm/test/TableGen/size.td b/llvm/test/TableGen/size.td
index f7061e110790..5a1e661f19c2 100644
--- a/llvm/test/TableGen/size.td
+++ b/llvm/test/TableGen/size.td
@@ -1,6 +1,8 @@
 // RUN: llvm-tblgen %s | FileCheck %s
 // XFAIL: vg_leak
 
+// Test !size of lists.
+
 // CHECK: --- Defs ---
 
 // CHECK: def A1 {
@@ -32,3 +34,70 @@ def A2 : A<[1, 1, 2]>;
 
 def B1 : B<[]>;
 def B2 : B<["a", "b"]>;
+
+// Test !size of DAGs.
+
+// CHECK: def D0 {
+// CHECK:   int Val = 0;
+// CHECK: }
+
+// CHECK: def D1 {
+// CHECK:   int Val = 1;
+// CHECK: }
+
+// CHECK: def D2 {
+// CHECK:   int Val = 2;
+// CHECK: }
+
+// CHECK: def D3 {
+// CHECK:   int Val = 3;
+// CHECK: }
+
+// CHECK: def D4 {
+// CHECK:   int Val = 4;
+// CHECK: }
+
+class D<dag D> {
+  int Val = !size(D);
+}
+
+def op;
+
+def D0 : D<(op)>;
+def D1 : D<(op "string")>;
+def D2 : D<(op "string", 42)>;
+def D3 : D<(op "string", 42, (op "sub-dag"))>;
+def D4 : D<(op "string", 42, (op "sub-dag"), D0.Val)>;
+
+// Test !size of strings.
+
+// CHECK: def S0 {
+// CHECK:   int Val = 0;
+// CHECK: }
+
+// CHECK: def S1 {
+// CHECK:   int Val = 1;
+// CHECK: }
+
+// CHECK: def S2 {
+// CHECK:   int Val = 2;
+// CHECK: }
+
+// CHECK: def S3 {
+// CHECK:   int Val = 3;
+// CHECK: }
+
+// CHECK: def S4 {
+// CHECK:   int Val = 29;
+// CHECK: }
+
+class S<string S> {
+  int Val = !size(S);
+}
+
+def S0 : S<"">;
+def S1 : S<"a">;
+def S2 : S<"ab">;
+def S3 : S<"abc">;
+def S4 : S<"This is the end of the world!">;
+


        


More information about the llvm-commits mailing list