Index: docs/TableGen/LangIntro.rst =================================================================== --- docs/TableGen/LangIntro.rst +++ docs/TableGen/LangIntro.rst @@ -160,6 +160,12 @@ 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. Index: docs/TableGen/LangRef.rst =================================================================== --- docs/TableGen/LangRef.rst +++ docs/TableGen/LangRef.rst @@ -93,7 +93,7 @@ BangOperator: one of :!eq !if !head !tail !con :!add !shl !sra !srl - :!cast !empty !subst !foreach !strconcat + :!cast !empty !subst !foreach !listconcat !strconcat Syntax ====== Index: include/llvm/TableGen/Record.h =================================================================== --- include/llvm/TableGen/Record.h +++ include/llvm/TableGen/Record.h @@ -929,7 +929,8 @@ /// 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; Index: lib/TableGen/Record.cpp =================================================================== --- lib/TableGen/Record.cpp +++ lib/TableGen/Record.cpp @@ -918,6 +918,18 @@ } break; } + case LISTCONCAT: { + ListInit *LHSs = dyn_cast(LHS); + ListInit *RHSs = dyn_cast(RHS); + if (LHSs && RHSs) { + std::vector Args; + Args.insert(Args.end(), LHSs->begin(), LHSs->end()); + Args.insert(Args.end(), RHSs->begin(), RHSs->end()); + return ListInit::get( + Args, static_cast(LHSs->getType())->getElementType()); + } + break; + } case STRCONCAT: { StringInit *LHSs = dyn_cast(LHS); StringInit *RHSs = dyn_cast(RHS); @@ -987,6 +999,7 @@ 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() + ")"; Index: lib/TableGen/TGLexer.h =================================================================== --- lib/TableGen/TGLexer.h +++ lib/TableGen/TGLexer.h @@ -47,7 +47,7 @@ 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. Index: lib/TableGen/TGLexer.cpp =================================================================== --- lib/TableGen/TGLexer.cpp +++ lib/TableGen/TGLexer.cpp @@ -478,6 +478,7 @@ .Case("empty", tgtok::XEmpty) .Case("subst", tgtok::XSubst) .Case("foreach", tgtok::XForEach) + .Case("listconcat", tgtok::XListConcat) .Case("strconcat", tgtok::XStrConcat) .Default(tgtok::Error); Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -903,6 +903,7 @@ 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(); @@ -919,6 +920,10 @@ 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(); @@ -949,9 +954,22 @@ } 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(InitList[0])) + Type = Arg0->getType(); + else if (ListInit *Arg0 = dyn_cast(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)) @@ -1134,6 +1152,7 @@ /// 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, @@ -1417,6 +1436,7 @@ 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: Index: test/TableGen/listconcat.td =================================================================== --- /dev/null +++ test/TableGen/listconcat.td @@ -0,0 +1,18 @@ +// RUN: llvm-tblgen %s | FileCheck %s + +// CHECK: class Y Y:S = ?> { +// CHECK: list T1 = !listconcat(Y:S, ["foo"]); +// CHECK: list T2 = !listconcat(Y:S, !listconcat(["foo"], !listconcat(Y:S, ["bar", "baz"]))); +// CHECK: } + +// CHECK: def Z { +// CHECK: list T1 = ["fu", "foo"]; +// CHECK: list T2 = ["fu", "foo", "fu", "bar", "baz"]; +// CHECK: } + +class Y S> { + list T1 = !listconcat(S, ["foo"]); + list T2 = !listconcat(S, ["foo"], S, ["bar", "baz"]); +} + +def Z : Y<["fu"]>;