remaining elements in the list may be arbitrary other values, including
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, ...)``
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
BangOperator: one of
:!eq !if !head !tail !con
:!add !shl !sra !srl
- :!cast !empty !subst !foreach !strconcat
+ :!cast !empty !subst !foreach !listconcat !strconcat
Syntax
======
///
class BinOpInit : public OpInit {
public:
- enum BinaryOp { ADD, SHL, SRA, SRL, STRCONCAT, CONCAT, EQ };
+ enum BinaryOp { ADD, SHL, SRA, SRL, LISTCONCAT, STRCONCAT, CONCAT, EQ };
+
private:
BinaryOp Opc;
Init *LHS, *RHS;
}
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: {
StringInit *LHSs = dyn_cast<StringInit>(LHS);
StringInit *RHSs = dyn_cast<StringInit>(RHS);
case SRA: Result = "!sra"; break;
case SRL: Result = "!srl"; break;
case EQ: Result = "!eq"; break;
+ case LISTCONCAT: Result = "!listconcat"; break;
case STRCONCAT: Result = "!strconcat"; break;
}
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
.Case("empty", tgtok::XEmpty)
.Case("subst", tgtok::XSubst)
.Case("foreach", tgtok::XForEach)
+ .Case("listconcat", tgtok::XListConcat)
.Case("strconcat", tgtok::XStrConcat)
.Default(tgtok::Error);
MultiClass, String,
// !keywords.
- XConcat, XADD, XSRA, XSRL, XSHL, XStrConcat, XCast, XSubst,
+ XConcat, XADD, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, XSubst,
XForEach, XHead, XTail, XEmpty, XIf, XEq,
// Integer value.
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
+ case tgtok::XListConcat:
case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')'
tgtok::TokKind OpTok = Lex.getCode();
SMLoc OpLoc = Lex.getLoc();
case tgtok::XSRL: Code = BinOpInit::SRL; 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::XListConcat:
+ Code = BinOpInit::LISTCONCAT;
+ // We don't know the list type until we parse the first argument
+ break;
case tgtok::XStrConcat:
Code = BinOpInit::STRCONCAT;
Type = StringRecTy::get();
}
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
// shorthand for nesting them.
- if (Code == BinOpInit::STRCONCAT) {
+ if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) {
while (InitList.size() > 2) {
Init *RHS = InitList.pop_back_val();
RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))
/// SimpleValue ::= SHLTOK '(' Value ',' Value ')'
/// SimpleValue ::= SRATOK '(' Value ',' Value ')'
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
+/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
///
Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XSRL:
case tgtok::XSHL:
case tgtok::XEq:
+ case tgtok::XListConcat:
case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf:
case tgtok::XForEach:
--- /dev/null
+// 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"]>;