Index: llvm/trunk/docs/TableGen/LangIntro.rst =================================================================== --- llvm/trunk/docs/TableGen/LangIntro.rst +++ llvm/trunk/docs/TableGen/LangIntro.rst @@ -189,6 +189,10 @@ More than two arguments are accepted with the result being the concatenation of all the lists given. +``!listsplat(a, size)`` + A list value that contains the value ``a`` ``size`` times. + Example: ``!listsplat(0, 2)`` results in ``[0, 0]``. + ``!strconcat(a, b, ...)`` A string value that is the result of concatenating the 'a' and 'b' strings. More than two arguments are accepted with the result being the concatenation Index: llvm/trunk/docs/TableGen/LangRef.rst =================================================================== --- llvm/trunk/docs/TableGen/LangRef.rst +++ llvm/trunk/docs/TableGen/LangRef.rst @@ -100,7 +100,7 @@ :!or !empty !subst !foreach !strconcat :!cast !listconcat !size !foldl :!isa !dag !le !lt !ge - :!gt !ne !mul + :!gt !ne !mul !listsplat TableGen also has !cond operator that needs a slightly different syntax compared to other "bang operators": Index: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/include/llvm/TableGen/Record.h @@ -801,7 +801,8 @@ class BinOpInit : public OpInit, public FoldingSetNode { public: enum BinaryOp : uint8_t { ADD, MUL, AND, OR, SHL, SRA, SRL, LISTCONCAT, - STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, GT }; + LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, + GT }; private: Init *LHS, *RHS; @@ -821,6 +822,7 @@ RecTy *Type); static Init *getStrConcat(Init *lhs, Init *rhs); static Init *getListConcat(TypedInit *lhs, Init *rhs); + static Init *getListSplat(TypedInit *lhs, Init *rhs); void Profile(FoldingSetNodeID &ID) const; Index: llvm/trunk/lib/TableGen/Record.cpp =================================================================== --- llvm/trunk/lib/TableGen/Record.cpp +++ llvm/trunk/lib/TableGen/Record.cpp @@ -875,6 +875,10 @@ return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType()); } +Init *BinOpInit::getListSplat(TypedInit *LHS, Init *RHS) { + return BinOpInit::get(BinOpInit::LISTSPLAT, LHS, RHS, LHS->getType()); +} + Init *BinOpInit::Fold(Record *CurRec) const { switch (getOpcode()) { case CONCAT: { @@ -915,6 +919,15 @@ } break; } + case LISTSPLAT: { + TypedInit *Value = dyn_cast(LHS); + IntInit *Size = dyn_cast(RHS); + if (Value && Size) { + SmallVector Args(Size->getValue(), Value); + return ListInit::get(Args, Value->getType()); + } + break; + } case STRCONCAT: { StringInit *LHSs = dyn_cast(LHS); StringInit *RHSs = dyn_cast(RHS); @@ -1022,6 +1035,7 @@ case GE: Result = "!ge"; break; case GT: Result = "!gt"; break; case LISTCONCAT: Result = "!listconcat"; break; + case LISTSPLAT: Result = "!listsplat"; break; case STRCONCAT: Result = "!strconcat"; break; } return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; Index: llvm/trunk/lib/TableGen/TGLexer.h =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.h +++ llvm/trunk/lib/TableGen/TGLexer.h @@ -49,9 +49,9 @@ MultiClass, String, Defset, // !keywords. - XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, - XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, - XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, + XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat, + XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, + XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, // Integer value. IntVal, Index: llvm/trunk/lib/TableGen/TGLexer.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.cpp +++ llvm/trunk/lib/TableGen/TGLexer.cpp @@ -564,6 +564,7 @@ .Case("foldl", tgtok::XFoldl) .Case("foreach", tgtok::XForEach) .Case("listconcat", tgtok::XListConcat) + .Case("listsplat", tgtok::XListSplat) .Case("strconcat", tgtok::XStrConcat) .Default(tgtok::Error); Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -1042,6 +1042,7 @@ case tgtok::XGe: case tgtok::XGt: case tgtok::XListConcat: + case tgtok::XListSplat: case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); SMLoc OpLoc = Lex.getLoc(); @@ -1065,6 +1066,7 @@ case tgtok::XGe: Code = BinOpInit::GE; break; case tgtok::XGt: Code = BinOpInit::GT; break; case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; + case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break; case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; } @@ -1103,6 +1105,9 @@ // We don't know the list type until we parse the first argument ArgType = ItemType; break; + case tgtok::XListSplat: + // Can't do any typechecking until we parse the first argument. + break; case tgtok::XStrConcat: Type = StringRecTy::get(); ArgType = StringRecTy::get(); @@ -1142,6 +1147,33 @@ return nullptr; } break; + case BinOpInit::LISTSPLAT: + if (ItemType && InitList.size() == 1) { + if (!isa(ItemType)) { + Error(OpLoc, + Twine("expected output type to be a list, got type '") + + ItemType->getAsString() + "'"); + return nullptr; + } + if (!ArgType->getListTy()->typeIsConvertibleTo(ItemType)) { + Error(OpLoc, Twine("expected first arg type to be '") + + ArgType->getAsString() + + "', got value of type '" + + cast(ItemType) + ->getElementType() + ->getAsString() + + "'"); + return nullptr; + } + } + if (InitList.size() == 2 && !isa(ArgType)) { + Error(InitLoc, Twine("expected second parameter to be an int, got " + "value of type '") + + ArgType->getAsString() + "'"); + return nullptr; + } + ArgType = nullptr; // Broken invariant: types not identical. + break; case BinOpInit::EQ: case BinOpInit::NE: if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) && @@ -1179,8 +1211,12 @@ } Lex.Lex(); // eat the ')' + // listconcat returns a list with type of the argument. if (Code == BinOpInit::LISTCONCAT) Type = ArgType; + // listsplat returns a list of type of the *first* argument. + if (Code == BinOpInit::LISTSPLAT) + Type = cast(InitList.front())->getType()->getListTy(); // We allow multiple operands to associative operators like !strconcat as // shorthand for nesting them. @@ -1718,6 +1754,7 @@ /// SimpleValue ::= SRATOK '(' Value ',' Value ')' /// SimpleValue ::= SRLTOK '(' Value ',' Value ')' /// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')' +/// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')' /// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= COND '(' [Value ':' Value,]+ ')' /// @@ -2031,6 +2068,7 @@ case tgtok::XGe: case tgtok::XGt: case tgtok::XListConcat: + case tgtok::XListSplat: case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: case tgtok::XCond: Index: llvm/trunk/test/TableGen/listsplat.td =================================================================== --- llvm/trunk/test/TableGen/listsplat.td +++ llvm/trunk/test/TableGen/listsplat.td @@ -0,0 +1,75 @@ +// RUN: llvm-tblgen %s | FileCheck %s + +// CHECK: ------------- Classes ----------------- +// CHECK-NEXT: class X { +// CHECK-NEXT: list x = !listsplat(X:a, X:b); +// CHECK-NEXT: } +// CHECK-NEXT: class Y { +// CHECK-NEXT: list x = !listsplat(Y:a, Y:b); +// CHECK-NEXT: } +// CHECK-NEXT: ------------- Defs ----------------- +// CHECK-NEXT: def DX00 { // X +// CHECK-NEXT: list x = []; +// CHECK-NEXT: } +// CHECK-NEXT: def DX01 { // X +// CHECK-NEXT: list x = [0]; +// CHECK-NEXT: } +// CHECK-NEXT: def DX02 { // X +// CHECK-NEXT: list x = [0, 0]; +// CHECK-NEXT: } +// CHECK-NEXT: def DX10 { // X +// CHECK-NEXT: list x = []; +// CHECK-NEXT: } +// CHECK-NEXT: def DX11 { // X +// CHECK-NEXT: list x = [1]; +// CHECK-NEXT: } +// CHECK-NEXT: def DX12 { // X +// CHECK-NEXT: list x = [1, 1]; +// CHECK-NEXT: } +// CHECK-NEXT: def DYa0 { // Y +// CHECK-NEXT: list x = []; +// CHECK-NEXT: } +// CHECK-NEXT: def DYa1 { // Y +// CHECK-NEXT: list x = ["a"]; +// CHECK-NEXT: } +// CHECK-NEXT: def DYa2 { // Y +// CHECK-NEXT: list x = ["a", "a"]; +// CHECK-NEXT: } +// CHECK-NEXT: def DYe0 { // Y +// CHECK-NEXT: list x = []; +// CHECK-NEXT: } +// CHECK-NEXT: def DYe1 { // Y +// CHECK-NEXT: list x = [""]; +// CHECK-NEXT: } +// CHECK-NEXT: def DYe2 { // Y +// CHECK-NEXT: list x = ["", ""]; +// CHECK-NEXT: } +// CHECK-NEXT: def DZ { // X +// CHECK-NEXT: list x = [42, 42, 42]; +// CHECK-NEXT: } + +class X { + list x = !listsplat(a, b); +} + +class Y { + list x = !listsplat(a, b); +} + +def DX00 : X<0, 0>; +def DX01 : X<0, 1>; +def DX02 : X<0, 2>; + +def DX10 : X<1, 0>; +def DX11 : X<1, 1>; +def DX12 : X<1, 2>; + +def DYe0 : Y<"", 0>; +def DYe1 : Y<"", 1>; +def DYe2 : Y<"", 2>; + +def DYa0 : Y<"a", 0>; +def DYa1 : Y<"a", 1>; +def DYa2 : Y<"a", 2>; + +def DZ : X<42, !size([1, 2, 3])>; Index: llvm/trunk/utils/kate/llvm-tablegen.xml =================================================================== --- llvm/trunk/utils/kate/llvm-tablegen.xml +++ llvm/trunk/utils/kate/llvm-tablegen.xml @@ -28,6 +28,7 @@ !strconcat !cast !listconcat + !listsplat !size !foldl !isa