Index: docs/TableGen/LangIntro.rst =================================================================== --- docs/TableGen/LangIntro.rst +++ docs/TableGen/LangIntro.rst @@ -165,6 +165,19 @@ remaining elements in the list may be arbitrary other values, including nested ```dag``' values. +``!con(a, b, ...)`` + Concatenate two or more DAG nodes. Their operations must equal. + + Example: !con((op a1:$name1, a2:$name2), (op b1:$name3)) results in + the DAG node (op a1:$name1, a2:$name2, b1:$name3). + +``!dag(op, children, names)`` + Generate a DAG node programmatically. 'children' and 'names' must be lists + of equal length or unset ('?'). + + Example: !dag(op, [a1, a2], ["name1", "name2"]) results in + (op a1:$name1, a2:$name2). + ``!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. Index: docs/TableGen/LangRef.rst =================================================================== --- docs/TableGen/LangRef.rst +++ docs/TableGen/LangRef.rst @@ -99,7 +99,7 @@ :!add !shl !sra !srl !and :!or !empty !subst !foreach !strconcat :!cast !listconcat !size !foldl - :!isa + :!isa !dag Syntax Index: include/llvm/TableGen/Record.h =================================================================== --- include/llvm/TableGen/Record.h +++ include/llvm/TableGen/Record.h @@ -856,7 +856,7 @@ /// !op (X, Y, Z) - Combine two inits. class TernOpInit : public OpInit, public FoldingSetNode { public: - enum TernaryOp : uint8_t { SUBST, FOREACH, IF }; + enum TernaryOp : uint8_t { SUBST, FOREACH, IF, DAG }; private: Init *LHS, *MHS, *RHS; Index: lib/TableGen/Record.cpp =================================================================== --- lib/TableGen/Record.cpp +++ lib/TableGen/Record.cpp @@ -1114,6 +1114,30 @@ } break; } + + case DAG: { + ListInit *MHSl = dyn_cast<ListInit>(MHS); + ListInit *RHSl = dyn_cast<ListInit>(RHS); + bool MHSok = MHSl || isa<UnsetInit>(MHS); + bool RHSok = RHSl || isa<UnsetInit>(RHS); + + if (isa<UnsetInit>(MHS) && isa<UnsetInit>(RHS)) + break; // Typically prevented by the parser, but might happen with template args + + if (MHSok && RHSok && (!MHSl || !RHSl || MHSl->size() == RHSl->size())) { + SmallVector<std::pair<Init *, StringInit *>, 8> Children; + unsigned Size = MHSl ? MHSl->size() : RHSl->size(); + for (unsigned i = 0; i != Size; ++i) { + Init *Node = MHSl ? MHSl->getElement(i) : UnsetInit::get(); + Init *Name = RHSl ? RHSl->getElement(i) : UnsetInit::get(); + if (!isa<StringInit>(Name) && !isa<UnsetInit>(Name)) + return const_cast<TernOpInit *>(this); + Children.emplace_back(Node, dyn_cast<StringInit>(Name)); + } + return DagInit::get(LHS, nullptr, Children); + } + break; + } } return const_cast<TernOpInit *>(this); @@ -1155,6 +1179,7 @@ case SUBST: Result = "!subst"; break; case FOREACH: Result = "!foreach"; break; case IF: Result = "!if"; break; + case DAG: Result = "!dag"; break; } return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " + RHS->getAsString() + ")"; Index: lib/TableGen/TGLexer.h =================================================================== --- lib/TableGen/TGLexer.h +++ lib/TableGen/TGLexer.h @@ -48,7 +48,7 @@ // !keywords. XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, - XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, + XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag, // Integer value. IntVal, Index: lib/TableGen/TGLexer.cpp =================================================================== --- lib/TableGen/TGLexer.cpp +++ lib/TableGen/TGLexer.cpp @@ -473,6 +473,7 @@ .Case("tail", tgtok::XTail) .Case("size", tgtok::XSize) .Case("con", tgtok::XConcat) + .Case("dag", tgtok::XDag) .Case("add", tgtok::XADD) .Case("and", tgtok::XAND) .Case("or", tgtok::XOR) Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -1159,6 +1159,7 @@ ->Fold(CurRec, CurMultiClass); } + case tgtok::XDag: case tgtok::XIf: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' TernOpInit::TernaryOp Code; @@ -1168,6 +1169,11 @@ Lex.Lex(); // eat the operation switch (LexCode) { default: llvm_unreachable("Unhandled code!"); + case tgtok::XDag: + Code = TernOpInit::DAG; + Type = DagRecTy::get(); + ItemType = nullptr; + break; case tgtok::XIf: Code = TernOpInit::IF; break; @@ -1190,6 +1196,7 @@ } Lex.Lex(); // eat the ',' + SMLoc MHSLoc = Lex.getLoc(); Init *MHS = ParseValue(CurRec, ItemType); if (!MHS) return nullptr; @@ -1200,6 +1207,7 @@ } Lex.Lex(); // eat the ',' + SMLoc RHSLoc = Lex.getLoc(); Init *RHS = ParseValue(CurRec, ItemType); if (!RHS) return nullptr; @@ -1212,6 +1220,36 @@ switch (LexCode) { default: llvm_unreachable("Unhandled code!"); + case tgtok::XDag: { + TypedInit *MHSt = dyn_cast<TypedInit>(MHS); + if (!MHSt && !isa<UnsetInit>(MHS)) { + Error(MHSLoc, "could not determine type of the child list in !dag"); + return nullptr; + } + if (MHSt && !isa<ListRecTy>(MHSt->getType())) { + Error(MHSLoc, Twine("expected list of children, got type '") + + MHSt->getType()->getAsString() + "'"); + return nullptr; + } + + TypedInit *RHSt = dyn_cast<TypedInit>(RHS); + if (!RHSt && !isa<UnsetInit>(RHS)) { + Error(RHSLoc, "could not determine type of the name list in !dag"); + return nullptr; + } + if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) { + Error(RHSLoc, Twine("expected list<string>, got type '") + + RHSt->getType()->getAsString() + "'"); + return nullptr; + } + + if (!MHSt && !RHSt) { + Error(MHSLoc, + "cannot have both unset children and unset names in !dag"); + return nullptr; + } + break; + } case tgtok::XIf: { RecTy *MHSTy = nullptr; RecTy *RHSTy = nullptr; @@ -1728,6 +1766,7 @@ case tgtok::XCast: // Value ::= !unop '(' Value ')' case tgtok::XIsA: case tgtok::XConcat: + case tgtok::XDag: case tgtok::XADD: case tgtok::XAND: case tgtok::XOR: Index: test/TableGen/dag-functional.td =================================================================== --- /dev/null +++ test/TableGen/dag-functional.td @@ -0,0 +1,53 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def A0 { +// CHECK: dag ret = (ops); +// CHECK: } + +// CHECK: def A1 { +// CHECK: dag ret = (ops 1:$a, 2:$b); +// CHECK: } + +// CHECK: def B0 { +// CHECK: dag ret = (ops); +// CHECK: } + +// CHECK: def B1 { +// CHECK: dag ret = (ops 1:$a, 2:$b); +// CHECK: } + +// CHECK: def C0 { +// CHECK: dag ret1 = (ops ?:$a, ?:$b); +// CHECK: dag ret2 = (ops 1, 2); +// CHECK: } + +def ops; + +class A<list<int> nodes, list<string> names> { + dag ret = !dag(ops, nodes, names); +} + +class Node<int val, string name> { + int Val = val; + string Name = name; +} + +class B<list<Node> nodes> { + dag ret = !foldl((ops), nodes, lhs, rhs, !con(lhs, !dag(ops, [rhs.Val], [rhs.Name]))); +} + +def A0 : A<[], []>; +def A1 : A<[1, 2], ["a", "b"]>; + +def B0 : B<[]>; +def B1 : B<[Node<1, "a">, Node<2, "b">]>; + +class C<list<int> nodes, list<string> names> { + dag ret1 = !dag(ops, ?, names); + dag ret2 = !dag(ops, nodes, ?); +} + +def C0 : C<[1, 2], ["a", "b"]>;