Index: llvm/docs/TableGen/ProgRef.rst =================================================================== --- llvm/docs/TableGen/ProgRef.rst +++ llvm/docs/TableGen/ProgRef.rst @@ -274,7 +274,7 @@ the programmer's intention. ``bits<``\ *n*\ ``>`` - The ``bits`` type is a fixed-size integer of arbitrary length *n* that + The ``bits`` type is a fixed-sized integer of arbitrary length *n* that is treated as separate bits. These bits can be accessed individually. A field of this type is useful for representing an instruction operation code, register number, or address mode/register/displacement. The bits of @@ -1240,8 +1240,8 @@ or to associate an operand in one DAG with a like-named operand in another DAG. -The following bang operators manipulate DAGs: ``!con``, ``!dag``, ``!foreach``, -``!getop``, ``!setop``. +The following bang operators are useful for working with DAGs: +``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getop``, ``!setop``, ``!size``. Defvar in a record body ----------------------- @@ -1507,8 +1507,9 @@ Example: ``!dag(op, [a1, a2, ?], ["name1", "name2", "name3"])`` results in ``(op a1:$name1, a2:$name2, ?:$name3)``. -``!empty(``\ *list*\ ``)`` - This operator produces 1 if the *list* is empty; 0 otherwise. +``!empty(``\ *a*\ ``)`` + This operator produces 1 if the string, list, or DAG *a* is empty; 0 otherwise. + A dag is empty if it has no arguments; the operator does not count. ``!eq(`` *a*\ `,` *b*\ ``)`` This operator produces 1 if *a* is equal to *b*; 0 otherwise. @@ -1629,7 +1630,8 @@ is undefined for shift counts outside 0...63. ``!size(``\ *a*\ ``)`` - This operator produces the number of elements in the list *a*. + This operator produces the size of the string, list, or dag *a*. + The size of a DAG is the number of arguments; the operator does not count. ``!sra(``\ *a*\ ``,`` *count*\ ``)`` This operator shifts *a* right arithmetically by *count* bits and produces the resulting Index: llvm/lib/TableGen/Record.cpp =================================================================== --- llvm/lib/TableGen/Record.cpp +++ llvm/lib/TableGen/Record.cpp @@ -786,11 +786,17 @@ case SIZE: if (ListInit *LHSl = dyn_cast(LHS)) return IntInit::get(LHSl->size()); + if (DagInit *LHSd = dyn_cast(LHS)) + return IntInit::get(LHSd->arg_size()); + if (StringInit *LHSs = dyn_cast(LHS)) + return IntInit::get(LHSs->getValue().size()); break; case EMPTY: if (ListInit *LHSl = dyn_cast(LHS)) return IntInit::get(LHSl->empty()); + if (DagInit *LHSd = dyn_cast(LHS)) + return IntInit::get(LHSd->arg_empty()); if (StringInit *LHSs = dyn_cast(LHS)) return IntInit::get(LHSs->getValue().empty()); break; Index: llvm/lib/TableGen/TGParser.cpp =================================================================== --- llvm/lib/TableGen/TGParser.cpp +++ llvm/lib/TableGen/TGParser.cpp @@ -986,56 +986,58 @@ Init *LHS = ParseValue(CurRec); if (!LHS) return nullptr; - if (Code == UnOpInit::HEAD || - Code == UnOpInit::TAIL || - Code == UnOpInit::EMPTY) { + if (Code == UnOpInit::EMPTY || Code == UnOpInit::SIZE) { ListInit *LHSl = dyn_cast(LHS); StringInit *LHSs = dyn_cast(LHS); + DagInit *LHSd = dyn_cast(LHS); TypedInit *LHSt = dyn_cast(LHS); - if (!LHSl && !LHSs && !LHSt) { - TokError("expected list or string type argument in unary operator"); + if (!LHSl && !LHSs && !LHSd && !LHSt) { + TokError("expected string, list, or dag type argument in unary operator"); return nullptr; } if (LHSt) { ListRecTy *LType = dyn_cast(LHSt->getType()); StringRecTy *SType = dyn_cast(LHSt->getType()); - if (!LType && !SType) { - TokError("expected list or string type argument in unary operator"); + DagRecTy *DType = dyn_cast(LHSt->getType()); + if (!LType && !SType && !DType) { + TokError("expected string, list, or dag type argument in unary operator"); return nullptr; } } + } - if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL || - Code == UnOpInit::SIZE) { - if (!LHSl && !LHSt) { + if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { + ListInit *LHSl = dyn_cast(LHS); + TypedInit *LHSt = dyn_cast(LHS); + if (!LHSl && !LHSt) { + TokError("expected list type argument in unary operator"); + return nullptr; + } + if (LHSt) { + ListRecTy *LType = dyn_cast(LHSt->getType()); + if (!LType) { TokError("expected list type argument in unary operator"); return nullptr; } } - if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { - if (LHSl && LHSl->empty()) { - TokError("empty list argument in unary operator"); + if (LHSl && LHSl->empty()) { + TokError("empty list argument in unary operator"); + return nullptr; + } + if (LHSl) { + Init *Item = LHSl->getElement(0); + TypedInit *Itemt = dyn_cast(Item); + if (!Itemt) { + TokError("untyped list element in unary operator"); return nullptr; } - if (LHSl) { - Init *Item = LHSl->getElement(0); - TypedInit *Itemt = dyn_cast(Item); - if (!Itemt) { - TokError("untyped list element in unary operator"); - return nullptr; - } - Type = (Code == UnOpInit::HEAD) ? Itemt->getType() - : ListRecTy::get(Itemt->getType()); - } else { - assert(LHSt && "expected list type argument in unary operator"); - ListRecTy *LType = dyn_cast(LHSt->getType()); - if (!LType) { - TokError("expected list type argument in unary operator"); - return nullptr; - } - Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType; - } + Type = (Code == UnOpInit::HEAD) ? Itemt->getType() + : ListRecTy::get(Itemt->getType()); + } else { + assert(LHSt && "expected list type argument in unary operator"); + ListRecTy *LType = dyn_cast(LHSt->getType()); + Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType; } } Index: llvm/test/TableGen/empty.td =================================================================== --- /dev/null +++ llvm/test/TableGen/empty.td @@ -0,0 +1,71 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +defvar LongList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +defvar EmptyStr = ""; + +// Test !empty(dag). + +// CHECK: def Drec1 { +// CHECK: bit Empty = 1; +// CHECK: bit NotEmpty = 0; +// CHECK: def Drec2 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; +// CHECK: def Drec3 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; + +class D { + bit Empty = !empty(ADag); + bit NotEmpty = !not(!empty(ADag)); +} + +def op; + +def Drec1 : D<(op)>; +def Drec2 : D<(op "string")>; +def Drec3 : D<(op "string", 42)>; + +// Test !empty(list). + +// CHECK: def Lrec1 { +// CHECK: bit Empty = 1; +// CHECK: bit NotEmpty = 0; +// CHECK: def Lrec2 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; +// CHECK: def Lrec3 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; + +class L Ints> { + bit Empty = !empty(Ints); + bit NotEmpty = !not(!empty(Ints)); +} + +def Lrec1 : L<[]>; +def Lrec2 : L<[1]>; +def Lrec3 : L; + +// Test !empty(string). + +// CHECK: def Srec1 { +// CHECK: bit Empty = 1; +// CHECK: bit NotEmpty = 0; +// CHECK: def Srec2 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; +// CHECK: def Srec3 { +// CHECK: bit Empty = 0; +// CHECK: bit NotEmpty = 1; + +class S { + bit Empty = !empty(Str); + bit NotEmpty = !not(!empty(Str)); +} + +def Srec1 : S; +def Srec2 : S<"a">; +def Srec3 : S<"ab">; + Index: llvm/test/TableGen/size.td =================================================================== --- llvm/test/TableGen/size.td +++ llvm/test/TableGen/size.td @@ -1,6 +1,8 @@ // RUN: llvm-tblgen %s | FileCheck %s // XFAIL: vg_leak +// Test !size of lists. + // CHECK: --- Defs --- // CHECK: def A1 { @@ -32,3 +34,70 @@ def B1 : B<[]>; def B2 : B<["a", "b"]>; + +// Test !size of DAGs. + +// CHECK: def D0 { +// CHECK: int Val = 0; +// CHECK: } + +// CHECK: def D1 { +// CHECK: int Val = 1; +// CHECK: } + +// CHECK: def D2 { +// CHECK: int Val = 2; +// CHECK: } + +// CHECK: def D3 { +// CHECK: int Val = 3; +// CHECK: } + +// CHECK: def D4 { +// CHECK: int Val = 4; +// CHECK: } + +class D { + int Val = !size(D); +} + +def op; + +def D0 : D<(op)>; +def D1 : D<(op "string")>; +def D2 : D<(op "string", 42)>; +def D3 : D<(op "string", 42, (op "sub-dag"))>; +def D4 : D<(op "string", 42, (op "sub-dag"), D0.Val)>; + +// Test !size of strings. + +// CHECK: def S0 { +// CHECK: int Val = 0; +// CHECK: } + +// CHECK: def S1 { +// CHECK: int Val = 1; +// CHECK: } + +// CHECK: def S2 { +// CHECK: int Val = 2; +// CHECK: } + +// CHECK: def S3 { +// CHECK: int Val = 3; +// CHECK: } + +// CHECK: def S4 { +// CHECK: int Val = 29; +// CHECK: } + +class S { + int Val = !size(S); +} + +def S0 : S<"">; +def S1 : S<"a">; +def S2 : S<"ab">; +def S3 : S<"abc">; +def S4 : S<"This is the end of the world!">; +