diff options
author | Nicolai Haehnle <nhaehnle@gmail.com> | 2018-03-09 12:24:06 +0000 |
---|---|---|
committer | Nicolai Haehnle <nhaehnle@gmail.com> | 2018-03-09 12:24:06 +0000 |
commit | b537605956400d62729cebc9d5d053c45aa5f4c5 (patch) | |
tree | 309691df62219727c021261ba83e0dd95a1082f3 | |
parent | 47c3472c412b79ccd9df9b1461910127df0d1d97 (diff) | |
download | bcm5719-llvm-b537605956400d62729cebc9d5d053c45aa5f4c5.tar.gz bcm5719-llvm-b537605956400d62729cebc9d5d053c45aa5f4c5.zip |
TableGen: add !isa operation
Change-Id: Iddb724c3ae706d82933a2d82c91d07e0e36b30e3
Differential revision: https://reviews.llvm.org/D44105
llvm-svn: 327117
-rw-r--r-- | llvm/docs/TableGen/LangIntro.rst | 3 | ||||
-rw-r--r-- | llvm/docs/TableGen/LangRef.rst | 1 | ||||
-rw-r--r-- | llvm/include/llvm/TableGen/Record.h | 34 | ||||
-rw-r--r-- | llvm/lib/TableGen/Record.cpp | 62 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.h | 2 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGParser.cpp | 28 | ||||
-rw-r--r-- | llvm/test/TableGen/isa.td | 39 |
8 files changed, 169 insertions, 1 deletions
diff --git a/llvm/docs/TableGen/LangIntro.rst b/llvm/docs/TableGen/LangIntro.rst index 67000fa03c6..c4a7a34c025 100644 --- a/llvm/docs/TableGen/LangIntro.rst +++ b/llvm/docs/TableGen/LangIntro.rst @@ -208,6 +208,9 @@ supported include: is a special case in that the argument can be an int or a record. In the latter case, the record's name is returned. +``!isa<type>(a)`` + Returns an integer: 1 if 'a' is dynamically of the given type, 0 otherwise. + ``!subst(a, b, c)`` If 'a' and 'b' are of string type or are symbol references, substitute 'b' for 'a' in 'c.' This operation is analogous to $(subst) in GNU make. diff --git a/llvm/docs/TableGen/LangRef.rst b/llvm/docs/TableGen/LangRef.rst index 5da852879d2..89996f35822 100644 --- a/llvm/docs/TableGen/LangRef.rst +++ b/llvm/docs/TableGen/LangRef.rst @@ -99,6 +99,7 @@ wide variety of meanings: :!add !shl !sra !srl !and :!or !empty !subst !foreach !strconcat :!cast !listconcat !size !foldl + :!isa Syntax diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index e10b0bfb64e..d23167ac5bf 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -317,6 +317,7 @@ protected: IK_UnOpInit, IK_LastOpInit, IK_FoldOpInit, + IK_IsAOpInit, IK_StringInit, IK_VarInit, IK_VarListElementInit, @@ -951,6 +952,39 @@ public: std::string getAsString() const override; }; +/// !isa<type>(expr) - Dynamically determine the type of an expression. +class IsAOpInit : public TypedInit, public FoldingSetNode { +private: + RecTy *CheckType; + Init *Expr; + + IsAOpInit(RecTy *CheckType, Init *Expr) + : TypedInit(IK_IsAOpInit, IntRecTy::get()), CheckType(CheckType), + Expr(Expr) {} + +public: + IsAOpInit(const IsAOpInit &) = delete; + IsAOpInit &operator=(const IsAOpInit &) = delete; + + static bool classof(const Init *I) { return I->getKind() == IK_IsAOpInit; } + + static IsAOpInit *get(RecTy *CheckType, Init *Expr); + + void Profile(FoldingSetNodeID &ID) const; + + // Fold - If possible, fold this to a simpler init. Return this if not + // possible to fold. + Init *Fold() const; + + bool isComplete() const override { return false; } + + Init *resolveReferences(Resolver &R) const override; + + Init *getBit(unsigned Bit) const override; + + std::string getAsString() const override; +}; + /// 'Opcode' - Represent a reference to an entire variable object. class VarInit : public TypedInit { Init *VarName; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index c1344aea4eb..76bbe7a0e5d 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -1231,6 +1231,68 @@ std::string FoldOpInit::getAsString() const { .str(); } +static void ProfileIsAOpInit(FoldingSetNodeID &ID, RecTy *CheckType, + Init *Expr) { + ID.AddPointer(CheckType); + ID.AddPointer(Expr); +} + +IsAOpInit *IsAOpInit::get(RecTy *CheckType, Init *Expr) { + static FoldingSet<IsAOpInit> ThePool; + + FoldingSetNodeID ID; + ProfileIsAOpInit(ID, CheckType, Expr); + + void *IP = nullptr; + if (IsAOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) + return I; + + IsAOpInit *I = new (Allocator) IsAOpInit(CheckType, Expr); + ThePool.InsertNode(I, IP); + return I; +} + +void IsAOpInit::Profile(FoldingSetNodeID &ID) const { + ProfileIsAOpInit(ID, CheckType, Expr); +} + +Init *IsAOpInit::Fold() const { + if (TypedInit *TI = dyn_cast<TypedInit>(Expr)) { + // Is the expression type known to be (a subclass of) the desired type? + if (TI->getType()->typeIsConvertibleTo(CheckType)) + return IntInit::get(1); + + if (isa<RecordRecTy>(CheckType)) { + // If the target type is not a subclass of the expression type, or if + // the expression has fully resolved to a record, we know that it can't + // be of the required type. + if (!CheckType->typeIsConvertibleTo(TI->getType()) || isa<DefInit>(Expr)) + return IntInit::get(0); + } else { + // We treat non-record types as not castable. + return IntInit::get(0); + } + } + return const_cast<IsAOpInit *>(this); +} + +Init *IsAOpInit::resolveReferences(Resolver &R) const { + Init *NewExpr = Expr->resolveReferences(R); + if (Expr != NewExpr) + return get(CheckType, NewExpr)->Fold(); + return const_cast<IsAOpInit *>(this); +} + +Init *IsAOpInit::getBit(unsigned Bit) const { + return VarBitInit::get(const_cast<IsAOpInit *>(this), Bit); +} + +std::string IsAOpInit::getAsString() const { + return (Twine("!isa<") + CheckType->getAsString() + ">(" + + Expr->getAsString() + ")") + .str(); +} + RecTy *TypedInit::getFieldType(StringInit *FieldName) const { if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType())) { for (Record *Rec : RecordType->getClasses()) { diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index 9d8d693f975..222aac25f9d 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -467,6 +467,7 @@ tgtok::TokKind TGLexer::LexExclaim() { StringSwitch<tgtok::TokKind>(StringRef(Start, CurPtr - Start)) .Case("eq", tgtok::XEq) .Case("if", tgtok::XIf) + .Case("isa", tgtok::XIsA) .Case("head", tgtok::XHead) .Case("tail", tgtok::XTail) .Case("size", tgtok::XSize) diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index cfed08ec4d4..bebe3176d7b 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, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, + XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, // Integer value. IntVal, diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 488d1c8d82a..47c734502f0 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -936,6 +936,33 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec, CurMultiClass); } + case tgtok::XIsA: { + // Value ::= !isa '<' Type '>' '(' Value ')' + Lex.Lex(); // eat the operation + + RecTy *Type = ParseOperatorType(); + if (!Type) + return nullptr; + + if (Lex.getCode() != tgtok::l_paren) { + TokError("expected '(' after type of !isa"); + return nullptr; + } + Lex.Lex(); // eat the '(' + + Init *LHS = ParseValue(CurRec); + if (!LHS) + return nullptr; + + if (Lex.getCode() != tgtok::r_paren) { + TokError("expected ')' in !isa"); + return nullptr; + } + Lex.Lex(); // eat the ')' + + return (IsAOpInit::get(Type, LHS))->Fold(); + } + case tgtok::XConcat: case tgtok::XADD: case tgtok::XAND: @@ -1696,6 +1723,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, case tgtok::XSize: case tgtok::XEmpty: case tgtok::XCast: // Value ::= !unop '(' Value ')' + case tgtok::XIsA: case tgtok::XConcat: case tgtok::XADD: case tgtok::XAND: diff --git a/llvm/test/TableGen/isa.td b/llvm/test/TableGen/isa.td new file mode 100644 index 00000000000..cfaacb03b71 --- /dev/null +++ b/llvm/test/TableGen/isa.td @@ -0,0 +1,39 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def X0 { +// CHECK: int ret = 0; +// CHECK: } + +// CHECK: def X1 { +// CHECK: int ret = 1; +// CHECK: } + +// CHECK: def Y0 { +// CHECK: int ret = 0; +// CHECK: } + +// CHECK: def Y1 { +// CHECK: int ret = 11; +// CHECK: } + +class A<int dummy>; +class B<int num> : A<num> { + int Num = num; +} + +class X<A a> { + int ret = !isa<B>(a); +} + +class Y<A a> { + int ret = !if(!isa<B>(a), !cast<B>(a).Num, 0); +} + +def X0 : X<A<0>>; +def X1 : X<B<0>>; + +def Y0 : Y<A<10>>; +def Y1 : Y<B<11>>; |