the operand of the paste.
``!cast<type>(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<string> 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<type>(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<string>
+ 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'
class RecordVal;
class Resolver;
class StringInit;
+class TypedInit;
//===----------------------------------------------------------------------===//
// Type Classes
/// 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<this>.
ListRecTy *getListTy();
};
std::string getAsString() const override;
bool typeIsConvertibleTo(const RecTy *RHS) const override;
+
+ bool typeIsA(const RecTy *RHS) const override;
};
/// 'code' - Represent a code fragment
public:
static bool classof(const RecTy *RT) {
- return RT->getRecTyKind() == StringRecTyKind ||
- RT->getRecTyKind() == CodeRecTyKind;
+ return RT->getRecTyKind() == StringRecTyKind;
}
static StringRecTy *get() { return &Shared; }
std::string getAsString() const override;
bool typeIsConvertibleTo(const RecTy *RHS) const override;
+
+ bool typeIsA(const RecTy *RHS) const override;
};
/// 'dag' - Represent a dag fragment
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.
/// 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
RecTy *getType() const { return Ty; }
+ Init *getCastTo(RecTy *Ty) const override;
Init *convertInitializerTo(RecTy *Ty) const override;
Init *convertInitializerBitRange(ArrayRef<unsigned> Bits) const override;
static UnsetInit *get();
+ Init *getCastTo(RecTy *Ty) const override;
Init *convertInitializerTo(RecTy *Ty) const override;
Init *getBit(unsigned Bit) const override {
static VarBitInit *get(TypedInit *T, unsigned B);
- Init *convertInitializerTo(RecTy *Ty) const override;
-
Init *getBitVar() const { return TI; }
unsigned getBitNum() const { return Bit; }
void Profile(FoldingSetNodeID &ID) const;
- Init *convertInitializerTo(RecTy *Ty) const override;
-
Init *getOperator() const { return Val; }
StringInit *getName() const { return ValName; }
RecTy *getType() const { return TyAndPrefix.getPointer(); }
Init *getValue() const { return Value; }
- bool setValue(Init *V) {
- if (V) {
- Value = V->convertInitializerTo(getType());
- assert(!Value || !isa<TypedInit>(Value) ||
- cast<TypedInit>(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;
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;
return (kind == BitRecTyKind && Size == 1) || (kind == IntRecTyKind);
}
+bool BitsRecTy::typeIsA(const RecTy *RHS) const {
+ if (const BitsRecTy *RHSb = dyn_cast<BitsRecTy>(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;
return false;
}
+bool ListRecTy::typeIsA(const RecTy *RHS) const {
+ if (const ListRecTy *RHSl = dyn_cast<ListRecTy>(RHS))
+ return getElementType()->typeIsA(RHSl->getElementType());
+ return false;
+}
+
std::string DagRecTy::getAsString() const {
return "dag";
}
});
}
+bool RecordRecTy::typeIsA(const RecTy *RHS) const {
+ return typeIsConvertibleTo(RHS);
+}
+
static RecordRecTy *resolveRecordTypes(RecordRecTy *T1, RecordRecTy *T2) {
SmallVector<Record *, 4> CommonSuperClasses;
SmallVector<Record *, 4> Stack;
return &TheInit;
}
-Init *UnsetInit::convertInitializerTo(RecTy *Ty) const {
- if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
- SmallVector<Init *, 16> 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<UnsetInit *>(this);
+}
- // All other types can just be returned.
+Init *UnsetInit::convertInitializerTo(RecTy *Ty) const {
return const_cast<UnsetInit *>(this);
}
if (IntInit *LHSi = dyn_cast<IntInit>(LHS))
return StringInit::get(LHSi->getAsString());
- } else {
+ } else if (isa<RecordRecTy>(getType())) {
if (StringInit *Name = dyn_cast<StringInit>(LHS)) {
// From TGParser::ParseIDValue
if (CurRec) {
PrintFatalError(CurRec->getLoc(),
"Undefined reference:'" + Name->getValue() + "'\n");
}
-
- if (isa<IntRecTy>(getType())) {
- if (BitsInit *BI = dyn_cast<BitsInit>(LHS)) {
- if (Init *NewInit = BI->convertInitializerTo(IntRecTy::get()))
- return NewInit;
- break;
- }
- }
}
+
+ if (Init *NewInit = LHS->convertInitializerTo(getType()))
+ return NewInit;
break;
case HEAD:
}
case IF: {
- IntInit *LHSi = dyn_cast<IntInit>(LHS);
- if (Init *I = LHS->convertInitializerTo(IntRecTy::get()))
- LHSi = dyn_cast<IntInit>(I);
- if (LHSi) {
+ if (IntInit *LHSi = dyn_cast_or_null<IntInit>(
+ LHS->convertInitializerTo(IntRecTy::get()))) {
if (LHSi->getValue())
return MHS;
return RHS;
Init *lhs = LHS->resolveReferences(R);
if (getOpcode() == IF && lhs != LHS) {
- IntInit *Value = dyn_cast<IntInit>(lhs);
- if (Init *I = lhs->convertInitializerTo(IntRecTy::get()))
- Value = dyn_cast<IntInit>(I);
- if (Value) {
+ if (IntInit *Value = dyn_cast_or_null<IntInit>(
+ 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);
}
}
Init *
TypedInit::convertInitializerTo(RecTy *Ty) const {
- if (isa<IntRecTy>(Ty)) {
- if (getType()->typeIsConvertibleTo(Ty))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
+ if (getType() == Ty || getType()->typeIsA(Ty))
+ return const_cast<TypedInit *>(this);
- if (isa<StringRecTy>(Ty)) {
- if (isa<StringRecTy>(getType()))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
-
- if (isa<CodeRecTy>(Ty)) {
- if (isa<CodeRecTy>(getType()))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
-
- if (isa<BitRecTy>(Ty)) {
- // Accept variable if it is already of bit type!
- if (isa<BitRecTy>(getType()))
- return const_cast<TypedInit *>(this);
- if (auto *BitsTy = dyn_cast<BitsRecTy>(getType())) {
- // Accept only bits<1> expression.
- if (BitsTy->getNumBits() == 1)
- return const_cast<TypedInit *>(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<TernOpInit>(this)) {
- if (TOI->getOpcode() == TernOpInit::TernaryOp::IF &&
- TOI->getMHS()->convertInitializerTo(BitRecTy::get()) &&
- TOI->getRHS()->convertInitializerTo(BitRecTy::get()))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
- return nullptr;
- }
-
- if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
- if (BRT->getNumBits() == 1 && isa<BitRecTy>(getType()))
- return BitsInit::get(const_cast<TypedInit *>(this));
-
- if (getType()->typeIsConvertibleTo(BRT)) {
- SmallVector<Init *, 16> NewBits(BRT->getNumBits());
-
- for (unsigned i = 0; i != BRT->getNumBits(); ++i)
- NewBits[i] = VarBitInit::get(const_cast<TypedInit *>(this), i);
- return BitsInit::get(NewBits);
- }
-
- return nullptr;
- }
-
- if (auto *DLRT = dyn_cast<ListRecTy>(Ty)) {
- if (auto *SLRT = dyn_cast<ListRecTy>(getType()))
- if (SLRT->getElementType()->typeIsConvertibleTo(DLRT->getElementType()))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
-
- if (auto *DRT = dyn_cast<DagRecTy>(Ty)) {
- if (getType()->typeIsConvertibleTo(DRT))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
-
- if (auto *SRRT = dyn_cast<RecordRecTy>(Ty)) {
- if (getType()->typeIsConvertibleTo(SRRT))
- return const_cast<TypedInit *>(this);
- return nullptr;
- }
+ if (isa<BitRecTy>(getType()) && isa<BitsRecTy>(Ty) &&
+ cast<BitsRecTy>(Ty)->getNumBits() == 1)
+ return BitsInit::get({const_cast<TypedInit *>(this)});
return nullptr;
}
return BitsInit::get(NewBits);
}
+Init *TypedInit::getCastTo(RecTy *Ty) const {
+ // Handle the common case quickly
+ if (getType() == Ty || getType()->typeIsA(Ty))
+ return const_cast<TypedInit *>(this);
+
+ if (Init *Converted = convertInitializerTo(Ty)) {
+ assert(!isa<TypedInit>(Converted) ||
+ cast<TypedInit>(Converted)->getType()->typeIsA(Ty));
+ return Converted;
+ }
+
+ if (!getType()->typeIsConvertibleTo(Ty))
+ return nullptr;
+
+ return UnOpInit::get(UnOpInit::CAST, const_cast<TypedInit *>(this), Ty)
+ ->Fold(nullptr, nullptr);
+}
+
Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const {
ListRecTy *T = dyn_cast<ListRecTy>(getType());
if (!T) return nullptr; // Cannot subscript a non-list variable.
return I;
}
-Init *VarBitInit::convertInitializerTo(RecTy *Ty) const {
- if (isa<BitRecTy>(Ty))
- return const_cast<VarBitInit *>(this);
-
- return nullptr;
-}
-
std::string VarBitInit::getAsString() const {
return TI->getAsString() + "{" + utostr(Bit) + "}";
}
ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects<Init *>(), NumArgs), makeArrayRef(getTrailingObjects<StringInit *>(), NumArgNames));
}
-Init *DagInit::convertInitializerTo(RecTy *Ty) const {
- if (isa<DagRecTy>(Ty))
- return const_cast<DagInit *>(this);
-
- return nullptr;
-}
-
Init *DagInit::resolveReferences(Resolver &R) const {
SmallVector<Init*, 8> NewArgs;
NewArgs.reserve(arg_size());
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!");
}
return cast<StringInit>(getNameInit())->getValue();
}
+bool RecordVal::setValue(Init *V) {
+ if (V) {
+ Value = V->getCastTo(getType());
+ if (Value) {
+ assert(!isa<TypedInit>(Value) ||
+ cast<TypedInit>(Value)->getType()->typeIsA(getType()));
+ if (BitsRecTy *BTy = dyn_cast<BitsRecTy>(getType())) {
+ if (!isa<BitsInit>(Value)) {
+ SmallVector<Init *, 64> 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