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 @@ -225,10 +225,10 @@ : !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 + : !not !or !range !setdagarg !setdagname + : !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: @@ -1370,7 +1370,7 @@ The following bang operators are useful for working with DAGs: ``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagarg``, ``!getdagname``, -``!getdagop``, ``!setdagop``, ``!size``. +``!getdagop``, ``!setdagarg``, ``!setdagname``, ``!setdagop``, ``!size``. Defvar in a record body ----------------------- @@ -1821,6 +1821,15 @@ ``!range(``\ *list*\ ``)`` Equivalent to ``!range(0, !size(list))``. +``!setdagarg(``\ *dag*\ ``,``\ *key*\ ``,``\ *arg*\ ``)`` + This operator produces a DAG node with the same operator as *dag*, but + replacing the value of the argument, specified by the *key*, which is + either an integer index or a string name, with *arg*. + +``!setdagname(``\ *dag*\ ``,``\ *index*\ ``,``\ *name*\ ``)`` + This operator produces a DAG node with the same operator as *dag*, but + replacing the name of the argument, specified by the *index* ,with *name*. + ``!setdagop(``\ *dag*\ ``,`` *op*\ ``)`` This operator produces a DAG node with the same arguments as *dag*, but with its operator replaced with *op*. 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 @@ -918,7 +918,17 @@ /// !op (X, Y, Z) - Combine two inits. class TernOpInit : public OpInit, public FoldingSetNode { public: - enum TernaryOp : uint8_t { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR, FIND }; + enum TernaryOp : uint8_t { + SUBST, + FOREACH, + FILTER, + IF, + DAG, + SUBSTR, + FIND, + SETDAGARG, + SETDAGNAME, + }; private: Init *LHS, *MHS, *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 @@ -1701,6 +1701,79 @@ } break; } + + case SETDAGARG: { + DagInit *Dag = dyn_cast(LHS); + if (Dag) { + // Helper setting the specified argument. + auto setDagArg = [](DagInit *Dag, unsigned Pos, Init *Arg) -> Init * { + assert(Pos < Dag->getNumArgs()); + SmallVector Args(Dag->getArgs()); + SmallVector Names(Dag->getArgNames()); + Args[Pos] = Arg; + return DagInit::get(Dag->getOperator(), Dag->getName(), Args, Names); + }; + // Accessor by index + if (IntInit *Idx = dyn_cast(MHS)) { + int64_t Pos = Idx->getValue(); + if (Pos < 0) { + // The index is negative. + PrintFatalError(CurRec->getLoc(), Twine("!setdagarg index ") + + std::to_string(Pos) + + " is negative"); + } + if (Pos >= Dag->getNumArgs()) { + PrintFatalError(CurRec->getLoc(), + Twine("!setdagarg index ") + std::to_string(Pos) + + " is out of range (dag has " + + std::to_string(Dag->getNumArgs()) + + " arguments)"); + } + return setDagArg(Dag, Pos, RHS); + } + // Accessor by name + if (StringInit *Key = dyn_cast(MHS)) { + for (unsigned i = 0, e = Dag->getNumArgs(); i < e; ++i) { + StringInit *ArgName = Dag->getArgName(i); + if (!ArgName || ArgName->getValue() != Key->getValue()) + continue; + // Found + return setDagArg(Dag, i, RHS); + } + // The key is not found. + PrintFatalError(CurRec->getLoc(), Twine("!setdagarg key '") + + Key->getValue() + + "' is not found"); + } + } + break; + } + + case SETDAGNAME: { + DagInit *Dag = dyn_cast(LHS); + IntInit *Idx = dyn_cast(MHS); + StringInit *Name = dyn_cast(RHS); + if (Dag && Idx) { + int64_t Pos = Idx->getValue(); + if (Pos < 0) { + // The index is negative. + PrintFatalError(CurRec->getLoc(), Twine("!setdagname index ") + + std::to_string(Pos) + + " is negative"); + } + if (Pos >= Dag->getNumArgs()) { + PrintFatalError(CurRec->getLoc(), + Twine("!setdagname index ") + std::to_string(Pos) + + " is out of range (dag has " + + std::to_string(Dag->getNumArgs()) + " arguments)"); + } + SmallVector Args(Dag->getArgs()); + SmallVector Names(Dag->getArgNames()); + Names[Pos] = Name; + return DagInit::get(Dag->getOperator(), Dag->getName(), Args, Names); + } + break; + } } return const_cast(this); @@ -1747,6 +1820,12 @@ case SUBST: Result = "!subst"; break; case SUBSTR: Result = "!substr"; break; case FIND: Result = "!find"; break; + case SETDAGARG: + Result = "!setdagarg"; + break; + case SETDAGNAME: + Result = "!setdagname"; + break; } return (Result + "(" + (UnquotedLHS ? LHS->getAsUnquotedString() : LHS->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 @@ -129,6 +129,8 @@ XRange, XGetDagArg, XGetDagName, + XSetDagArg, + XSetDagName, // Boolean literals. TrueVal, 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 @@ -594,6 +594,8 @@ .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated. .Case("getdagarg", tgtok::XGetDagArg) .Case("getdagname", tgtok::XGetDagName) + .Case("setdagarg", tgtok::XSetDagArg) + .Case("setdagname", tgtok::XSetDagName) .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 @@ -1769,6 +1769,8 @@ return ParseOperationForEachFilter(CurRec, ItemType); } + case tgtok::XSetDagArg: + case tgtok::XSetDagName: case tgtok::XDag: case tgtok::XIf: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' @@ -1790,6 +1792,16 @@ case tgtok::XSubst: Code = TernOpInit::SUBST; break; + case tgtok::XSetDagArg: + Code = TernOpInit::SETDAGARG; + Type = DagRecTy::get(Records); + ItemType = nullptr; + break; + case tgtok::XSetDagName: + Code = TernOpInit::SETDAGNAME; + Type = DagRecTy::get(Records); + ItemType = nullptr; + break; } if (!consume(tgtok::l_paren)) { TokError("expected '(' after ternary operator"); @@ -1902,6 +1914,35 @@ Type = RHSt->getType(); break; } + case tgtok::XSetDagArg: { + TypedInit *MHSt = dyn_cast(MHS); + if (!MHSt || !isa(MHSt->getType())) { + Error(MHSLoc, Twine("expected integer index or string name, got ") + + (MHSt ? ("type '" + MHSt->getType()->getAsString()) + : ("'" + MHS->getAsString())) + + "'"); + return nullptr; + } + break; + } + case tgtok::XSetDagName: { + TypedInit *MHSt = dyn_cast(MHS); + if (!MHSt || !isa(MHSt->getType())) { + Error(MHSLoc, Twine("expected integer index, got ") + + (MHSt ? ("type '" + MHSt->getType()->getAsString()) + : ("'" + MHS->getAsString())) + + "'"); + return nullptr; + } + TypedInit *RHSt = dyn_cast(RHS); + // The name could be a string or unset. + if (RHSt && !isa(RHSt->getType())) { + Error(RHSLoc, Twine("expected string name, got type '") + + RHSt->getType()->getAsString() + "'"); + return nullptr; + } + break; + } } return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec); } @@ -2787,6 +2828,8 @@ case tgtok::XGetDagArg: case tgtok::XGetDagName: case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XSetDagArg: + case tgtok::XSetDagName: case tgtok::XIf: case tgtok::XCond: case tgtok::XFoldl: 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 @@ -5,6 +5,9 @@ // 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 // RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s +// RUN: not llvm-tblgen -DERROR7 %s 2>&1 | FileCheck --check-prefix=ERROR7 %s +// RUN: not llvm-tblgen -DERROR8 %s 2>&1 | FileCheck --check-prefix=ERROR8 %s +// RUN: not llvm-tblgen -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %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. @@ -114,4 +117,32 @@ dag in6 = (foo alice:$a, bob:$b); // CHECK: Base base = bob; Base base = !getdagarg(in6, 1); + + // CHECK: dag orig_set_val = (foo 1, 2:$a, "val":$b); + dag orig_set_val = !setdagarg(orig, 2, "val"); + // CHECK: dag orig_set_val_by_name = (foo 1, 2:$a, "aval":$b); + dag orig_set_val_by_name = !setdagarg(orig, "b", "aval"); + // CHECK: dag orig_set_dag_val = (foo 1, 2:$a, (bar foo:$p, qux:$q):$b); + dag orig_set_dag_val = !setdagarg(orig, "b", (bar foo:$p, qux:$q)); + // CHECK: dag orig_clr_val = (foo 1, ?:$a, ?:$b); + dag orig_clr_val = !setdagarg(orig, "a", ?); + // CHECK: dag orig_set_name = (foo 1:$c, 2:$a, ?:$b); + dag orig_set_name = !setdagname(orig, 0, "c"); + // CHECK: dag orig_clr_name = (foo 1, 2, ?:$b); + dag orig_clr_name = !setdagname(orig, 1, ?); + +#ifdef ERROR7 + // ERROR7: error: !setdagarg index -1 is negative + dag orig_negative = !setdagarg(orig, -1, "val"); +#endif + +#ifdef ERROR8 + // ERROR8: error: !setdagarg index 3 is out of range (dag has 3 arguments) + dag orig_out_of_range = !setdagarg(orig, 3, "val"); +#endif + +#ifdef ERROR9 + // ERROR9: error: expected integer index or string name, got type 'Base' + dag orig_out_of_range = !setdagarg(orig, foo, (foo qux:$a)); +#endif }