summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/docs/TableGen/LangIntro.rst8
-rw-r--r--llvm/lib/TableGen/TGParser.cpp122
-rw-r--r--llvm/test/TableGen/Paste.td10
-rw-r--r--llvm/test/TableGen/arithmetic.td25
-rw-r--r--llvm/test/TableGen/dag-functional.td8
-rw-r--r--llvm/test/TableGen/listconcat.td16
-rw-r--r--llvm/test/TableGen/math.td17
7 files changed, 174 insertions, 32 deletions
diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst
index 1f9b44586d9..75bce2b5216 100644
--- a/llvm/docs/TableGen/LangIntro.rst
+++ b/llvm/docs/TableGen/LangIntro.rst
@@ -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``"
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 0dd4da416d9..d839c2ad623 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -981,28 +981,59 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
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 *CurRec, RecTy *ItemType) {
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();
- InitList.push_back(ParseValue(CurRec));
- if (!InitList.back()) return nullptr;
+ 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;
+ }
+
+ if (Lex.getCode() != tgtok::comma)
+ break;
+ Lex.Lex(); // eat the ','
}
if (Lex.getCode() != tgtok::r_paren) {
@@ -1027,20 +1095,14 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
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 *CurRec, RecTy *ItemType, IDParseMode Mode) {
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!");
diff --git a/llvm/test/TableGen/Paste.td b/llvm/test/TableGen/Paste.td
index a7e2a5b318b..22c492b1ce1 100644
--- a/llvm/test/TableGen/Paste.td
+++ b/llvm/test/TableGen/Paste.td
@@ -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;
diff --git a/llvm/test/TableGen/arithmetic.td b/llvm/test/TableGen/arithmetic.td
new file mode 100644
index 00000000000..50007c5f18a
--- /dev/null
+++ b/llvm/test/TableGen/arithmetic.td
@@ -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>;
diff --git a/llvm/test/TableGen/dag-functional.td b/llvm/test/TableGen/dag-functional.td
index b9be2bf6b09..dc1c37c8eca 100644
--- a/llvm/test/TableGen/dag-functional.td
+++ b/llvm/test/TableGen/dag-functional.td
@@ -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> names> {
}
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
diff --git a/llvm/test/TableGen/listconcat.td b/llvm/test/TableGen/listconcat.td
index 26dce17e92d..a989c3aa19c 100644
--- a/llvm/test/TableGen/listconcat.td
+++ b/llvm/test/TableGen/listconcat.td
@@ -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));
}
diff --git a/llvm/test/TableGen/math.td b/llvm/test/TableGen/math.td
index a8b939176e0..34377bd5b61 100644
--- a/llvm/test/TableGen/math.td
+++ b/llvm/test/TableGen/math.td
@@ -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)>;
OpenPOWER on IntegriCloud