mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
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 llvm-svn: 327494
This commit is contained in:
parent
bf9d16116d
commit
5962b8bbf7
@ -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``"
|
||||
|
@ -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;
|
||||
|
||||
while (Lex.getCode() == tgtok::comma) {
|
||||
Lex.Lex(); // eat the ','
|
||||
|
||||
InitList.push_back(ParseValue(CurRec));
|
||||
for (;;) {
|
||||
SMLoc InitLoc = Lex.getLoc();
|
||||
InitList.push_back(ParseValue(CurRec, ArgType));
|
||||
if (!InitList.back()) return nullptr;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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!");
|
||||
|
@ -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;
|
||||
|
||||
|
25
test/TableGen/arithmetic.td
Normal file
25
test/TableGen/arithmetic.td
Normal file
@ -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>;
|
@ -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));
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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)>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user