[llvm] r327494 - TableGen: Type-check BinOps

Nicolai Haehnle via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 14 04:00:43 PDT 2018


Author: nha
Date: Wed Mar 14 04:00:43 2018
New Revision: 327494

URL: http://llvm.org/viewvc/llvm-project?rev=327494&view=rev
Log:
TableGen: Type-check BinOps

Additionally, allow more than two operands to !con, !add, !and, !or
in the same way as is already allowed for !listconcat and !strconcat.

Change-Id: I9659411f554201b90cd8ed7c7e004d381a66fa93

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

Added:
    llvm/trunk/test/TableGen/arithmetic.td
Modified:
    llvm/trunk/docs/TableGen/LangIntro.rst
    llvm/trunk/lib/TableGen/TGParser.cpp
    llvm/trunk/test/TableGen/Paste.td
    llvm/trunk/test/TableGen/dag-functional.td
    llvm/trunk/test/TableGen/listconcat.td
    llvm/trunk/test/TableGen/math.td

Modified: llvm/trunk/docs/TableGen/LangIntro.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/TableGen/LangIntro.rst?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/docs/TableGen/LangIntro.rst (original)
+++ llvm/trunk/docs/TableGen/LangIntro.rst Wed Mar 14 04:00:43 2018
@@ -267,8 +267,12 @@ supported include:
     on string, int and bit objects.  Use !cast<string> to compare other types of
     objects.
 
-``!shl(a,b)`` ``!srl(a,b)`` ``!sra(a,b)`` ``!add(a,b)`` ``!and(a,b)``
-    The usual binary and arithmetic operators.
+``!shl(a,b)`` ``!srl(a,b)`` ``!sra(a,b)``
+    The usual shift operators. Operations are on 64-bit integers, the result
+    is undefined for shift counts outside [0, 63].
+
+``!add(a,b,...)`` ``!and(a,b,...)`` ``!or(a,b,...)``
+    The usual arithmetic and binary operators.
 
 Note that all of the values have rules specifying how they convert to values
 for different types.  These rules allow you to assign a value like "``7``"

