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:
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
-----------------------
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
LT,
GE,
GT,
- SETDAGOP
+ GETDAGARG,
+ GETDAGNAME,
+ SETDAGOP,
};
private:
return BitInit::get(getRecordKeeper(), *Result);
break;
}
+ case GETDAGARG: {
+ DagInit *Dag = dyn_cast<DagInit>(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<TypedInit>(Arg))
+ if (!TI->getType()->typeIsConvertibleTo(Type))
+ return UnsetInit::get(Dag->getRecordKeeper());
+ return Arg;
+ };
+
+ // Accessor by index
+ if (IntInit *Idx = dyn_cast<IntInit>(RHS)) {
+ int64_t Pos = Idx->getValue();
+ if (Pos < 0) {
+ // The index is negative.
+ PrintFatalError(CurRec->getLoc(), Twine("!getdagarg index ") +
+ std::to_string(Pos) +
+ Twine(" is negative"));
+ }
+ if (Pos >= Dag->getNumArgs()) {
+ // The index is out-of-range.
+ PrintFatalError(CurRec->getLoc(),
+ Twine("!getdagarg index ") + std::to_string(Pos) +
+ " is out of range (dag has " +
+ std::to_string(Dag->getNumArgs()) + " arguments)");
+ }
+ return getDagArgAsType(Dag, Pos, getType());
+ }
+ // Accessor by name
+ if (StringInit *Key = dyn_cast<StringInit>(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<DagInit>(LHS);
+ IntInit *Idx = dyn_cast<IntInit>(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() - 1) + ": " +
+ std::to_string(Pos));
+ }
+ Init *ArgName = Dag->getArgName(Pos);
+ if (!ArgName)
+ return UnsetInit::get(getRecordKeeper());
+ return ArgName;
+ }
+ break;
+ }
case SETDAGOP: {
DagInit *Dag = dyn_cast<DagInit>(LHS);
DefInit *Op = dyn_cast<DefInit>(RHS);
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() + ")";
}
.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)
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,
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
};
}
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();
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;
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:
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:
// 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;
}
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:
// 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
+// RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %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.
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);
// ERROR3: error: type for !getdagop must be a record type
int ridiculousCast = !getdagop<int>(orig);
#endif
+
+ dag in1 = (foo 1:$a, 2:$b, 3:$c);
+ // CHECK: list<string> in1Names = ["a", "b", "c"];
+ list<string> in1Names = !foreach(i, !range(!size(in1)), !getdagname(in1, i));
+ // CHECK: list<int> in1Args = [1, 2, 3];
+ list<int> in1Args = !foreach(i, !range(!size(in1)), !getdagarg<int>(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<dag>(!getdagarg<dag>(in2, 1), "y");
+ // CHECK: Base in2NestedArg = foo;
+ Base in2NestedArg = !getdagarg<Base>(!getdagarg<dag>(!getdagarg<dag>(in2, 1), "y"), "s1");
+
+ dag in3 = (foo 1:$a, ?:$b, 3);
+ // CHECK: list<string> in3Names = ["a", "b", ?];
+ list<string> in3Names = !foreach(i, !range(!size(in3)), !getdagname(in3, i));
+ // CHECK: list<int> in3Args = [1, ?, 3];
+ list<int> in3Args = !foreach(i, !range(!size(in3)), !getdagarg<int>(in3, i));
+
+#ifdef ERROR4
+ // ERROR4: error: !getdagarg index -1 is negative
+ int outOfRange = !getdagarg<int>(in1, -1);
+#endif
+
+#ifdef ERROR5
+ // ERROR5: error: !getdagarg index 3 is out of range (dag has 3 arguments)
+ int outOfRange = !getdagarg<int>(in1, 3);
+#endif
+
+#ifdef ERROR6
+ // ERROR6: error: !getdagarg key 'x' is not found
+ int notFound = !getdagarg<int>(in1, "x");
+#endif
+
+ dag in4 = (foo "arg1":$a, "arg2":$b, "arg3":$c);
+ // CHECK: int misMatchType1 = ?;
+ int misMatchType1 = !getdagarg<int>(in4, 0);
+
+ dag in5 = (foo foo:$a, bar:$b, foo:$c);
+ // CHECK: OtherBase misMatchType2 = ?;
+ OtherBase misMatchType2 = !getdagarg<OtherBase>(in5, 1);
+
+ dag in6 = (foo alice:$a, bob:$b);
+ // CHECK: Base base = bob;
+ Base base = !getdagarg<Base>(in6, 1);
}