From 0243aaf42c6c766ea64868b67357dc761ea95b99 Mon Sep 17 00:00:00 2001 From: Nicolai Haehnle Date: Fri, 23 Feb 2018 10:46:07 +0000 Subject: [PATCH] TableGen: Add !size operation Summary: Returns the size of a list. I have found this to be rather useful in some development for the AMDGPU backend where we could simplify our .td files by concatenating list for complex intrinsics. Doing so requires us to compute the position argument for LLVMMatchType. Basically, the usage is in a pattern that looks somewhat like this: list argtypes = !listconcat(base, [llvm_any_ty, LLVMMatchType]); Change-Id: I360a0b000fd488d18bea412228230fd93722bd2c Reviewers: arsenm, craig.topper, tra, MartinO Subscribers: wdng, llvm-commits, tpr Differential Revision: https://reviews.llvm.org/D43553 llvm-svn: 325883 --- llvm/docs/TableGen/LangIntro.rst | 3 +++ llvm/docs/TableGen/LangRef.rst | 2 +- llvm/include/llvm/TableGen/Record.h | 2 +- llvm/lib/TableGen/Record.cpp | 6 ++++++ llvm/lib/TableGen/TGLexer.cpp | 1 + llvm/lib/TableGen/TGLexer.h | 2 +- llvm/lib/TableGen/TGParser.cpp | 12 +++++++++++- llvm/test/TableGen/size.td | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 llvm/test/TableGen/size.td diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst index 460ff90..534597b 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 285572f..5f7917a 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 0c27f39..a94f76d 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 f447b3b..80c0973 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 5d6f7c2..bc03055 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 b5b5816..342eb76 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 17c2c2e..72ab8d3 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 0000000..f7061e1 --- /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"]>; -- 2.7.4