forked from OSchip/llvm-project
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<LLVMType> 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<LLVMType> argtypes = !listconcat(base, [llvm_any_ty, LLVMMatchType<!size(base)>]); Change-Id: I360a0b000fd488d18bea412228230fd93722bd2c Reviewers: arsenm, craig.topper, tra, MartinO Subscribers: wdng, llvm-commits, tpr Differential Revision: https://reviews.llvm.org/D43553 llvm-svn: 325883
This commit is contained in:
parent
6cf306deca
commit
0243aaf42c
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -722,6 +722,11 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
|
|||
}
|
||||
break;
|
||||
|
||||
case SIZE:
|
||||
if (ListInit *LHSl = dyn_cast<ListInit>(LHS))
|
||||
return IntInit::get(LHSl->size());
|
||||
break;
|
||||
|
||||
case EMPTY:
|
||||
if (ListInit *LHSl = dyn_cast<ListInit>(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() + ")";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<list<int> L> {
|
||||
int Val = !size(L);
|
||||
}
|
||||
|
||||
class B<list<string> L> {
|
||||
int Val = !size(L);
|
||||
}
|
||||
|
||||
def A1 : A<[]>;
|
||||
def A2 : A<[1, 1, 2]>;
|
||||
|
||||
def B1 : B<[]>;
|
||||
def B2 : B<["a", "b"]>;
|
Loading…
Reference in New Issue