summaryrefslogtreecommitdiff
path: root/llvm/lib/TableGen
diff options
context:
space:
mode:
authorNicolai Haehnle <nhaehnle@gmail.com>2018-03-06 13:48:39 +0000
committerNicolai Haehnle <nhaehnle@gmail.com>2018-03-06 13:48:39 +0000
commit67771d15fe8147d2b05ed4af0323d98360296be9 (patch)
tree461ad5bd840479cbda3e8ec98ccc9f3d5adb89fa /llvm/lib/TableGen
parent72acd5f0b6741985ea07c287a48637591fa24a03 (diff)
TableGen: Allow !cast of records, cleanup conversion machinery
Summary: Distinguish two relationships between types: is-a and convertible-to. For example, a bit is not an int or vice versa, but they can be converted into each other (with range checks that you can think of as "dynamic": unlike other type checks, those range checks do not happen during parsing, but only once the final values have been established). Actually converting initializers between types is subtle: even when values of type A can be converted to type B (e.g. int into string), it may not be possible to do so with a concrete initializer (e.g., a VarInit that refers to a variable of type int cannot be immediately converted to a string). For this reason, distinguish between getCastTo and convertInitializerTo: the latter implements the actual conversion when appropriate, while the former will first try to do the actual conversion and fall back to introducing a !cast operation so that the conversion will be delayed until variable references have been resolved. To make the approach of adding !cast operations to work, !cast needs to fallback to convertInitializerTo when the special string <-> record logic does not apply. This enables casting records to a subclass, although that new functionality is only truly useful together with !isa, which will be added in a later change. The test is removed because it uses !srl on a bit sequence, which cannot really be supported consistently, but luckily isn't used anywhere either. Change-Id: I98168bf52649176654ed2ec61a29bdb29970cfe7 Reviewers: arsenm, craig.topper, tra, MartinO Subscribers: wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D43753
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r--llvm/lib/TableGen/Record.cpp201
-rw-r--r--llvm/lib/TableGen/TGParser.cpp15
2 files changed, 85 insertions, 131 deletions
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index a2f586c3e57..3fa78a61df7 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -63,6 +63,8 @@ bool RecTy::typeIsConvertibleTo(const RecTy *RHS) 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;
@@ -92,6 +94,12 @@ bool BitsRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
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;
@@ -121,6 +129,12 @@ bool ListRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
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";
}
@@ -214,6 +228,10 @@ bool RecordRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
});
}
+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;
@@ -275,17 +293,11 @@ UnsetInit *UnsetInit::get() {
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);
}
@@ -684,7 +696,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
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) {
@@ -729,15 +741,10 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
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:
@@ -1083,10 +1090,8 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
}
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;
@@ -1102,19 +1107,12 @@ Init *TernOpInit::resolveReferences(Resolver &R) const {
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);
}
}
@@ -1158,79 +1156,12 @@ RecTy *TypedInit::getFieldType(StringInit *FieldName) const {
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;
}
@@ -1251,6 +1182,24 @@ Init *TypedInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
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.
@@ -1313,13 +1262,6 @@ VarBitInit *VarBitInit::get(TypedInit *T, unsigned B) {
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) + "}";
}
@@ -1485,13 +1427,6 @@ void DagInit::Profile(FoldingSetNodeID &ID) const {
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());
@@ -1530,7 +1465,7 @@ std::string DagInit::getAsString() const {
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 @@ StringRef RecordVal::getName() const {
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
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 58bb743de77..79f0799197b 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -117,13 +117,10 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
"' 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<BitsInit>(BI);
-
SmallVector<Init *, 16> NewBits(CurVal->getNumBits());
// Loop over bits, assigning values as appropriate.
@@ -132,7 +129,7 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
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 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
// 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 @@ Record *TGParser::InstantiateMulticlassDef(MultiClass &MC, Record *DefProto,
DefName = CurRec->getNameInit();
DefNameString = dyn_cast<StringInit>(DefName);
- if (!DefNameString)
+ if (!DefNameString) {
DefName = DefName->convertInitializerTo(StringRecTy::get());
+ DefNameString = dyn_cast<StringInit>(DefName);
+ }
- // We ran out of options here...
- DefNameString = dyn_cast<StringInit>(DefName);
if (!DefNameString) {
PrintFatalError(CurRec->getLoc()[CurRec->getLoc().size() - 1],
DefName->getAsUnquotedString() + " is not a string.");