diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst --- a/llvm/docs/TableGen/LangIntro.rst +++ b/llvm/docs/TableGen/LangIntro.rst @@ -166,10 +166,18 @@ 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). +``!conp(a, b, ...)`` + Concatenate two or more DAG nodes. For ``!con``, their operations must be + equal. For ``!conp`` ('permissive'), they need not be equal, and the first + DAG node's operation is copied into the result. + + Example: ``!con((op a1:$name1, a2:$name2), (op b1:$name3))`` results in + the DAG node ``(op a1:$name1, a2:$name2, b1:$name3)``. + + ``!conp((FirstOp a1:$name1, a2:$name2), (SecondOp b1:$name3))`` results in + the DAG node ``(FirstOp a1:$name1, a2:$name2, b1:$name3)``. This would be + an error if it had used ``!con`` instead of ``!conp``. ``!dag(op, children, names)`` Generate a DAG node programmatically. 'children' and 'names' must be lists diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst --- a/llvm/docs/TableGen/LangRef.rst +++ b/llvm/docs/TableGen/LangRef.rst @@ -100,7 +100,7 @@ :!or !empty !subst !foreach !strconcat :!cast !listconcat !size !foldl :!isa !dag !le !lt !ge - :!gt !ne !mul !listsplat + :!gt !ne !mul !listsplat !conp TableGen also has !cond operator that needs a slightly different syntax compared to other "bang operators": diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -801,8 +801,8 @@ class BinOpInit : public OpInit, public FoldingSetNode { public: enum BinaryOp : uint8_t { ADD, MUL, AND, OR, SHL, SRA, SRL, LISTCONCAT, - LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, - GT }; + LISTSPLAT, STRCONCAT, CONCAT, CONCAT_PERMISSIVE, + EQ, NE, LE, LT, GE, GT }; private: Init *LHS, *RHS; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -881,7 +881,8 @@ Init *BinOpInit::Fold(Record *CurRec) const { switch (getOpcode()) { - case CONCAT: { + case CONCAT: + case CONCAT_PERMISSIVE: { DagInit *LHSs = dyn_cast(LHS); DagInit *RHSs = dyn_cast(RHS); if (LHSs && RHSs) { @@ -889,7 +890,7 @@ DefInit *ROp = dyn_cast(RHSs->getOperator()); if (!LOp || !ROp) break; - if (LOp->getDef() != ROp->getDef()) { + if (getOpcode() != CONCAT_PERMISSIVE && LOp->getDef() != ROp->getDef()) { PrintFatalError(Twine("Concatenated Dag operators do not match: '") + LHSs->getAsString() + "' vs. '" + RHSs->getAsString() + "'"); @@ -1021,6 +1022,7 @@ std::string Result; switch (getOpcode()) { case CONCAT: Result = "!con"; break; + case CONCAT_PERMISSIVE: Result = "!conp"; break; case ADD: Result = "!add"; break; case MUL: Result = "!mul"; break; case AND: Result = "!and"; break; diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -51,7 +51,7 @@ // !keywords. XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat, XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, - XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, + XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XConcatP, // Integer value. IntVal, diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -543,6 +543,7 @@ .Case("tail", tgtok::XTail) .Case("size", tgtok::XSize) .Case("con", tgtok::XConcat) + .Case("conp", tgtok::XConcatP) .Case("dag", tgtok::XDag) .Case("add", tgtok::XADD) .Case("mul", tgtok::XMUL) diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -1040,6 +1040,7 @@ } case tgtok::XConcat: + case tgtok::XConcatP: case tgtok::XADD: case tgtok::XMUL: case tgtok::XAND: @@ -1064,6 +1065,7 @@ switch (OpTok) { default: llvm_unreachable("Unhandled code!"); case tgtok::XConcat: Code = BinOpInit::CONCAT; break; + case tgtok::XConcatP: Code = BinOpInit::CONCAT_PERMISSIVE; break; case tgtok::XADD: Code = BinOpInit::ADD; break; case tgtok::XMUL: Code = BinOpInit::MUL; break; case tgtok::XAND: Code = BinOpInit::AND; break; @@ -1088,6 +1090,7 @@ default: llvm_unreachable("Unhandled code!"); case tgtok::XConcat: + case tgtok::XConcatP: Type = DagRecTy::get(); ArgType = DagRecTy::get(); break; @@ -1233,9 +1236,9 @@ // We allow multiple operands to associative operators like !strconcat as // shorthand for nesting them. if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT || - Code == BinOpInit::CONCAT || Code == BinOpInit::ADD || - Code == BinOpInit::AND || Code == BinOpInit::OR || - Code == BinOpInit::MUL) { + Code == BinOpInit::CONCAT || Code == BinOpInit::CONCAT_PERMISSIVE || + Code == BinOpInit::ADD || Code == BinOpInit::MUL || + Code == BinOpInit::AND || Code == BinOpInit::OR) { while (InitList.size() > 2) { Init *RHS = InitList.pop_back_val(); RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))->Fold(CurRec); @@ -2065,6 +2068,7 @@ case tgtok::XCast: // Value ::= !unop '(' Value ')' case tgtok::XIsA: case tgtok::XConcat: + case tgtok::XConcatP: case tgtok::XDag: case tgtok::XADD: case tgtok::XMUL: diff --git a/llvm/test/TableGen/dag-functional.td b/llvm/test/TableGen/dag-functional.td --- a/llvm/test/TableGen/dag-functional.td +++ b/llvm/test/TableGen/dag-functional.td @@ -38,6 +38,7 @@ // CHECK: def D { // CHECK: dag d1 = (ops 1, ?:$name1, 2, 3); +// CHECK: dag d2 = (ops 1, ?:$name1, 2, 3); // CHECK: } // CHECK: def E0 { @@ -47,6 +48,8 @@ class Ops; def ops : Ops; +def dummy : Ops; +def dummy2 : Ops; class Node { int Val = val; @@ -106,6 +109,7 @@ def D { dag d1 = !con((ops 1), (ops $name1), (ops), (ops 2, 3)); + dag d2 = !conp((ops 1), (dummy $name1), (dummy2), (dummy 2, 3)); } class E {