Index: docs/TableGen/LangIntro.rst =================================================================== --- docs/TableGen/LangIntro.rst +++ docs/TableGen/LangIntro.rst @@ -165,21 +165,21 @@ remaining elements in the list may be arbitrary other values, including nested ```dag``' values. +``!concat(a, b, ...)`` + A string, code fragment or list that is the result of concatenating the 'a' + and 'b' elements. More than two arguments are accepted with the result being + the concatenation of all the elements given. + ``!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. + Alias for !concat. ``!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 - of all the strings given. + Alias for !concat. ``str1#str2`` - "#" (paste) is a shorthand for !strconcat. It may concatenate things that - are not quoted strings, in which case an implicit !cast is done on - the operand of the paste. + "#" (paste) is a shorthand for !concat. It may concatenate things that are + not quoted strings, in which case an implicit !cast is done on the + operand of the paste. ``!cast(a)`` A symbol of type *type* obtained by looking up the string 'a' in the symbol @@ -389,9 +389,9 @@ class inst; multiclass ri_inst { - def _rr : inst; - def _ri : inst; } @@ -415,11 +415,11 @@ class inst; class rrinst - : inst; class riinst - : inst; // Instantiations of the ri_inst multiclass. Index: include/llvm/TableGen/Record.h =================================================================== --- include/llvm/TableGen/Record.h +++ include/llvm/TableGen/Record.h @@ -801,8 +801,7 @@ /// !op (X, Y) - Combine two inits. class BinOpInit : public OpInit, public FoldingSetNode { public: - enum BinaryOp : uint8_t { ADD, AND, OR, SHL, SRA, SRL, LISTCONCAT, - STRCONCAT, CONCAT, EQ }; + enum BinaryOp : uint8_t { ADD, AND, OR, SHL, SRA, SRL, CONCAT, CON, EQ }; private: Init *LHS, *RHS; Index: lib/TableGen/Record.cpp =================================================================== --- lib/TableGen/Record.cpp +++ lib/TableGen/Record.cpp @@ -763,16 +763,15 @@ ProfileBinOpInit(ID, getOpcode(), getLHS(), getRHS(), getType()); } -static StringInit *ConcatStringInits(const StringInit *I0, - const StringInit *I1) { +template static T *ConcatStringLikeInits(const T *I0, const T *I1) { SmallString<80> Concat(I0->getValue()); Concat.append(I1->getValue()); - return StringInit::get(Concat); + return T::get(Concat); } Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { switch (getOpcode()) { - case CONCAT: { + case CON: { DagInit *LHSs = dyn_cast(LHS); DagInit *RHSs = dyn_cast(RHS); if (LHSs && RHSs) { @@ -794,23 +793,24 @@ } break; } - case LISTCONCAT: { - ListInit *LHSs = dyn_cast(LHS); - ListInit *RHSs = dyn_cast(RHS); - if (LHSs && RHSs) { + case CONCAT: { + ListInit *LHSl = dyn_cast(LHS); + ListInit *RHSl = dyn_cast(RHS); + if (LHSl && RHSl) { SmallVector Args; - Args.insert(Args.end(), LHSs->begin(), LHSs->end()); - Args.insert(Args.end(), RHSs->begin(), RHSs->end()); + Args.insert(Args.end(), LHSl->begin(), LHSl->end()); + Args.insert(Args.end(), RHSl->begin(), RHSl->end()); return ListInit::get( - Args, cast(LHSs->getType())->getElementType()); + Args, cast(LHSl->getType())->getElementType()); } - break; - } - case STRCONCAT: { + CodeInit *LHSc = dyn_cast(LHS); + CodeInit *RHSc = dyn_cast(RHS); + if (LHSc && RHSc) + return ConcatStringLikeInits(LHSc, RHSc); StringInit *LHSs = dyn_cast(LHS); StringInit *RHSs = dyn_cast(RHS); if (LHSs && RHSs) - return ConcatStringInits(LHSs, RHSs); + return ConcatStringLikeInits(LHSs, RHSs); break; } case EQ: { @@ -875,7 +875,7 @@ std::string BinOpInit::getAsString() const { std::string Result; switch (getOpcode()) { - case CONCAT: Result = "!con"; break; + case CON: Result = "!con"; break; case ADD: Result = "!add"; break; case AND: Result = "!and"; break; case OR: Result = "!or"; break; @@ -883,8 +883,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; + case CONCAT: Result = "!concat"; break; } return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; } @@ -1896,8 +1895,8 @@ // Shortcut for the common case of concatenating two strings. if (const StringInit *I0s = dyn_cast(I0)) if (const StringInit *I1s = dyn_cast(I1)) - return ConcatStringInits(I0s, I1s); - return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get()); + return ConcatStringLikeInits(I0s, I1s); + return BinOpInit::get(BinOpInit::CONCAT, I0, I1, StringRecTy::get()); } Init *llvm::QualifyName(Record &CurRec, MultiClass *CurMultiClass, Index: lib/TableGen/TGLexer.h =================================================================== --- lib/TableGen/TGLexer.h +++ lib/TableGen/TGLexer.h @@ -47,8 +47,8 @@ MultiClass, String, // !keywords. - XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, - XSubst, XForEach, XHead, XTail, XEmpty, XIf, XEq, + XCon, XADD, XAND, XOR, XSRA, XSRL, XSHL, XConcat, XCast, XSubst, XForEach, + XHead, XTail, XEmpty, XIf, XEq, // Integer value. IntVal, Index: lib/TableGen/TGLexer.cpp =================================================================== --- lib/TableGen/TGLexer.cpp +++ lib/TableGen/TGLexer.cpp @@ -469,7 +469,7 @@ .Case("if", tgtok::XIf) .Case("head", tgtok::XHead) .Case("tail", tgtok::XTail) - .Case("con", tgtok::XConcat) + .Case("con", tgtok::XCon) .Case("add", tgtok::XADD) .Case("and", tgtok::XAND) .Case("or", tgtok::XOR) @@ -480,8 +480,9 @@ .Case("empty", tgtok::XEmpty) .Case("subst", tgtok::XSubst) .Case("foreach", tgtok::XForEach) - .Case("listconcat", tgtok::XListConcat) - .Case("strconcat", tgtok::XStrConcat) + .Case("concat", tgtok::XConcat) + .Case("listconcat", tgtok::XConcat) + .Case("strconcat", tgtok::XConcat) .Default(tgtok::Error); return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -879,7 +879,7 @@ return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec, CurMultiClass); } - case tgtok::XConcat: + case tgtok::XCon: case tgtok::XADD: case tgtok::XAND: case tgtok::XOR: @@ -887,8 +887,7 @@ case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: - case tgtok::XListConcat: - case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XConcat: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); SMLoc OpLoc = Lex.getLoc(); Lex.Lex(); // eat the operation @@ -898,7 +897,7 @@ switch (OpTok) { default: llvm_unreachable("Unhandled code!"); - case tgtok::XConcat: Code = BinOpInit::CONCAT;Type = DagRecTy::get(); break; + case tgtok::XCon: Code = BinOpInit::CON; Type = DagRecTy::get(); break; case tgtok::XADD: Code = BinOpInit::ADD; Type = IntRecTy::get(); break; case tgtok::XAND: Code = BinOpInit::AND; Type = IntRecTy::get(); break; case tgtok::XOR: Code = BinOpInit::OR; Type = IntRecTy::get(); break; @@ -906,13 +905,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(); + case tgtok::XConcat: + Code = BinOpInit::CONCAT; + // We don't know the list type until we parse the first argument break; } @@ -940,22 +936,20 @@ } 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(); + // If we are doing !concat, we should know the type by now + if (OpTok == tgtok::XConcat) { + if (TypedInit *TI = dyn_cast(InitList[0])) + Type = TI->getType(); else { InitList[0]->print(errs()); - Error(OpLoc, "expected a list"); + Error(OpLoc, "expected a typed expression."); return nullptr; } } - // We allow multiple operands to associative operators like !strconcat as + // We allow multiple operands to associative operators like !concat as // shorthand for nesting them. - if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) { + if (Code == BinOpInit::CONCAT) { while (InitList.size() > 2) { Init *RHS = InitList.pop_back_val(); RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type)) @@ -1139,8 +1133,6 @@ /// 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, IDParseMode Mode) { @@ -1243,12 +1235,12 @@ } // We can't return the prototype def here, instead return: - // !cast(!strconcat(NAME, AnonName)). + // !cast(!concat(NAME, AnonName)). const RecordVal *MCNameRV = CurMultiClass->Rec.getValue("NAME"); assert(MCNameRV && "multiclass record must have a NAME"); return UnOpInit::get(UnOpInit::CAST, - BinOpInit::get(BinOpInit::STRCONCAT, + BinOpInit::get(BinOpInit::CONCAT, VarInit::get(MCNameRV->getName(), MCNameRV->getType()), NewRec->getNameInit(), @@ -1445,7 +1437,7 @@ case tgtok::XTail: case tgtok::XEmpty: case tgtok::XCast: // Value ::= !unop '(' Value ')' - case tgtok::XConcat: + case tgtok::XCon: case tgtok::XADD: case tgtok::XAND: case tgtok::XOR: @@ -1453,8 +1445,7 @@ case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: - case tgtok::XListConcat: - case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' @@ -1547,7 +1538,7 @@ case tgtok::paste: SMLoc PasteLoc = Lex.getLoc(); - // Create a !strconcat() operation, first casting each operand to + // Create a !concat() operation, first casting each operand to // a string if necessary. TypedInit *LHS = dyn_cast(Result); @@ -1590,7 +1581,7 @@ break; } - Result = BinOpInit::get(BinOpInit::STRCONCAT, LHS, RHS, + Result = BinOpInit::get(BinOpInit::CONCAT, LHS, RHS, StringRecTy::get())->Fold(CurRec, CurMultiClass); break; } @@ -2361,7 +2352,7 @@ // We have a fully expanded string so there are no operators to // resolve. We should concatenate the given prefix and name. DefName = - BinOpInit::get(BinOpInit::STRCONCAT, + BinOpInit::get(BinOpInit::CONCAT, UnOpInit::get(UnOpInit::CAST, DefmPrefix, StringRecTy::get())->Fold(DefProto, &MC), DefName, StringRecTy::get())->Fold(DefProto, &MC); Index: test/TableGen/listconcat.td =================================================================== --- test/TableGen/listconcat.td +++ test/TableGen/listconcat.td @@ -1,8 +1,8 @@ // 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: list T1 = !concat(Y:S, ["foo"]); +// CHECK: list T2 = !concat(Y:S, !concat(["foo"], !concat(Y:S, ["bar", "baz"]))); // CHECK: } // CHECK: def Z { Index: test/TableGen/strconcat.td =================================================================== --- test/TableGen/strconcat.td +++ test/TableGen/strconcat.td @@ -1,24 +1,28 @@ // RUN: llvm-tblgen %s | FileCheck %s -// CHECK: class Y { -// CHECK: string T = !strconcat(Y:S, "foo"); -// CHECK: string T2 = !strconcat(Y:S, !strconcat("foo", !strconcat(Y:S, "bar"))); +// CHECK: class Y { +// CHECK: string T = !concat(Y:S, "foo"); +// CHECK: string T2 = !concat(Y:S, !concat("foo", !concat(Y:S, "bar"))); // CHECK: string S = "foobar"; +// CHECK: code T3 = !concat(Y:C, [{ ; }]); // CHECK: } // CHECK: def Z { // CHECK: string T = "fufoo"; // CHECK: string T2 = "fufoofubar"; // CHECK: string S = "foobar"; +// CHECK: code T3 = [{ 1 ; }]; // CHECK: } -class Y { +class Y { string T = !strconcat(S, "foo"); // More than two arguments is equivalent to nested calls string T2 = !strconcat(S, "foo", S, "bar"); // String values concatenate lexically, as in C. string S = "foo" "bar"; + + code T3 = !strconcat(C, [{ ; }]); } -def Z : Y<"fu">; +def Z : Y<"fu", [{ 1 }]>;