[tablegen] Add !listconcat operator with the similar semantics as !strconcat

Summary:
It concatenates two or more lists. In addition to the !strconcat semantics
the lists must have the same element type.

My overall aim is to make it easy to append to Instruction.Predicates
rather than override it. This can be done by concatenating lists passed as
arguments, or by concatenating lists passed in additional fields.

Reviewers: dsanders

Reviewed By: dsanders

Subscribers: hfinkel, llvm-commits

Differential Revision: http://reviews.llvm.org/D3506

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208183 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2014-05-07 10:13:19 +00:00
parent 0c9ea21554
commit d80222a48b
8 changed files with 63 additions and 4 deletions

View File

@ -160,6 +160,12 @@ supported include:
remaining elements in the list may be arbitrary other values, including remaining elements in the list may be arbitrary other values, including
nested ```dag``' values. nested ```dag``' values.
``!listconcat(a, b, ...)``
A list value that is the result of concatenating the 'a' and 'b' lists.
The lists must have the same element type.
More than two arguments are accepted with the result being the concatenation
of all the lists given.
``!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

@ -93,7 +93,7 @@ wide variety of meanings:
BangOperator: one of BangOperator: one of
:!eq !if !head !tail !con :!eq !if !head !tail !con
:!add !shl !sra !srl :!add !shl !sra !srl
:!cast !empty !subst !foreach !strconcat :!cast !empty !subst !foreach !listconcat !strconcat
Syntax Syntax
====== ======

View File

@ -929,7 +929,8 @@ public:
/// ///
class BinOpInit : public OpInit { class BinOpInit : public OpInit {
public: public:
enum BinaryOp { ADD, SHL, SRA, SRL, STRCONCAT, CONCAT, EQ }; enum BinaryOp { ADD, SHL, SRA, SRL, LISTCONCAT, STRCONCAT, CONCAT, EQ };
private: private:
BinaryOp Opc; BinaryOp Opc;
Init *LHS, *RHS; Init *LHS, *RHS;

View File

@ -918,6 +918,18 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
} }
break; break;
} }
case LISTCONCAT: {
ListInit *LHSs = dyn_cast<ListInit>(LHS);
ListInit *RHSs = dyn_cast<ListInit>(RHS);
if (LHSs && RHSs) {
std::vector<Init *> Args;
Args.insert(Args.end(), LHSs->begin(), LHSs->end());
Args.insert(Args.end(), RHSs->begin(), RHSs->end());
return ListInit::get(
Args, static_cast<ListRecTy *>(LHSs->getType())->getElementType());
}
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);
@ -987,6 +999,7 @@ std::string BinOpInit::getAsString() const {
case SRA: Result = "!sra"; break; case SRA: Result = "!sra"; break;
case SRL: Result = "!srl"; break; case SRL: Result = "!srl"; break;
case EQ: Result = "!eq"; break; case EQ: Result = "!eq"; break;
case LISTCONCAT: Result = "!listconcat"; 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

@ -478,6 +478,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("empty", tgtok::XEmpty) .Case("empty", tgtok::XEmpty)
.Case("subst", tgtok::XSubst) .Case("subst", tgtok::XSubst)
.Case("foreach", tgtok::XForEach) .Case("foreach", tgtok::XForEach)
.Case("listconcat", tgtok::XListConcat)
.Case("strconcat", tgtok::XStrConcat) .Case("strconcat", tgtok::XStrConcat)
.Default(tgtok::Error); .Default(tgtok::Error);

View File

@ -47,7 +47,7 @@ namespace tgtok {
MultiClass, String, MultiClass, String,
// !keywords. // !keywords.
XConcat, XADD, XSRA, XSRL, XSHL, XStrConcat, XCast, XSubst, XConcat, XADD, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, XSubst,
XForEach, XHead, XTail, XEmpty, XIf, XEq, XForEach, XHead, XTail, XEmpty, XIf, XEq,
// Integer value. // Integer value.

View File

@ -903,6 +903,7 @@ Init *TGParser::ParseOperation(Record *CurRec) {
case tgtok::XSRL: case tgtok::XSRL:
case tgtok::XSHL: case tgtok::XSHL:
case tgtok::XEq: case tgtok::XEq:
case tgtok::XListConcat:
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();
@ -919,6 +920,10 @@ Init *TGParser::ParseOperation(Record *CurRec) {
case tgtok::XSRL: Code = BinOpInit::SRL; 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::XSHL: Code = BinOpInit::SHL; Type = IntRecTy::get(); break;
case tgtok::XEq: Code = BinOpInit::EQ; Type = BitRecTy::get(); break; case tgtok::XEq: Code = BinOpInit::EQ; Type = BitRecTy::get(); break;
case tgtok::XListConcat:
Code = BinOpInit::LISTCONCAT;
// We don't know the list type until we parse the first argument
break;
case tgtok::XStrConcat: case tgtok::XStrConcat:
Code = BinOpInit::STRCONCAT; Code = BinOpInit::STRCONCAT;
Type = StringRecTy::get(); Type = StringRecTy::get();
@ -949,9 +954,22 @@ Init *TGParser::ParseOperation(Record *CurRec) {
} }
Lex.Lex(); // eat the ')' Lex.Lex(); // eat the ')'
// If we are doing !listconcat, we should know the type by now
if (OpTok == tgtok::XListConcat) {
if (VarInit *Arg0 = dyn_cast<VarInit>(InitList[0]))
Type = Arg0->getType();
else if (ListInit *Arg0 = dyn_cast<ListInit>(InitList[0]))
Type = Arg0->getType();
else {
InitList[0]->dump();
Error(OpLoc, "expected a list");
return nullptr;
}
}
// 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.
if (Code == BinOpInit::STRCONCAT) { if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) {
while (InitList.size() > 2) { while (InitList.size() > 2) {
Init *RHS = InitList.pop_back_val(); Init *RHS = InitList.pop_back_val();
RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type)) RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))
@ -1134,6 +1152,7 @@ RecTy *TGParser::ParseOperatorType() {
/// SimpleValue ::= SHLTOK '(' Value ',' Value ')' /// SimpleValue ::= SHLTOK '(' Value ',' Value ')'
/// SimpleValue ::= SRATOK '(' Value ',' Value ')' /// SimpleValue ::= SRATOK '(' Value ',' Value ')'
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')' /// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
/// ///
Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
@ -1417,6 +1436,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XSRL: case tgtok::XSRL:
case tgtok::XSHL: case tgtok::XSHL:
case tgtok::XEq: case tgtok::XEq:
case tgtok::XListConcat:
case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf: case tgtok::XIf:
case tgtok::XForEach: case tgtok::XForEach:

View File

@ -0,0 +1,18 @@
// RUN: llvm-tblgen %s | FileCheck %s
// CHECK: class Y<list<string> Y:S = ?> {
// CHECK: list<string> T1 = !listconcat(Y:S, ["foo"]);
// CHECK: list<string> T2 = !listconcat(Y:S, !listconcat(["foo"], !listconcat(Y:S, ["bar", "baz"])));
// CHECK: }
// CHECK: def Z {
// CHECK: list<string> T1 = ["fu", "foo"];
// CHECK: list<string> T2 = ["fu", "foo", "fu", "bar", "baz"];
// CHECK: }
class Y<list<string> S> {
list<string> T1 = !listconcat(S, ["foo"]);
list<string> T2 = !listconcat(S, ["foo"], S, ["bar", "baz"]);
}
def Z : Y<["fu"]>;