Modified: llvm/trunk/lib/TableGen/TGParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.cpp?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/lib/TableGen/TGParser.cpp (original)
+++ llvm/trunk/lib/TableGen/TGParser.cpp Wed Mar 14 04:00:43 2018
@@ -981,28 +981,59 @@ Init *TGParser::ParseOperation(Record *C
     Lex.Lex();  // eat the operation
 
     BinOpInit::BinaryOp Code;
-    RecTy *Type = nullptr;
-
     switch (OpTok) {
     default: llvm_unreachable("Unhandled code!");
-    case tgtok::XConcat: Code = BinOpInit::CONCAT;Type = DagRecTy::get(); break;
-    case tgtok::XADD:    Code = BinOpInit::ADD;   Type = IntRecTy::get(); break;
-    case tgtok::XAND:    Code = BinOpInit::AND;   Type = IntRecTy::get(); break;
-    case tgtok::XOR:     Code = BinOpInit::OR;    Type = IntRecTy::get(); break;
-    case tgtok::XSRA:    Code = BinOpInit::SRA;   Type = IntRecTy::get(); break;
-    case tgtok::XSRL:    Code = BinOpInit::SRL;   Type = IntRecTy::get(); break;
-    case tgtok::XSHL:    Code = BinOpInit::SHL;   Type = IntRecTy::get(); break;
-    case tgtok::XEq:     Code = BinOpInit::EQ;    Type = BitRecTy::get(); break;
+    case tgtok::XConcat: Code = BinOpInit::CONCAT; break;
+    case tgtok::XADD:    Code = BinOpInit::ADD; break;
+    case tgtok::XAND:    Code = BinOpInit::AND; break;
+    case tgtok::XOR:     Code = BinOpInit::OR; break;
+    case tgtok::XSRA:    Code = BinOpInit::SRA; break;
+    case tgtok::XSRL:    Code = BinOpInit::SRL; break;
+    case tgtok::XSHL:    Code = BinOpInit::SHL; break;
+    case tgtok::XEq:     Code = BinOpInit::EQ; break;
+    case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
+    case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
+    }
+
+    RecTy *Type = nullptr;
+    RecTy *ArgType = nullptr;
+    switch (OpTok) {
+    default:
+      llvm_unreachable("Unhandled code!");
+    case tgtok::XConcat:
+      Type = DagRecTy::get();
+      ArgType = DagRecTy::get();
+      break;
+    case tgtok::XAND:
+    case tgtok::XOR:
+    case tgtok::XSRA:
+    case tgtok::XSRL:
+    case tgtok::XSHL:
+    case tgtok::XADD:
+      Type = IntRecTy::get();
+      ArgType = IntRecTy::get();
+      break;
+    case tgtok::XEq:
+      Type = BitRecTy::get();
+      // ArgType for Eq is not known at this point
+      break;
     case tgtok::XListConcat:
-      Code = BinOpInit::LISTCONCAT;
       // We don't know the list type until we parse the first argument
+      ArgType = ItemType;
       break;
     case tgtok::XStrConcat:
-      Code = BinOpInit::STRCONCAT;
       Type = StringRecTy::get();
+      ArgType = StringRecTy::get();
       break;
     }
 
+    if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) {
+      Error(OpLoc, Twine("expected value of type '") +
+                   ItemType->getAsString() + "', got '" +
+                   Type->getAsString() + "'");
+      return nullptr;
+    }
+
     if (Lex.getCode() != tgtok::l_paren) {
       TokError("expected '(' after binary operator");
       return nullptr;
@@ -1011,14 +1042,51 @@ Init *TGParser::ParseOperation(Record *C
 
     SmallVector<Init*, 2> InitList;
 
-    InitList.push_back(ParseValue(CurRec));
-    if (!InitList.back()) return nullptr;
+    for (;;) {
+      SMLoc InitLoc = Lex.getLoc();
+      InitList.push_back(ParseValue(CurRec, ArgType));
+      if (!InitList.back()) return nullptr;
 
-    while (Lex.getCode() == tgtok::comma) {
-      Lex.Lex();  // eat the ','
+      // All BinOps require their arguments to be of compatible types.
+      TypedInit *TI = dyn_cast<TypedInit>(InitList.back());
+      if (!ArgType) {
+        ArgType = TI->getType();
+
+        switch (Code) {
+        case BinOpInit::LISTCONCAT:
+          if (!isa<ListRecTy>(ArgType)) {
+            Error(InitLoc, Twine("expected a list, got value of type '") +
+                           ArgType->getAsString() + "'");
+            return nullptr;
+          }
+          break;
+        case BinOpInit::EQ:
+          if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
+              !ArgType->typeIsConvertibleTo(StringRecTy::get())) {
+            Error(InitLoc, Twine("expected int, bits, or string; got value of "
+                                 "type '") + ArgType->getAsString() + "'");
+            return nullptr;
+          }
+          break;
+        default: llvm_unreachable("other ops have fixed argument types");
+        }
+      } else {
+        RecTy *Resolved = resolveTypes(ArgType, TI->getType());
+        if (!Resolved) {
+          Error(InitLoc, Twine("expected value of type '") +
+                         ArgType->getAsString() + "', got '" +
+                         TI->getType()->getAsString() + "'");
+          return nullptr;
+        }
+        if (Code != BinOpInit::ADD && Code != BinOpInit::AND &&
+            Code != BinOpInit::OR && Code != BinOpInit::SRA &&
+            Code != BinOpInit::SRL && Code != BinOpInit::SHL)
+          ArgType = Resolved;
+      }
 
-      InitList.push_back(ParseValue(CurRec));
-      if (!InitList.back()) return nullptr;
+      if (Lex.getCode() != tgtok::comma)
+        break;
+      Lex.Lex();  // eat the ','
     }
 
     if (Lex.getCode() != tgtok::r_paren) {
@@ -1027,20 +1095,14 @@ Init *TGParser::ParseOperation(Record *C
     }
     Lex.Lex();  // eat the ')'
 
-    // If we are doing !listconcat, we should know the type by now
-    if (OpTok == tgtok::XListConcat) {
-      if (TypedInit *Arg0 = dyn_cast<TypedInit>(InitList[0]))
-        Type = Arg0->getType();
-      else {
-        InitList[0]->print(errs());
-        Error(OpLoc, "expected a list");
-        return nullptr;
-      }
-    }
+    if (Code == BinOpInit::LISTCONCAT)
+      Type = ArgType;
 
     // We allow multiple operands to associative operators like !strconcat as
     // shorthand for nesting them.
-    if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) {
+    if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT ||
+        Code == BinOpInit::CONCAT || Code == BinOpInit::ADD ||
+        Code == BinOpInit::AND || Code == BinOpInit::OR) {
       while (InitList.size() > 2) {
         Init *RHS = InitList.pop_back_val();
         RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))
@@ -1896,7 +1958,7 @@ Init *TGParser::ParseValue(Record *CurRe
         break;
 
       default:
-        Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode);
+        Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode);
         RHS = dyn_cast<TypedInit>(RHSResult);
         if (!RHS) {
           Error(PasteLoc, "RHS of paste is not typed!");

Modified: llvm/trunk/test/TableGen/Paste.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/Paste.td?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/Paste.td (original)
+++ llvm/trunk/test/TableGen/Paste.td Wed Mar 14 04:00:43 2018
@@ -12,6 +12,16 @@ multiclass Test {
   def Vy#NAME#PD : Instr<3>;
 }
 
+class Arithmetic<int i> {
+  string name = "number"#!add(i, 1);
+}
+
+def A : Arithmetic<5>;
+
+// CHECK: def A {
+// CHECK:   string name = "number6";
+// CHECK: }
+
 defm ADD : Test;
 defm SUB : Test;
 

Added: llvm/trunk/test/TableGen/arithmetic.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/arithmetic.td?rev=327494&view=auto
==============================================================================
--- llvm/trunk/test/TableGen/arithmetic.td (added)
+++ llvm/trunk/test/TableGen/arithmetic.td Wed Mar 14 04:00:43 2018
@@ -0,0 +1,25 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+// CHECK: --- Defs ---
+
+// CHECK: def A0 {
+// CHECK:   bits<8> add = { 0, 1, 0, 0, 0, 0, 0, 0 };
+// CHECK:   bits<8> and = { 0, 0, 0, 0, 0, 0, 0, 1 };
+// CHECK:   bits<8> or =  { 0, 0, 1, 1, 1, 1, 1, 1 };
+// CHECK:   bits<8> srl = { 0, 0, 0, 1, 1, 1, 1, 1 };
+// CHECK:   bits<8> sra = { 0, 0, 0, 1, 1, 1, 1, 1 };
+// CHECK:   bits<8> shl = { 0, 1, 1, 1, 1, 1, 1, 0 };
+// CHECK: }
+
+class A<bits<8> a, bits<2> b> {
+  // Operands of different bits types are allowed.
+  bits<8> add = !add(a, b);
+  bits<8> and = !and(a, b);
+  bits<8> or = !or(a, b);
+  bits<8> srl = !srl(a, b);
+  bits<8> sra = !sra(a, b);
+  bits<8> shl = !shl(a, b);
+}
+
+def A0 : A<63, 1>;

Modified: llvm/trunk/test/TableGen/dag-functional.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/dag-functional.td?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/dag-functional.td (original)
+++ llvm/trunk/test/TableGen/dag-functional.td Wed Mar 14 04:00:43 2018
@@ -36,6 +36,10 @@
 // CHECK:   dag ret2 = (ops 1, 2);
 // CHECK: }
 
+// CHECK: def D {
+// CHECK:   dag d1 = (ops 1, ?:$name1, 2, 3);
+// CHECK: }
+
 def ops;
 
 class Node<int val, string name> {
@@ -93,3 +97,7 @@ class C<list<int> nodes, list<string> na
 }
 
 def C0 : C<[1, 2], ["a", "b"]>;
+
+def D {
+  dag d1 = !con((ops 1), (ops $name1), (ops), (ops 2, 3));
+}
\ No newline at end of file

Modified: llvm/trunk/test/TableGen/listconcat.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/listconcat.td?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/listconcat.td (original)
+++ llvm/trunk/test/TableGen/listconcat.td Wed Mar 14 04:00:43 2018
@@ -9,6 +9,14 @@
 // CHECK:   list<string> T2 = !listconcat(Y:S, !listconcat(["foo"], !listconcat(Y:S, ["bar", "baz"])));
 // CHECK: }
 
+// CHECK: def A0 {
+// CHECK:   list<int> lst = [4];
+// CHECK: }
+
+// CHECK: def A1 {
+// CHECK:   list<int> lst = [];
+// CHECK: }
+
 // CHECK: def DX {
 // CHECK:   list<int> x = [0, 1, 1, 2]
 // CHECK: }
@@ -18,6 +26,14 @@
 // CHECK:   list<string> T2 = ["fu", "foo", "fu", "bar", "baz"];
 // CHECK: }
 
+class A<bit x> {
+  // The empty lists type-check without issues.
+  list<int> lst = !listconcat([], !if(x, [], [4]));
+}
+
+def A0 : A<0>;
+def A1 : A<1>;
+
 class X<list<int> a, list<int> b, list<int> c> {
     list<int> x = !listconcat(!listconcat(a, b), !listconcat(b, c));
 }

Modified: llvm/trunk/test/TableGen/math.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/math.td?rev=327494&r1=327493&r2=327494&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/math.td (original)
+++ llvm/trunk/test/TableGen/math.td Wed Mar 14 04:00:43 2018
@@ -35,6 +35,13 @@ def v1025   : Int<!add(v1024.Value, 1)>;
 // CHECK: def v1025
 // CHECK: Value = 1025
 
+// CHECK: def v1a
+// CHECK: Value = 1
+
+// CHECK: def v2
+// CHECK: Value = 2
+def v2 : Int<2>;
+
 def v2048   : Int<!add(v1024.Value, v1024.Value)>;
 // CHECK: def v2048
 // CHECK: Value = 2048
@@ -45,3 +52,13 @@ def v1 : Int<!and(v1025.Value, 1)>;
 // CHECK: def v3072
 // CHECK: Value = 3072
 def v3072 : Int<!or(v1024.Value, v2048.Value)>;
+
+// CHECK: def v4
+// CHECK: Value = 4
+
+// CHECK: def v7
+// CHECK: Value = 7
+
+def v4 : Int<!add(v2.Value, 1, v1.Value)>;
+def v7 : Int<!or(v1.Value, v2.Value, v4.Value)>;
+def v1a : Int<!and(v7.Value, 5, v1.Value)>;




More information about the llvm-commits mailing list