From 5d9f656bb75ed4d0b9eb628115edd785fc61473b Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Wed, 10 Apr 2019 18:26:36 +0000 Subject: [PATCH] [TableGen] Introduce !listsplat 'binary' operator Summary: ``` ``!listsplat(a, size)`` A list value that contains the value ``a`` ``size`` times. Example: ``!listsplat(0, 2)`` results in ``[0, 0]``. ``` I plan to use this in X86ScheduleBdVer2.td for LoadRes handling. This is a little bit controversial because unlike every other binary operator the types aren't identical. Reviewers: stoklund, javed.absar, nhaehnle, craig.topper Reviewed By: javed.absar Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D60367 llvm-svn: 358117 --- llvm/docs/TableGen/LangIntro.rst | 4 ++ llvm/docs/TableGen/LangRef.rst | 2 +- llvm/include/llvm/TableGen/Record.h | 4 +- llvm/lib/TableGen/Record.cpp | 14 +++++++ llvm/lib/TableGen/TGLexer.cpp | 1 + llvm/lib/TableGen/TGLexer.h | 6 +-- llvm/lib/TableGen/TGParser.cpp | 38 +++++++++++++++++++ llvm/test/TableGen/listsplat.td | 75 +++++++++++++++++++++++++++++++++++++ llvm/utils/kate/llvm-tablegen.xml | 1 + 9 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 llvm/test/TableGen/listsplat.td diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst index 1a5f8b9..45104ac 100644 --- a/llvm/docs/TableGen/LangIntro.rst +++ b/llvm/docs/TableGen/LangIntro.rst @@ -189,6 +189,10 @@ supported include: 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 diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst index 59be6af..195106a 100644 --- a/llvm/docs/TableGen/LangRef.rst +++ b/llvm/docs/TableGen/LangRef.rst @@ -100,7 +100,7 @@ wide variety of meanings: :!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": diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index 17b63ec..bf7f022 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -801,7 +801,8 @@ public: 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 @@ public: 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; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 7577f0b..27d1bdc 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -875,6 +875,10 @@ Init *BinOpInit::getListConcat(TypedInit *LHS, Init *RHS) { 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 @@ Init *BinOpInit::Fold(Record *CurRec) const { } 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 @@ std::string BinOpInit::getAsString() const { 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() + ")"; diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index 9ffcc7a..b942025 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -564,6 +564,7 @@ tgtok::TokKind TGLexer::LexExclaim() { .Case("foldl", tgtok::XFoldl) .Case("foreach", tgtok::XForEach) .Case("listconcat", tgtok::XListConcat) + .Case("listsplat", tgtok::XListSplat) .Case("strconcat", tgtok::XStrConcat) .Default(tgtok::Error); diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index 49bdea4..4b42d31 100644 --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -49,9 +49,9 @@ namespace tgtok { 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, diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index f9486d4..937de9e 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -1042,6 +1042,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { // 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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { 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 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } 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 @@ Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) { /// 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 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, 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: diff --git a/llvm/test/TableGen/listsplat.td b/llvm/test/TableGen/listsplat.td new file mode 100644 index 0000000..5a93a4c --- /dev/null +++ b/llvm/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])>; diff --git a/llvm/utils/kate/llvm-tablegen.xml b/llvm/utils/kate/llvm-tablegen.xml index 92d6d01..df9507f 100644 --- a/llvm/utils/kate/llvm-tablegen.xml +++ b/llvm/utils/kate/llvm-tablegen.xml @@ -28,6 +28,7 @@ !strconcat !cast !listconcat + !listsplat !size !foldl !isa -- 2.7.4