[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
This commit is contained in:
Roman Lebedev 2019-04-10 18:26:36 +00:00
parent 163157378e
commit 5d9f656bb7
9 changed files with 140 additions and 5 deletions

View File

@ -189,6 +189,10 @@ supported include:
More than two arguments are accepted with the result being the concatenation More than two arguments are accepted with the result being the concatenation
of all the lists given. 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, ...)`` ``!strconcat(a, b, ...)``
A string value that is the result of concatenating the 'a' and 'b' strings. 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 More than two arguments are accepted with the result being the concatenation

View File

@ -100,7 +100,7 @@ wide variety of meanings:
:!or !empty !subst !foreach !strconcat :!or !empty !subst !foreach !strconcat
:!cast !listconcat !size !foldl :!cast !listconcat !size !foldl
:!isa !dag !le !lt !ge :!isa !dag !le !lt !ge
:!gt !ne !mul :!gt !ne !mul !listsplat
TableGen also has !cond operator that needs a slightly different TableGen also has !cond operator that needs a slightly different
syntax compared to other "bang operators": syntax compared to other "bang operators":

View File

@ -801,7 +801,8 @@ public:
class BinOpInit : public OpInit, public FoldingSetNode { class BinOpInit : public OpInit, public FoldingSetNode {
public: public:
enum BinaryOp : uint8_t { ADD, MUL, AND, OR, SHL, SRA, SRL, LISTCONCAT, 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: private:
Init *LHS, *RHS; Init *LHS, *RHS;
@ -821,6 +822,7 @@ public:
RecTy *Type); RecTy *Type);
static Init *getStrConcat(Init *lhs, Init *rhs); static Init *getStrConcat(Init *lhs, Init *rhs);
static Init *getListConcat(TypedInit *lhs, Init *rhs); static Init *getListConcat(TypedInit *lhs, Init *rhs);
static Init *getListSplat(TypedInit *lhs, Init *rhs);
void Profile(FoldingSetNodeID &ID) const; void Profile(FoldingSetNodeID &ID) const;

View File

@ -875,6 +875,10 @@ Init *BinOpInit::getListConcat(TypedInit *LHS, Init *RHS) {
return BinOpInit::get(BinOpInit::LISTCONCAT, LHS, RHS, LHS->getType()); 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 { Init *BinOpInit::Fold(Record *CurRec) const {
switch (getOpcode()) { switch (getOpcode()) {
case CONCAT: { case CONCAT: {
@ -915,6 +919,15 @@ Init *BinOpInit::Fold(Record *CurRec) const {
} }
break; break;
} }
case LISTSPLAT: {
TypedInit *Value = dyn_cast<TypedInit>(LHS);
IntInit *Size = dyn_cast<IntInit>(RHS);
if (Value && Size) {
SmallVector<Init *, 8> Args(Size->getValue(), Value);
return ListInit::get(Args, Value->getType());
}
break;
}
case STRCONCAT: { case STRCONCAT: {
StringInit *LHSs = dyn_cast<StringInit>(LHS); StringInit *LHSs = dyn_cast<StringInit>(LHS);
StringInit *RHSs = dyn_cast<StringInit>(RHS); StringInit *RHSs = dyn_cast<StringInit>(RHS);
@ -1022,6 +1035,7 @@ std::string BinOpInit::getAsString() const {
case GE: Result = "!ge"; break; case GE: Result = "!ge"; break;
case GT: Result = "!gt"; break; case GT: Result = "!gt"; break;
case LISTCONCAT: Result = "!listconcat"; break; case LISTCONCAT: Result = "!listconcat"; break;
case LISTSPLAT: Result = "!listsplat"; break;
case STRCONCAT: Result = "!strconcat"; break; case STRCONCAT: Result = "!strconcat"; break;
} }
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";

View File

@ -564,6 +564,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("foldl", tgtok::XFoldl) .Case("foldl", tgtok::XFoldl)
.Case("foreach", tgtok::XForEach) .Case("foreach", tgtok::XForEach)
.Case("listconcat", tgtok::XListConcat) .Case("listconcat", tgtok::XListConcat)
.Case("listsplat", tgtok::XListSplat)
.Case("strconcat", tgtok::XStrConcat) .Case("strconcat", tgtok::XStrConcat)
.Default(tgtok::Error); .Default(tgtok::Error);

View File

@ -49,9 +49,9 @@ namespace tgtok {
MultiClass, String, Defset, MultiClass, String, Defset,
// !keywords. // !keywords.
XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat,
XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty,
XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt,
// Integer value. // Integer value.
IntVal, IntVal,

View File

@ -1042,6 +1042,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XGe: case tgtok::XGe:
case tgtok::XGt: case tgtok::XGt:
case tgtok::XListConcat: case tgtok::XListConcat:
case tgtok::XListSplat:
case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')'
tgtok::TokKind OpTok = Lex.getCode(); tgtok::TokKind OpTok = Lex.getCode();
SMLoc OpLoc = Lex.getLoc(); SMLoc OpLoc = Lex.getLoc();
@ -1065,6 +1066,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
case tgtok::XGe: Code = BinOpInit::GE; break; case tgtok::XGe: Code = BinOpInit::GE; break;
case tgtok::XGt: Code = BinOpInit::GT; break; case tgtok::XGt: Code = BinOpInit::GT; break;
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; 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 // We don't know the list type until we parse the first argument
ArgType = ItemType; ArgType = ItemType;
break; break;
case tgtok::XListSplat:
// Can't do any typechecking until we parse the first argument.
break;
case tgtok::XStrConcat: case tgtok::XStrConcat:
Type = StringRecTy::get(); Type = StringRecTy::get();
ArgType = StringRecTy::get(); ArgType = StringRecTy::get();
@ -1142,6 +1147,33 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
return nullptr; return nullptr;
} }
break; break;
case BinOpInit::LISTSPLAT:
if (ItemType && InitList.size() == 1) {
if (!isa<ListRecTy>(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<ListRecTy>(ItemType)
->getElementType()
->getAsString() +
"'");
return nullptr;
}
}
if (InitList.size() == 2 && !isa<IntRecTy>(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::EQ:
case BinOpInit::NE: case BinOpInit::NE:
if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) && if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
@ -1179,8 +1211,12 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
} }
Lex.Lex(); // eat the ')' Lex.Lex(); // eat the ')'
// listconcat returns a list with type of the argument.
if (Code == BinOpInit::LISTCONCAT) if (Code == BinOpInit::LISTCONCAT)
Type = ArgType; Type = ArgType;
// listsplat returns a list of type of the *first* argument.
if (Code == BinOpInit::LISTSPLAT)
Type = cast<TypedInit>(InitList.front())->getType()->getListTy();
// We allow multiple operands to associative operators like !strconcat as // We allow multiple operands to associative operators like !strconcat as
// shorthand for nesting them. // shorthand for nesting them.
@ -1718,6 +1754,7 @@ Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
/// SimpleValue ::= SRATOK '(' Value ',' Value ')' /// SimpleValue ::= SRATOK '(' Value ',' Value ')'
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')' /// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')'
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')' /// SimpleValue ::= COND '(' [Value ':' Value,]+ ')'
/// ///
@ -2031,6 +2068,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XGe: case tgtok::XGe:
case tgtok::XGt: case tgtok::XGt:
case tgtok::XListConcat: case tgtok::XListConcat:
case tgtok::XListSplat:
case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf: case tgtok::XIf:
case tgtok::XCond: case tgtok::XCond:

View File

@ -0,0 +1,75 @@
// RUN: llvm-tblgen %s | FileCheck %s
// CHECK: ------------- Classes -----------------
// CHECK-NEXT: class X<int X:a = ?, int X:b = ?> {
// CHECK-NEXT: list<int> x = !listsplat(X:a, X:b);
// CHECK-NEXT: }
// CHECK-NEXT: class Y<string Y:a = ?, int Y:b = ?> {
// CHECK-NEXT: list<string> x = !listsplat(Y:a, Y:b);
// CHECK-NEXT: }
// CHECK-NEXT: ------------- Defs -----------------
// CHECK-NEXT: def DX00 { // X
// CHECK-NEXT: list<int> x = [];
// CHECK-NEXT: }
// CHECK-NEXT: def DX01 { // X
// CHECK-NEXT: list<int> x = [0];
// CHECK-NEXT: }
// CHECK-NEXT: def DX02 { // X
// CHECK-NEXT: list<int> x = [0, 0];
// CHECK-NEXT: }
// CHECK-NEXT: def DX10 { // X
// CHECK-NEXT: list<int> x = [];
// CHECK-NEXT: }
// CHECK-NEXT: def DX11 { // X
// CHECK-NEXT: list<int> x = [1];
// CHECK-NEXT: }
// CHECK-NEXT: def DX12 { // X
// CHECK-NEXT: list<int> x = [1, 1];
// CHECK-NEXT: }
// CHECK-NEXT: def DYa0 { // Y
// CHECK-NEXT: list<string> x = [];
// CHECK-NEXT: }
// CHECK-NEXT: def DYa1 { // Y
// CHECK-NEXT: list<string> x = ["a"];
// CHECK-NEXT: }
// CHECK-NEXT: def DYa2 { // Y
// CHECK-NEXT: list<string> x = ["a", "a"];
// CHECK-NEXT: }
// CHECK-NEXT: def DYe0 { // Y
// CHECK-NEXT: list<string> x = [];
// CHECK-NEXT: }
// CHECK-NEXT: def DYe1 { // Y
// CHECK-NEXT: list<string> x = [""];
// CHECK-NEXT: }
// CHECK-NEXT: def DYe2 { // Y
// CHECK-NEXT: list<string> x = ["", ""];
// CHECK-NEXT: }
// CHECK-NEXT: def DZ { // X
// CHECK-NEXT: list<int> x = [42, 42, 42];
// CHECK-NEXT: }
class X<int a, int b> {
list<int> x = !listsplat(a, b);
}
class Y<string a, int b> {
list<string> 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])>;

View File

@ -28,6 +28,7 @@
<item> !strconcat </item> <item> !strconcat </item>
<item> !cast </item> <item> !cast </item>
<item> !listconcat </item> <item> !listconcat </item>
<item> !listsplat </item>
<item> !size </item> <item> !size </item>
<item> !foldl </item> <item> !foldl </item>
<item> !isa </item> <item> !isa </item>