Index: llvm/trunk/docs/TableGen/LangIntro.rst =================================================================== --- llvm/trunk/docs/TableGen/LangIntro.rst +++ llvm/trunk/docs/TableGen/LangIntro.rst @@ -267,8 +267,12 @@ on string, int and bit objects. Use !cast 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``" Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -981,28 +981,59 @@ 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 @@ SmallVector 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; + + // All BinOps require their arguments to be of compatible types. + TypedInit *TI = dyn_cast(InitList.back()); + if (!ArgType) { + ArgType = TI->getType(); + + switch (Code) { + case BinOpInit::LISTCONCAT: + if (!isa(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; + } - while (Lex.getCode() == tgtok::comma) { + if (Lex.getCode() != tgtok::comma) + break; Lex.Lex(); // eat the ',' - - InitList.push_back(ParseValue(CurRec)); - if (!InitList.back()) return nullptr; } if (Lex.getCode() != tgtok::r_paren) { @@ -1027,20 +1095,14 @@ } 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(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 @@ break; default: - Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode); + Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode); RHS = dyn_cast(RHSResult); if (!RHS) { Error(PasteLoc, "RHS of paste is not typed!"); Index: llvm/trunk/test/TableGen/Paste.td =================================================================== --- llvm/trunk/test/TableGen/Paste.td +++ llvm/trunk/test/TableGen/Paste.td @@ -12,6 +12,16 @@ def Vy#NAME#PD : Instr<3>; } +class Arithmetic { + string name = "number"#!add(i, 1); +} + +def A : Arithmetic<5>; + +// CHECK: def A { +// CHECK: string name = "number6"; +// CHECK: } + defm ADD : Test; defm SUB : Test; Index: llvm/trunk/test/TableGen/arithmetic.td =================================================================== --- llvm/trunk/test/TableGen/arithmetic.td +++ llvm/trunk/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 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>; Index: llvm/trunk/test/TableGen/dag-functional.td =================================================================== --- llvm/trunk/test/TableGen/dag-functional.td +++ llvm/trunk/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 { @@ -93,3 +97,7 @@ } 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 Index: llvm/trunk/test/TableGen/listconcat.td =================================================================== --- llvm/trunk/test/TableGen/listconcat.td +++ llvm/trunk/test/TableGen/listconcat.td @@ -9,6 +9,14 @@ // CHECK: list T2 = !listconcat(Y:S, !listconcat(["foo"], !listconcat(Y:S, ["bar", "baz"]))); // CHECK: } +// CHECK: def A0 { +// CHECK: list lst = [4]; +// CHECK: } + +// CHECK: def A1 { +// CHECK: list lst = []; +// CHECK: } + // CHECK: def DX { // CHECK: list x = [0, 1, 1, 2] // CHECK: } @@ -18,6 +26,14 @@ // CHECK: list T2 = ["fu", "foo", "fu", "bar", "baz"]; // CHECK: } +class A { + // The empty lists type-check without issues. + list lst = !listconcat([], !if(x, [], [4])); +} + +def A0 : A<0>; +def A1 : A<1>; + class X a, list b, list c> { list x = !listconcat(!listconcat(a, b), !listconcat(b, c)); } Index: llvm/trunk/test/TableGen/math.td =================================================================== --- llvm/trunk/test/TableGen/math.td +++ llvm/trunk/test/TableGen/math.td @@ -35,6 +35,13 @@ // 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; // CHECK: def v2048 // CHECK: Value = 2048 @@ -45,3 +52,13 @@ // CHECK: def v3072 // CHECK: Value = 3072 def v3072 : Int; + +// CHECK: def v4 +// CHECK: Value = 4 + +// CHECK: def v7 +// CHECK: Value = 7 + +def v4 : Int; +def v7 : Int; +def v1a : Int;