Index: llvm/trunk/docs/TableGen/LangIntro.rst =================================================================== --- llvm/trunk/docs/TableGen/LangIntro.rst +++ llvm/trunk/docs/TableGen/LangIntro.rst @@ -165,6 +165,24 @@ 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 ('?'). 'names' must be a 'list'. + + Due to limitations of the type system, 'children' must be a list of items + of a common type. In practice, this means that they should either have the + same type or be records with a common superclass. Mixing dag and non-dag + items is not possible. + + 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: llvm/trunk/docs/TableGen/LangRef.rst =================================================================== --- llvm/trunk/docs/TableGen/LangRef.rst +++ llvm/trunk/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: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/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: llvm/trunk/lib/TableGen/Record.cpp =================================================================== --- llvm/trunk/lib/TableGen/Record.cpp +++ llvm/trunk/lib/TableGen/Record.cpp @@ -1114,6 +1114,30 @@ } break; } + + case DAG: { + ListInit *MHSl = dyn_cast(MHS); + ListInit *RHSl = dyn_cast(RHS); + bool MHSok = MHSl || isa(MHS); + bool RHSok = RHSl || isa(RHS); + + if (isa(MHS) && isa(RHS)) + break; // Typically prevented by the parser, but might happen with template args + + if (MHSok && RHSok && (!MHSl || !RHSl || MHSl->size() == RHSl->size())) { + SmallVector, 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(Name) && !isa(Name)) + return const_cast(this); + Children.emplace_back(Node, dyn_cast(Name)); + } + return DagInit::get(LHS, nullptr, Children); + } + break; + } } return const_cast(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: llvm/trunk/lib/TableGen/TGLexer.h =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.h +++ llvm/trunk/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: llvm/trunk/lib/TableGen/TGLexer.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.cpp +++ llvm/trunk/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: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/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(MHS); + if (!MHSt && !isa(MHS)) { + Error(MHSLoc, "could not determine type of the child list in !dag"); + return nullptr; + } + if (MHSt && !isa(MHSt->getType())) { + Error(MHSLoc, Twine("expected list of children, got type '") + + MHSt->getType()->getAsString() + "'"); + return nullptr; + } + + TypedInit *RHSt = dyn_cast(RHS); + if (!RHSt && !isa(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, 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: llvm/trunk/test/TableGen/dag-functional.td =================================================================== --- llvm/trunk/test/TableGen/dag-functional.td +++ llvm/trunk/test/TableGen/dag-functional.td @@ -0,0 +1,95 @@ +// 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 A2 { +// CHECK: dag ret = (ops (ops ?:$name):$a, (ops 1):$b, (ops "foo"):$c); +// CHECK: } + +// CHECK: def A3 { +// CHECK: dag ret = (ops NodeA0:$a, NodeB0:$b); +// CHECK: } + +// CHECK: def A4 { +// CHECK: dag ret = (ops NodeA0, NodeB0); +// 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 Node { + int Val = val; + string Name = name; +} + +class Aint nodes, list names> { + dag ret = !dag(ops, nodes, names); +} + +class Adag nodes, list names> { + dag ret = !dag(ops, nodes, names); +} + +class NodeBase; + +class NodeA : NodeBase { + int x = val; +} + +class NodeB : NodeBase { + int y = val; +} + +class Anode nodes, list names> { + dag ret = !dag(ops, nodes, names); +} + +class B nodes> { + dag ret = !foldl((ops), nodes, lhs, rhs, !con(lhs, !dag(ops, [rhs.Val], [rhs.Name]))); +} + +def A0 : Aint<[], []>; +def A1 : Aint<[1, 2], ["a", "b"]>; + +def A2 : Adag<[(ops $name), (ops 1), (ops "foo")], ["a", "b", "c"]>; + +def NodeA0 : NodeA<0>; +def NodeB0 : NodeB<0>; + +def A3 : Anode<[NodeA0, NodeB0], ["a", "b"]>; + +def A4 { + // Like A3, but with a literal list directly in the !dag. + dag ret = !dag(ops, [NodeA0, NodeB0], ?); +} + +def B0 : B<[]>; +def B1 : B<[Node<1, "a">, Node<2, "b">]>; + +class C nodes, list names> { + dag ret1 = !dag(ops, ?, names); + dag ret2 = !dag(ops, nodes, ?); +} + +def C0 : C<[1, 2], ["a", "b"]>;