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 !getdagarg + : !getdagname !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``, ``!getdagarg``, ``!getdagname``, +``!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. +``!getdagarg<``\ *type*\ ``>(``\ *dag*\ ``,``\ *key*\ ``)`` + This operator retrieves the argument from the given *dag* node by the + specified *key*, which is either an integer index or a string name. If that + argument is not convertible to the specified *type*, ``?`` is returned. + +``!getdagname(``\ *dag*\ ``,``\ *index*\ ``)`` + This operator retrieves the argument name from the given *dag* node by the + specified *index*. If that argument has no name associated, ``?`` is + returned. + ``!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 @@ -858,7 +858,9 @@ LT, GE, GT, - SETDAGOP + GETDAGARG, + GETDAGNAME, + SETDAGOP, }; private: 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 @@ -1276,6 +1276,69 @@ return BitInit::get(getRecordKeeper(), *Result); break; } + case GETDAGARG: { + DagInit *Dag = dyn_cast(LHS); + if (!Dag) + break; + + // Helper returning the specified argument. + auto getDagArgAsType = [](DagInit *Dag, unsigned Pos, + RecTy *Type) -> Init * { + assert(Pos < Dag->getNumArgs()); + Init *Arg = Dag->getArg(Pos); + if (auto *TI = dyn_cast(Arg)) + if (!TI->getType()->typeIsConvertibleTo(Type)) + return UnsetInit::get(Dag->getRecordKeeper()); + return Arg; + }; + + // Accessor by index + if (IntInit *Idx = dyn_cast(RHS)) { + int64_t Pos = Idx->getValue(); + if (Pos < 0 || Pos >= Dag->getNumArgs()) { + // The index is out-of-range. + PrintFatalError(CurRec->getLoc(), + Twine("!getdagarg index is out of range 0...") + + std::to_string(Dag->getNumArgs()) + ": " + + std::to_string(Pos)); + } + return getDagArgAsType(Dag, Pos, getType()); + } + // Accessor by name + if (StringInit *Key = dyn_cast(RHS)) { + for (unsigned i = 0, e = Dag->getNumArgs(); i < e; ++i) { + StringInit *ArgName = Dag->getArgName(i); + if (!ArgName || ArgName->getValue() != Key->getValue()) + continue; + // Found + return getDagArgAsType(Dag, i, getType()); + } + // The key is not found. + PrintFatalError(CurRec->getLoc(), Twine("!getdagarg key '") + + Key->getValue() + + Twine("' is not found")); + } + break; + } + case GETDAGNAME: { + DagInit *Dag = dyn_cast(LHS); + IntInit *Idx = dyn_cast(RHS); + if (Dag && Idx) { + int64_t Pos = Idx->getValue(); + if (Pos < 0 || Pos >= Dag->getNumArgs()) { + // The index is out-of-range. + PrintError(CurRec->getLoc(), + Twine("!getdagname index is out of range 0...") + + std::to_string(Dag->getNumArgs()) + ": " + + std::to_string(Pos)); + } + Init *ArgName = Dag->getArgName(Pos); + if (!ArgName) + return UnsetInit::get(getRecordKeeper()); + return ArgName; + } + break; + } case SETDAGOP: { DagInit *Dag = dyn_cast(LHS); DefInit *Op = dyn_cast(RHS); @@ -1380,6 +1443,12 @@ case STRCONCAT: Result = "!strconcat"; break; case INTERLEAVE: Result = "!interleave"; break; case SETDAGOP: Result = "!setdagop"; break; + case GETDAGARG: + Result = "!getdagarg<" + getType()->getAsString() + ">"; + break; + case GETDAGNAME: + Result = "!getdagname"; + break; } return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; } 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, + XGetDagArg, + XGetDagName, // 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("getdagarg", tgtok::XGetDagArg) + .Case("getdagname", tgtok::XGetDagName) .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 @@ -1397,6 +1397,8 @@ case tgtok::XRange: case tgtok::XStrConcat: case tgtok::XInterleave: + case tgtok::XGetDagArg: + case tgtok::XGetDagName: case tgtok::XSetDagOp: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); SMLoc OpLoc = Lex.getLoc(); @@ -1429,6 +1431,12 @@ case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; case tgtok::XInterleave: Code = BinOpInit::INTERLEAVE; break; case tgtok::XSetDagOp: Code = BinOpInit::SETDAGOP; break; + case tgtok::XGetDagArg: + Code = BinOpInit::GETDAGARG; + break; + case tgtok::XGetDagName: + Code = BinOpInit::GETDAGNAME; + break; } RecTy *Type = nullptr; @@ -1441,6 +1449,18 @@ Type = DagRecTy::get(Records); ArgType = DagRecTy::get(Records); break; + case tgtok::XGetDagArg: + Type = ParseOperatorType(); + if (!Type) { + TokError("did not get type for !getdagarg operator"); + return nullptr; + } + ArgType = DagRecTy::get(Records); + break; + case tgtok::XGetDagName: + Type = StringRecTy::get(Records); + ArgType = DagRecTy::get(Records); + break; case tgtok::XAND: case tgtok::XOR: case tgtok::XXOR: @@ -1594,6 +1614,8 @@ return nullptr; } break; + case BinOpInit::GETDAGARG: // The 2nd argument of !getdagarg could be + // index or name. case BinOpInit::LE: case BinOpInit::LT: case BinOpInit::GE: @@ -1658,6 +1680,15 @@ // a record, with no restriction on its superclasses. ArgType = RecordRecTy::get(Records, {}); break; + case BinOpInit::GETDAGARG: + // After parsing the first dag argument, expect an index integer or a + // name string. + ArgType = nullptr; + break; + case BinOpInit::GETDAGNAME: + // After parsing the first dag argument, expect an index integer. + ArgType = IntRecTy::get(Records); + break; default: break; } @@ -2753,6 +2784,8 @@ case tgtok::XRange: case tgtok::XStrConcat: case tgtok::XInterleave: + case tgtok::XGetDagArg: + case tgtok::XGetDagName: case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: case tgtok::XCond: 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 @@ -2,6 +2,8 @@ // RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s // RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s // RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s +// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s +// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s // !setop and !getop are deprecated in favor of !setdagop and !getdagop. // Two tests retain the old names just to be sure they are still supported. @@ -9,10 +11,15 @@ class Base; class OtherBase; +class Super : Base; + def foo: Base; def bar: Base; def qux: OtherBase; +def alice : Super; +def bob : Super; + 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 in1Names = ["a", "b", "c"]; + list in1Names = !foreach(i, !range(!size(in1)), !getdagname(in1, i)); + // CHECK: list in1Args = [1, 2, 3]; + list in1Args = !foreach(i, !range(!size(in1)), !getdagarg(in1, i)); + + dag in2 = (foo 1:$a, (bar "x":$x, (qux foo:$s1, bar:$s2):$y, 7:$z):$b, 3:$c); + // CHECK: dag in2NestedDag = (qux foo:$s1, bar:$s2); + dag in2NestedDag = !getdagarg(!getdagarg(in2, 1), "y"); + // CHECK: Base in2NestedArg = foo; + Base in2NestedArg = !getdagarg(!getdagarg(!getdagarg(in2, 1), "y"), "s1"); + + dag in3 = (foo 1:$a, ?:$b, 3); + // CHECK: list in3Names = ["a", "b", ?]; + list in3Names = !foreach(i, !range(!size(in3)), !getdagname(in3, i)); + // CHECK: list in3Args = [1, ?, 3]; + list in3Args = !foreach(i, !range(!size(in3)), !getdagarg(in3, i)); + +#ifdef ERROR4 + // ERROR4: error: !getdagarg index is out of range 0...3: 3 + int outOfRange = !getdagarg(in1, 3); +#endif + +#ifdef ERROR5 + // ERROR5: error: !getdagarg key 'x' is not found + int notFound = !getdagarg(in1, "x"); +#endif + + dag in4 = (foo "arg1":$a, "arg2":$b, "arg3":$c); + // CHECK: int misMatchType1 = ?; + int misMatchType1 = !getdagarg(in4, 0); + + dag in5 = (foo foo:$a, bar:$b, foo:$c); + // CHECK: OtherBase misMatchType2 = ?; + OtherBase misMatchType2 = !getdagarg(in5, 1); + + dag in6 = (foo alice:$a, bob:$b); + // CHECK: Base base = bob; + Base base = !getdagarg(in6, 1); }