1
0
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:
Nicolai Haehnle 2018-03-14 11:00:43 +00:00
parent bf9d16116d
commit 5962b8bbf7
7 changed files with 175 additions and 33 deletions

View File

@ -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``"

View File

@ -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!");

View File

@ -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;

View 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>;

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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)>;