mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-11 02:16:50 +00:00
[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:
parent
163157378e
commit
5d9f656bb7
@ -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
|
||||
|
@ -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":
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<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: {
|
||||
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
||||
StringInit *RHSs = dyn_cast<StringInit>(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() + ")";
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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<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::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<TypedInit>(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:
|
||||
|
75
llvm/test/TableGen/listsplat.td
Normal file
75
llvm/test/TableGen/listsplat.td
Normal 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])>;
|
@ -28,6 +28,7 @@
|
||||
<item> !strconcat </item>
|
||||
<item> !cast </item>
|
||||
<item> !listconcat </item>
|
||||
<item> !listsplat </item>
|
||||
<item> !size </item>
|
||||
<item> !foldl </item>
|
||||
<item> !isa </item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user