diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -221,13 +221,14 @@ BangOperator: one of : !add !and !cast !con !dag : !div !empty !eq !exists !filter - : !find !foldl !foreach !ge !getdagop - : !gt !head !if !interleave !isa - : !le !listconcat !listremove !listsplat !logtwo - : !lt !mul !ne !not !or - : !range !setdagop !shl !size !sra - : !srl !strconcat !sub !subst !substr - : !tail !tolower !toupper !xor + : !find !foldl !foreach !ge !getdagargs + : !getdagnames !getdagop !gt !head !if + : !interleave !isa !le !listconcat !listremove + : !listsplat !logtwo !lt !mul !ne + : !not !or !range !setdagop !shl + : !size !sra !srl !strconcat !sub + : !subst !substr !tail !tolower !toupper + : !xor The ``!cond`` operator has a slightly different syntax compared to other bang operators, so it is defined separately: @@ -1368,7 +1369,8 @@ DAG. The following bang operators are useful for working with DAGs: -``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagop``, ``!setdagop``, ``!size``. +``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagargs``, +``!getdagnames``, ``!getdagop``, ``!setdagop``, ``!size``. Defvar in a record body ----------------------- @@ -1711,6 +1713,16 @@ This operator produces 1 if *a* is greater than or equal to *b*; 0 otherwise. The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values. +``!getdagargs<``\ *type*\ ``>(``\ *dag*\ ``)`` + This operator produces the list of arguments of the specified common *type* + from the given *dag* node. Due to limitations of the type system, if not + all arguments are not of the specified type or derived from the specified + base class, ``?`` is returned instead. + +``!getdagnames<``\ *type*\ ``>(``\ *dag*\ ``)`` + This operator produces the list of argument names from the given *dag* + node. ``?`` is used for unnamed arguments. + ``!getdagop(``\ *dag*\ ``)`` --or-- ``!getdagop<``\ *type*\ ``>(``\ *dag*\ ``)`` This operator produces the operator of the given *dag* node. Example: ``!getdagop((foo 1, 2))`` results in ``foo``. Recall that 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 @@ -781,6 +781,8 @@ SIZE, EMPTY, GETDAGOP, + GETDAGARGS, + GETDAGNAMES, LOG2 }; 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 @@ -876,6 +876,37 @@ } break; + case GETDAGARGS: + if (DagInit *Dag = dyn_cast(LHS)) { + SmallVector Args; + RecTy *EltTy = cast(getType())->getElementType(); + for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { + Init *Arg = Dag->getArg(i); + // Check argument types. If it's a typed value but not the same type or + // derived from the same base class, return `?` instead. + if (TypedInit *TI = dyn_cast(Dag->getArg(i))) { + if (!TI->getType()->typeIsConvertibleTo(EltTy)) + Arg = UnsetInit::get(RK); + } + Args.push_back(Arg); + } + return ListInit::get(Args, EltTy); + } + break; + + case GETDAGNAMES: + if (DagInit *Dag = dyn_cast(LHS)) { + SmallVector ArgNames; + for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { + Init *ArgName = Dag->getArgName(i); + if (!ArgName) + ArgName = UnsetInit::get(RK); + ArgNames.push_back(ArgName); + } + return ListInit::get(ArgNames, StringRecTy::get(Dag->getRecordKeeper())); + } + break; + case LOG2: if (IntInit *LHSi = dyn_cast_or_null( LHS->convertInitializerTo(IntRecTy::get(RK)))) { @@ -915,6 +946,13 @@ case SIZE: Result = "!size"; break; case EMPTY: Result = "!empty"; break; case GETDAGOP: Result = "!getdagop"; break; + case GETDAGARGS: + Result = "!getdagargs<" + + cast(getType())->getElementType()->getAsString() + ">"; + break; + case GETDAGNAMES: + Result = "!getdagnames"; + break; case LOG2 : Result = "!logtwo"; break; case TOLOWER: Result = "!tolower"; 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 @@ -31,35 +31,108 @@ namespace tgtok { enum TokKind { // Markers - Eof, Error, + Eof, + Error, // Tokens with no info. - minus, plus, // - + - l_square, r_square, // [ ] - l_brace, r_brace, // { } - l_paren, r_paren, // ( ) - less, greater, // < > - colon, semi, // : ; - comma, dot, // , . - equal, question, // = ? - paste, // # - dotdotdot, // ... + minus, + plus, // - + + l_square, + r_square, // [ ] + l_brace, + r_brace, // { } + l_paren, + r_paren, // ( ) + less, + greater, // < > + colon, + semi, // : ; + comma, + dot, // , . + equal, + question, // = ? + paste, // # + dotdotdot, // ... // Reserved keywords. ('ElseKW' is named to distinguish it from the // existing 'Else' that means the preprocessor #else.) - Assert, Bit, Bits, Class, Code, Dag, Def, Defm, Defset, Defvar, ElseKW, - FalseKW, Field, Foreach, If, In, Include, Int, Let, List, MultiClass, - String, Then, TrueKW, + Assert, + Bit, + Bits, + Class, + Code, + Dag, + Def, + Defm, + Defset, + Defvar, + ElseKW, + FalseKW, + Field, + Foreach, + If, + In, + Include, + Int, + Let, + List, + MultiClass, + String, + Then, + TrueKW, // Bang operators. - XConcat, XADD, XSUB, XMUL, XDIV, XNOT, XLOG2, XAND, XOR, XXOR, XSRA, XSRL, - XSHL, XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind, - XCast, XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf, - XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp, - XExists, XListRemove, XToLower, XToUpper, XRange, + XConcat, + XADD, + XSUB, + XMUL, + XDIV, + XNOT, + XLOG2, + XAND, + XOR, + XXOR, + XSRA, + XSRL, + XSHL, + XListConcat, + XListSplat, + XStrConcat, + XInterleave, + XSubstr, + XFind, + XCast, + XSubst, + XForEach, + XFilter, + XFoldl, + XHead, + XTail, + XSize, + XEmpty, + XIf, + XCond, + XEq, + XIsA, + XDag, + XNe, + XLe, + XLt, + XGe, + XGt, + XSetDagOp, + XGetDagOp, + XExists, + XListRemove, + XToLower, + XToUpper, + XRange, + XGetDagArgs, + XGetDagNames, // Boolean literals. - TrueVal, FalseVal, + TrueVal, + FalseVal, // Integer value. IntVal, @@ -69,11 +142,18 @@ BinaryIntVal, // String valued tokens. - Id, StrVal, VarName, CodeFragment, + Id, + StrVal, + VarName, + CodeFragment, // Preprocessing tokens for internal usage by the lexer. // They are never returned as a result of Lex(). - Ifdef, Ifndef, Else, Endif, Define + Ifdef, + Ifndef, + Else, + Endif, + Define }; } 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 @@ -592,6 +592,8 @@ .Case("find", tgtok::XFind) .Cases("setdagop", "setop", tgtok::XSetDagOp) // !setop is deprecated. .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated. + .Case("getdagargs", tgtok::XGetDagArgs) + .Case("getdagnames", tgtok::XGetDagNames) .Case("exists", tgtok::XExists) .Case("tolower", tgtok::XToLower) .Case("toupper", tgtok::XToUpper) 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 @@ -1154,6 +1154,8 @@ case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: + case tgtok::XGetDagArgs: + case tgtok::XGetDagNames: case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')' UnOpInit::UnaryOp Code; RecTy *Type = nullptr; @@ -1232,6 +1234,21 @@ } Code = UnOpInit::GETDAGOP; break; + case tgtok::XGetDagArgs: + Lex.Lex(); // eat the operation + Code = UnOpInit::GETDAGARGS; + Type = ParseOperatorType(); + if (!Type) { + TokError("did not get type for !getdagtypes operator"); + return nullptr; + } + Type = ListRecTy::get(Type); + break; + case tgtok::XGetDagNames: + Lex.Lex(); // eat the operation + Code = UnOpInit::GETDAGNAMES; + Type = ListRecTy::get(StringRecTy::get(Records)); + break; } if (!consume(tgtok::l_paren)) { TokError("expected '(' after unary operator"); @@ -2724,6 +2741,8 @@ case tgtok::XCast: case tgtok::XToLower: case tgtok::XToUpper: + case tgtok::XGetDagArgs: + case tgtok::XGetDagNames: case tgtok::XGetDagOp: // Value ::= !unop '(' Value ')' case tgtok::XExists: case tgtok::XIsA: diff --git a/llvm/test/TableGen/getsetop.td b/llvm/test/TableGen/getsetop.td --- a/llvm/test/TableGen/getsetop.td +++ b/llvm/test/TableGen/getsetop.td @@ -13,6 +13,13 @@ def bar: Base; def qux: OtherBase; +class OpBase; +class OpOtherBase; + +def opA : OpBase; +def opB : OpBase; +def opC : OpOtherBase; + def test { dag orig = (foo 1, 2:$a, $b); dag another = (qux "hello", $world); @@ -61,4 +68,44 @@ // ERROR3: error: type for !getdagop must be a record type int ridiculousCast = !getdagop(orig); #endif + + dag in1 = (foo 1:$a, 2:$b, 3:$c); + // CHECK: list in1Args = [1, 2, 3]; + list in1Args = !getdagargs(in1); + list> in1ArgsAsB8 = !getdagargs>(in1); + // CHECK: list in1Names = ["a", "b", "c"]; + list in1Names = !getdagnames(in1); + + dag in2 = (foo 1:$a, ?:$b, 3:$c); + // CHECK: list in2Args = [1, ?, 3]; + list in2Args = !getdagargs(in2); + // CHECK: list in2Names = ["a", "b", "c"]; + list in2Names = !getdagnames(in2); + + dag in3 = (foo 1:$a, 2, 3:$c); + // CHECK: list in3Args = [1, 2, 3]; + list in3Args = !getdagargs(in3); + // The 2nd argument has no name, `?` is returned. + // CHECK: list in3Names = ["a", ?, "c"]; + list in3Names = !getdagnames(in3); + + dag in4 = (foo 1:$a, "x":$b, 3:$c); + // The 2nd argument is not of type `int`, `?` is returned. + // CHECK: list in4Args = [1, ?, 3]; + list in4Args = !getdagargs(in4); + + dag in5 = (foo opA:$a, opB:$b, opC:$c); + // The 3rd argument doesn't share the same base class as `OpBase`, `?` is + // returned. + // CHECK: list in5Args = [opA, opB, ?]; + list in5Args = !getdagargs(in5); + + dag in6 = (foo opA:$a, opB:$b, opB:$c); + // CHECK: list in6Args = [opA, opB, opB]; + list in6Args = !getdagargs(in6); + + dag in7 = (foo opA:$a, (bar opA:$lhs, opB:$rhs), opB:$c); + // The 2nd argument is another dag, `?` is returned. + // CHECK: list in7Args = [opA, ?, opB]; + list in7Args = !getdagargs(in7); }