Index: llvm/trunk/docs/TableGen/LangIntro.rst =================================================================== --- llvm/trunk/docs/TableGen/LangIntro.rst +++ llvm/trunk/docs/TableGen/LangIntro.rst @@ -182,10 +182,31 @@ the operand of the paste. ``!cast(a)`` - A symbol of type *type* obtained by looking up the string 'a' in the symbol - table. If the type of 'a' does not match *type*, TableGen aborts with an - error. !cast is a special case in that the argument must be an - object defined by a 'def' construct. + If 'a' is a string, a record of type *type* obtained by looking up the + string 'a' in the list of all records defined by the time that all template + arguments in 'a' are fully resolved. + + For example, if !cast(a) appears in a multiclass definition, or in a + class instantiated inside of a multiclass definition, and 'a' does not + reference any template arguments of the multiclass, then a record of name + 'a' must be instantiated earlier in the source file. If 'a' does reference + a template argument, then the lookup is delayed until defm statements + instantiating the multiclass (or later, if the defm occurs in another + multiclass and template arguments of the inner multiclass that are + referenced by 'a' are substituted by values that themselves contain + references to template arguments of the outer multiclass). + + If the type of 'a' does not match *type*, TableGen aborts with an error. + + For historical reasons, 'a' can also be the name of a variable or a + template argument in some cases, but this use is unreliable and is + discouraged. + + Otherwise, perform a normal type cast e.g. between an int and a bit, or + between record types. This allows casting a record to a subclass, though if + the types do not match, constant folding will be inhibited. !cast + 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. ``!subst(a, b, c)`` If 'a' and 'b' are of string type or are symbol references, substitute 'b' Index: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/include/llvm/TableGen/Record.h @@ -46,6 +46,7 @@ class RecordVal; class Resolver; class StringInit; +class TypedInit; //===----------------------------------------------------------------------===// // Type Classes @@ -83,6 +84,10 @@ /// type. virtual bool typeIsConvertibleTo(const RecTy *RHS) const; + /// Return true if 'this' type is equal to or a subtype of RHS. For example, + /// a bit set is not an int, but they are convertible. + virtual bool typeIsA(const RecTy *RHS) const; + /// Returns the type representing list. ListRecTy *getListTy(); }; @@ -128,6 +133,8 @@ std::string getAsString() const override; bool typeIsConvertibleTo(const RecTy *RHS) const override; + + bool typeIsA(const RecTy *RHS) const override; }; /// 'code' - Represent a code fragment @@ -174,8 +181,7 @@ public: static bool classof(const RecTy *RT) { - return RT->getRecTyKind() == StringRecTyKind || - RT->getRecTyKind() == CodeRecTyKind; + return RT->getRecTyKind() == StringRecTyKind; } static StringRecTy *get() { return &Shared; } @@ -205,6 +211,8 @@ std::string getAsString() const override; bool typeIsConvertibleTo(const RecTy *RHS) const override; + + bool typeIsA(const RecTy *RHS) const override; }; /// 'dag' - Represent a dag fragment @@ -265,6 +273,8 @@ bool isSubClassOf(Record *Class) const; bool typeIsConvertibleTo(const RecTy *RHS) const override; + + bool typeIsA(const RecTy *RHS) const override; }; /// Find a common type that T1 and T2 convert to. @@ -353,8 +363,14 @@ /// invokes print on stderr. void dump() const; - /// This virtual function converts to the appropriate - /// Init based on the passed in type. + /// If this initializer is convertible to Ty, return an initializer whose + /// type is-a Ty, generating a !cast operation if required. Otherwise, return + /// nullptr. + virtual Init *getCastTo(RecTy *Ty) const = 0; + + /// Convert to an initializer whose type is-a Ty, or return nullptr if this + /// is not possible (this can happen if the initializer's type is convertible + /// to Ty, but there are unresolved references). virtual Init *convertInitializerTo(RecTy *Ty) const = 0; /// This method is used to implement the bitrange @@ -417,6 +433,7 @@ RecTy *getType() const { return Ty; } + Init *getCastTo(RecTy *Ty) const override; Init *convertInitializerTo(RecTy *Ty) const override; Init *convertInitializerBitRange(ArrayRef Bits) const override; @@ -443,6 +460,7 @@ static UnsetInit *get(); + Init *getCastTo(RecTy *Ty) const override; Init *convertInitializerTo(RecTy *Ty) const override; Init *getBit(unsigned Bit) const override { @@ -944,8 +962,6 @@ static VarBitInit *get(TypedInit *T, unsigned B); - Init *convertInitializerTo(RecTy *Ty) const override; - Init *getBitVar() const { return TI; } unsigned getBitNum() const { return Bit; } @@ -1089,8 +1105,6 @@ void Profile(FoldingSetNodeID &ID) const; - Init *convertInitializerTo(RecTy *Ty) const override; - Init *getOperator() const { return Val; } StringInit *getName() const { return ValName; } @@ -1173,16 +1187,7 @@ RecTy *getType() const { return TyAndPrefix.getPointer(); } Init *getValue() const { return Value; } - bool setValue(Init *V) { - if (V) { - Value = V->convertInitializerTo(getType()); - assert(!Value || !isa(Value) || - cast(Value)->getType()->typeIsConvertibleTo(getType())); - return Value == nullptr; - } - Value = nullptr; - return false; - } + bool setValue(Init *V); void dump() const; void print(raw_ostream &OS, bool PrintSem = true) const; Index: llvm/trunk/lib/TableGen/Record.cpp =================================================================== --- llvm/trunk/lib/TableGen/Record.cpp +++ llvm/trunk/lib/TableGen/Record.cpp @@ -63,6 +63,8 @@ return Kind == RHS->getRecTyKind(); } +bool RecTy::typeIsA(const RecTy *RHS) const { return this == RHS; } + bool BitRecTy::typeIsConvertibleTo(const RecTy *RHS) const{ if (RecTy::typeIsConvertibleTo(RHS) || RHS->getRecTyKind() == IntRecTyKind) return true; @@ -92,6 +94,12 @@ return (kind == BitRecTyKind && Size == 1) || (kind == IntRecTyKind); } +bool BitsRecTy::typeIsA(const RecTy *RHS) const { + if (const BitsRecTy *RHSb = dyn_cast(RHS)) + return RHSb->Size == Size; + return false; +} + bool IntRecTy::typeIsConvertibleTo(const RecTy *RHS) const { RecTyKind kind = RHS->getRecTyKind(); return kind==BitRecTyKind || kind==BitsRecTyKind || kind==IntRecTyKind; @@ -121,6 +129,12 @@ return false; } +bool ListRecTy::typeIsA(const RecTy *RHS) const { + if (const ListRecTy *RHSl = dyn_cast(RHS)) + return getElementType()->typeIsA(RHSl->getElementType()); + return false; +} + std::string DagRecTy::getAsString() const { return "dag"; } @@ -214,6 +228,10 @@ }); } +bool RecordRecTy::typeIsA(const RecTy *RHS) const { + return typeIsConvertibleTo(RHS); +} + static RecordRecTy *resolveRecordTypes(RecordRecTy *T1, RecordRecTy *T2) { SmallVector CommonSuperClasses; SmallVector Stack; @@ -275,17 +293,11 @@ return &TheInit; } -Init *UnsetInit::convertInitializerTo(RecTy *Ty) const { - if (auto *BRT = dyn_cast(Ty)) { - SmallVector NewBits(BRT->getNumBits()); - - for (unsigned i = 0; i != BRT->getNumBits(); ++i) - NewBits[i] = UnsetInit::get(); - - return BitsInit::get(NewBits); - } +Init *UnsetInit::getCastTo(RecTy *Ty) const { + return const_cast(this); +} - // All other types can just be returned. +Init *UnsetInit::convertInitializerTo(RecTy *Ty) const { return const_cast(this); } @@ -684,7 +696,7 @@ if (IntInit *LHSi = dyn_cast(LHS)) return StringInit::get(LHSi->getAsString()); - } else { + } else if (isa(getType())) { if (StringInit *Name = dyn_cast(LHS)) { // From TGParser::ParseIDValue if (CurRec) { @@ -729,15 +741,10 @@ PrintFatalError(CurRec->getLoc(), "Undefined reference:'" + Name->getValue() + "'\n"); } - - if (isa(getType())) { - if (BitsInit *BI = dyn_cast(LHS)) { - if (Init *NewInit = BI->convertInitializerTo(IntRecTy::get())) - return NewInit; - break; - } - } } + + if (Init *NewInit = LHS->convertInitializerTo(getType())) + return NewInit; break; case HEAD: @@ -1083,10 +1090,8 @@ } case IF: { - IntInit *LHSi = dyn_cast(LHS); - if (Init *I = LHS->convertInitializerTo(IntRecTy::get())) - LHSi = dyn_cast(I); - if (LHSi) { + if (IntInit *LHSi = dyn_cast_or_null( + LHS->convertInitializerTo(IntRecTy::get()))) { if (LHSi->getValue()) return MHS; return RHS; @@ -1102,19 +1107,12 @@ Init *lhs = LHS->resolveReferences(R); if (getOpcode() == IF && lhs != LHS) { - IntInit *Value = dyn_cast(lhs); - if (Init *I = lhs->convertInitializerTo(IntRecTy::get())) - Value = dyn_cast(I); - if (Value) { + if (IntInit *Value = dyn_cast_or_null( + lhs->convertInitializerTo(IntRecTy::get()))) { // Short-circuit - if (Value->getValue()) { - Init *mhs = MHS->resolveReferences(R); - return (TernOpInit::get(getOpcode(), lhs, mhs, RHS, getType())) - ->Fold(R.getCurrentRecord(), nullptr); - } - Init *rhs = RHS->resolveReferences(R); - return (TernOpInit::get(getOpcode(), lhs, MHS, rhs, getType())) - ->Fold(R.getCurrentRecord(), nullptr); + if (Value->getValue()) + return MHS->resolveReferences(R); + return RHS->resolveReferences(R); } } @@ -1158,79 +1156,12 @@ Init * TypedInit::convertInitializerTo(RecTy *Ty) const { - if (isa(Ty)) { - if (getType()->typeIsConvertibleTo(Ty)) - return const_cast(this); - return nullptr; - } - - if (isa(Ty)) { - if (isa(getType())) - return const_cast(this); - return nullptr; - } - - if (isa(Ty)) { - if (isa(getType())) - return const_cast(this); - return nullptr; - } - - if (isa(Ty)) { - // Accept variable if it is already of bit type! - if (isa(getType())) - return const_cast(this); - if (auto *BitsTy = dyn_cast(getType())) { - // Accept only bits<1> expression. - if (BitsTy->getNumBits() == 1) - return const_cast(this); - return nullptr; - } - // Ternary !if can be converted to bit, but only if both sides are - // convertible to a bit. - if (const auto *TOI = dyn_cast(this)) { - if (TOI->getOpcode() == TernOpInit::TernaryOp::IF && - TOI->getMHS()->convertInitializerTo(BitRecTy::get()) && - TOI->getRHS()->convertInitializerTo(BitRecTy::get())) - return const_cast(this); - return nullptr; - } - return nullptr; - } + if (getType() == Ty || getType()->typeIsA(Ty)) + return const_cast(this); - if (auto *BRT = dyn_cast(Ty)) { - if (BRT->getNumBits() == 1 && isa(getType())) - return BitsInit::get(const_cast(this)); - - if (getType()->typeIsConvertibleTo(BRT)) { - SmallVector NewBits(BRT->getNumBits()); - - for (unsigned i = 0; i != BRT->getNumBits(); ++i) - NewBits[i] = VarBitInit::get(const_cast(this), i); - return BitsInit::get(NewBits); - } - - return nullptr; - } - - if (auto *DLRT = dyn_cast(Ty)) { - if (auto *SLRT = dyn_cast(getType())) - if (SLRT->getElementType()->typeIsConvertibleTo(DLRT->getElementType())) - return const_cast(this); - return nullptr; - } - - if (auto *DRT = dyn_cast(Ty)) { - if (getType()->typeIsConvertibleTo(DRT)) - return const_cast(this); - return nullptr; - } - - if (auto *SRRT = dyn_cast(Ty)) { - if (getType()->typeIsConvertibleTo(SRRT)) - return const_cast(this); - return nullptr; - } + if (isa(getType()) && isa(Ty) && + cast(Ty)->getNumBits() == 1) + return BitsInit::get({const_cast(this)}); return nullptr; } @@ -1251,6 +1182,24 @@ return BitsInit::get(NewBits); } +Init *TypedInit::getCastTo(RecTy *Ty) const { + // Handle the common case quickly + if (getType() == Ty || getType()->typeIsA(Ty)) + return const_cast(this); + + if (Init *Converted = convertInitializerTo(Ty)) { + assert(!isa(Converted) || + cast(Converted)->getType()->typeIsA(Ty)); + return Converted; + } + + if (!getType()->typeIsConvertibleTo(Ty)) + return nullptr; + + return UnOpInit::get(UnOpInit::CAST, const_cast(this), Ty) + ->Fold(nullptr, nullptr); +} + Init *TypedInit::convertInitListSlice(ArrayRef Elements) const { ListRecTy *T = dyn_cast(getType()); if (!T) return nullptr; // Cannot subscript a non-list variable. @@ -1313,13 +1262,6 @@ return I; } -Init *VarBitInit::convertInitializerTo(RecTy *Ty) const { - if (isa(Ty)) - return const_cast(this); - - return nullptr; -} - std::string VarBitInit::getAsString() const { return TI->getAsString() + "{" + utostr(Bit) + "}"; } @@ -1485,13 +1427,6 @@ ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects(), NumArgs), makeArrayRef(getTrailingObjects(), NumArgNames)); } -Init *DagInit::convertInitializerTo(RecTy *Ty) const { - if (isa(Ty)) - return const_cast(this); - - return nullptr; -} - Init *DagInit::resolveReferences(Resolver &R) const { SmallVector NewArgs; NewArgs.reserve(arg_size()); @@ -1530,7 +1465,7 @@ RecordVal::RecordVal(Init *N, RecTy *T, bool P) : Name(N), TyAndPrefix(T, P) { - Value = UnsetInit::get()->convertInitializerTo(T); + setValue(UnsetInit::get()); assert(Value && "Cannot create unset value for current type!"); } @@ -1538,6 +1473,28 @@ return cast(getNameInit())->getValue(); } +bool RecordVal::setValue(Init *V) { + if (V) { + Value = V->getCastTo(getType()); + if (Value) { + assert(!isa(Value) || + cast(Value)->getType()->typeIsA(getType())); + if (BitsRecTy *BTy = dyn_cast(getType())) { + if (!isa(Value)) { + SmallVector Bits; + Bits.reserve(BTy->getNumBits()); + for (unsigned i = 0, e = BTy->getNumBits(); i < e; ++i) + Bits.push_back(Value->getBit(i)); + Value = BitsInit::get(Bits); + } + } + } + return Value == nullptr; + } + Value = nullptr; + return false; +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; } #endif Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -117,13 +117,10 @@ "' is not a bits type"); // Convert the incoming value to a bits type of the appropriate size... - Init *BI = V->convertInitializerTo(BitsRecTy::get(BitList.size())); + Init *BI = V->getCastTo(BitsRecTy::get(BitList.size())); if (!BI) return Error(Loc, "Initializer is not compatible with bit range"); - // We should have a BitsInit type now. - BitsInit *BInit = cast(BI); - SmallVector NewBits(CurVal->getNumBits()); // Loop over bits, assigning values as appropriate. @@ -132,7 +129,7 @@ if (NewBits[Bit]) return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" + ValName->getAsUnquotedString() + "' more than once"); - NewBits[Bit] = BInit->getBit(i); + NewBits[Bit] = BI->getBit(i); } for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i) @@ -1408,7 +1405,7 @@ // Fallthrough to try convert this to a bit. } // All other values must be convertible to just a single bit. - Init *Bit = Vals[i]->convertInitializerTo(BitRecTy::get()); + Init *Bit = Vals[i]->getCastTo(BitRecTy::get()); if (!Bit) { Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() + ") is not convertable to a bit"); @@ -2528,11 +2525,11 @@ DefName = CurRec->getNameInit(); DefNameString = dyn_cast(DefName); - if (!DefNameString) + if (!DefNameString) { DefName = DefName->convertInitializerTo(StringRecTy::get()); + DefNameString = dyn_cast(DefName); + } - // We ran out of options here... - DefNameString = dyn_cast(DefName); if (!DefNameString) { PrintFatalError(CurRec->getLoc()[CurRec->getLoc().size() - 1], DefName->getAsUnquotedString() + " is not a string."); Index: llvm/trunk/test/TableGen/BitsInit.td =================================================================== --- llvm/trunk/test/TableGen/BitsInit.td +++ llvm/trunk/test/TableGen/BitsInit.td @@ -69,7 +69,7 @@ // CHECK: bits<3> D4; // CHECK: bits<1> D5 = { 0 }; // CHECK: bits<1> D6 = { 1 }; -// CHECK: bits<1> D7 = { ? }; +// CHECK: bits<1> D7 = { !cast(3) }; // CHECK: bits<2> D8; // CHECK: bits<8> E = { 0, 0, 1, ?, 0, 0, 1, 0 }; // CHECK: bits<8> F1 = { 0, 1, 1, 0, 0, 1, 0, 0 }; Index: llvm/trunk/test/TableGen/BitsInitOverflow.td =================================================================== --- llvm/trunk/test/TableGen/BitsInitOverflow.td +++ llvm/trunk/test/TableGen/BitsInitOverflow.td @@ -1,4 +1,8 @@ -// RUN: not llvm-tblgen %s 2> /dev/null +// RUN: llvm-tblgen %s | FileCheck %s + +// Check that a large integer is not truncated to a small bit sequence. +// +// CHECK: bits<2> X = { !cast>(5){1}, !cast>(5){0} }; def { bits<2> X = 5; // bitfield is too small, reject Index: llvm/trunk/test/TableGen/FieldAccess.td =================================================================== --- llvm/trunk/test/TableGen/FieldAccess.td +++ llvm/trunk/test/TableGen/FieldAccess.td @@ -1,6 +1,20 @@ -// RUN: llvm-tblgen %s +// RUN: llvm-tblgen %s | FileCheck %s // XFAIL: vg_leak +// CHECK: --- Defs --- + +// CHECK: def a { +// CHECK: string blu = ""; +// CHECK: } + +// CHECK: def b { +// CHECK: string blu = ""; +// CHECK: } + +// CHECK: def c { +// CHECK: string blu = ""; +// CHECK: } + class Bla { string blu = t; @@ -12,5 +26,5 @@ } def a : Bli>; -def b : Bla(a.bla).blu>; // works -def c : Bla; // doesn't work: Cannot access field 'blu' of value 'a.bla' +def b : Bla(a.bla).blu>; +def c : Bla; Index: llvm/trunk/test/TableGen/code.td =================================================================== --- llvm/trunk/test/TableGen/code.td +++ llvm/trunk/test/TableGen/code.td @@ -3,13 +3,12 @@ // CHECK: --- Defs --- -// TODO: Both of these should result in CodeInits, i.e. print [{...}]. // CHECK: def A0 { -// CHECK: code Code = "Simple"; +// CHECK: code Code = [{Simple}]; // CHECK: } // CHECK: def B0 { -// CHECK: code Code = "With paste 7"; +// CHECK: code Code = [{With paste 7}]; // CHECK: } class A {