diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst index 460ff9067f20..534597b041bc 100644 --- a/llvm/docs/TableGen/LangIntro.rst +++ b/llvm/docs/TableGen/LangIntro.rst @@ -205,6 +205,9 @@ supported include: ``!empty(a)`` An integer {0,1} indicating whether list 'a' is empty. +``!size(a)`` + An integer indicating the number of elements in list 'a'. + ``!if(a,b,c)`` 'b' if the result of 'int' or 'bit' operator 'a' is nonzero, 'c' otherwise. diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst index 285572fa481c..5f7917a5b4bb 100644 --- a/llvm/docs/TableGen/LangRef.rst +++ b/llvm/docs/TableGen/LangRef.rst @@ -98,7 +98,7 @@ wide variety of meanings: :!eq !if !head !tail !con :!add !shl !sra !srl !and :!or !empty !subst !foreach !strconcat - :!cast !listconcat + :!cast !listconcat !size Syntax diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index 0c27f395cfbd..a94f76d852f3 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -759,7 +759,7 @@ public: /// class UnOpInit : public OpInit, public FoldingSetNode { public: - enum UnaryOp : uint8_t { CAST, HEAD, TAIL, EMPTY }; + enum UnaryOp : uint8_t { CAST, HEAD, TAIL, SIZE, EMPTY }; private: Init *LHS; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index f447b3b1b477..80c0973644bb 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -722,6 +722,11 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { } break; + case SIZE: + if (ListInit *LHSl = dyn_cast(LHS)) + return IntInit::get(LHSl->size()); + break; + case EMPTY: if (ListInit *LHSl = dyn_cast(LHS)) return IntInit::get(LHSl->empty()); @@ -746,6 +751,7 @@ std::string UnOpInit::getAsString() const { case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break; case HEAD: Result = "!head"; break; case TAIL: Result = "!tail"; break; + case SIZE: Result = "!size"; break; case EMPTY: Result = "!empty"; break; } return Result + "(" + LHS->getAsString() + ")"; diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index 5d6f7c23e0b6..bc03055eb236 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -469,6 +469,7 @@ tgtok::TokKind TGLexer::LexExclaim() { .Case("if", tgtok::XIf) .Case("head", tgtok::XHead) .Case("tail", tgtok::XTail) + .Case("size", tgtok::XSize) .Case("con", tgtok::XConcat) .Case("add", tgtok::XADD) .Case("and", tgtok::XAND) diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index b5b58161878b..342eb76fc0f2 100644 --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -48,7 +48,7 @@ namespace tgtok { // !keywords. XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, - XSubst, XForEach, XHead, XTail, XEmpty, XIf, XEq, + XSubst, XForEach, XHead, XTail, XSize, XEmpty, XIf, XEq, // Integer value. IntVal, diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 17c2c2ee6137..72ab8d3838d4 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -781,6 +781,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { return nullptr; case tgtok::XHead: case tgtok::XTail: + case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: { // Value ::= !unop '(' Value ')' UnOpInit::UnaryOp Code; @@ -808,6 +809,11 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { Lex.Lex(); // eat the operation Code = UnOpInit::TAIL; break; + case tgtok::XSize: + Lex.Lex(); + Code = UnOpInit::SIZE; + Type = IntRecTy::get(); + break; case tgtok::XEmpty: Lex.Lex(); // eat the operation Code = UnOpInit::EMPTY; @@ -842,12 +848,15 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { } } - if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) { + if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL || + Code == UnOpInit::SIZE) { if (!LHSl && !LHSt) { 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"); return nullptr; @@ -1453,6 +1462,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, case tgtok::XHead: case tgtok::XTail: + case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: // Value ::= !unop '(' Value ')' case tgtok::XConcat: diff --git a/llvm/test/TableGen/size.td b/llvm/test/TableGen/size.td new file mode 100644 index 000000000000..f7061e110790 --- /dev/null +++ b/llvm/test/TableGen/size.td @@ -0,0 +1,34 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def A1 { +// CHECK: int Val = 0; +// CHECK: } + +// CHECK: def A2 { +// CHECK: int Val = 3; +// CHECK: } + +// CHECK: def B1 { +// CHECK: int Val = 0; +// CHECK: } + +// CHECK: def B2 { +// CHECK: int Val = 2; +// CHECK: } + +class A L> { + int Val = !size(L); +} + +class B L> { + int Val = !size(L); +} + +def A1 : A<[]>; +def A2 : A<[1, 1, 2]>; + +def B1 : B<[]>; +def B2 : B<["a", "b"]>;