Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@163360 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/TableGen/Record.cpp b/lib/TableGen/Record.cpp
index 3176b2a..b2a7b62 100644
--- a/lib/TableGen/Record.cpp
+++ b/lib/TableGen/Record.cpp
@@ -112,7 +112,10 @@
}
Init *BitRecTy::convertValue(TypedInit *VI) {
- if (dynamic_cast<BitRecTy*>(VI->getType()))
+ RecTy *Ty = VI->getType();
+ if (dynamic_cast<BitRecTy*>(Ty) ||
+ dynamic_cast<BitsRecTy*>(Ty) ||
+ dynamic_cast<IntRecTy*>(Ty))
return VI; // Accept variable if it is already of bit type!
return 0;
}
@@ -178,60 +181,15 @@
}
Init *BitsRecTy::convertValue(TypedInit *VI) {
- if (BitsRecTy *BRT = dynamic_cast<BitsRecTy*>(VI->getType()))
- if (BRT->Size == Size) {
- SmallVector<Init *, 16> NewBits(Size);
-
- for (unsigned i = 0; i != Size; ++i)
- NewBits[i] = VarBitInit::get(VI, i);
- return BitsInit::get(NewBits);
- }
-
if (Size == 1 && dynamic_cast<BitRecTy*>(VI->getType()))
return BitsInit::get(VI);
- if (TernOpInit *Tern = dynamic_cast<TernOpInit*>(VI)) {
- if (Tern->getOpcode() == TernOpInit::IF) {
- Init *LHS = Tern->getLHS();
- Init *MHS = Tern->getMHS();
- Init *RHS = Tern->getRHS();
+ if (VI->getType()->typeIsConvertibleTo(this)) {
+ SmallVector<Init *, 16> NewBits(Size);
- IntInit *MHSi = dynamic_cast<IntInit*>(MHS);
- IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
-
- if (MHSi && RHSi) {
- int64_t MHSVal = MHSi->getValue();
- int64_t RHSVal = RHSi->getValue();
-
- if (canFitInBitfield(MHSVal, Size) && canFitInBitfield(RHSVal, Size)) {
- SmallVector<Init *, 16> NewBits(Size);
-
- for (unsigned i = 0; i != Size; ++i)
- NewBits[i] =
- TernOpInit::get(TernOpInit::IF, LHS,
- IntInit::get((MHSVal & (1LL << i)) ? 1 : 0),
- IntInit::get((RHSVal & (1LL << i)) ? 1 : 0),
- VI->getType());
-
- return BitsInit::get(NewBits);
- }
- } else {
- BitsInit *MHSbs = dynamic_cast<BitsInit*>(MHS);
- BitsInit *RHSbs = dynamic_cast<BitsInit*>(RHS);
-
- if (MHSbs && RHSbs) {
- SmallVector<Init *, 16> NewBits(Size);
-
- for (unsigned i = 0; i != Size; ++i)
- NewBits[i] = TernOpInit::get(TernOpInit::IF, LHS,
- MHSbs->getBit(i),
- RHSbs->getBit(i),
- VI->getType());
-
- return BitsInit::get(NewBits);
- }
- }
- }
+ for (unsigned i = 0; i != Size; ++i)
+ NewBits[i] = VarBitInit::get(VI, i);
+ return BitsInit::get(NewBits);
}
return 0;
@@ -519,6 +477,15 @@
return Result + " }";
}
+// Fix bit initializer to preserve the behavior that bit reference from a unset
+// bits initializer will resolve into VarBitInit to keep the field name and bit
+// number used in targets with fixed insn length.
+static Init *fixBitInit(const RecordVal *RV, Init *Before, Init *After) {
+ if (RV || After != UnsetInit::get())
+ return After;
+ return Before;
+}
+
// resolveReferences - If there are any field references that refer to fields
// that have been filled in, we can propagate the values now.
//
@@ -526,16 +493,39 @@
bool Changed = false;
SmallVector<Init *, 16> NewBits(getNumBits());
- for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
- Init *B;
- Init *CurBit = getBit(i);
+ Init *CachedInit = 0;
+ Init *CachedBitVar = 0;
+ bool CachedBitVarChanged = false;
- do {
- B = CurBit;
- CurBit = CurBit->resolveReferences(R, RV);
- Changed |= B != CurBit;
- } while (B != CurBit);
+ for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
+ Init *CurBit = Bits[i];
+ Init *CurBitVar = CurBit->getBitVar();
+
NewBits[i] = CurBit;
+
+ if (CurBitVar == CachedBitVar) {
+ if (CachedBitVarChanged) {
+ Init *Bit = CachedInit->getBit(CurBit->getBitNum());
+ NewBits[i] = fixBitInit(RV, CurBit, Bit);
+ }
+ continue;
+ }
+ CachedBitVar = CurBitVar;
+ CachedBitVarChanged = false;
+
+ Init *B;
+ do {
+ B = CurBitVar;
+ CurBitVar = CurBitVar->resolveReferences(R, RV);
+ CachedBitVarChanged |= B != CurBitVar;
+ Changed |= B != CurBitVar;
+ } while (B != CurBitVar);
+ CachedInit = CurBitVar;
+
+ if (CachedBitVarChanged) {
+ Init *Bit = CurBitVar->getBit(CurBit->getBitNum());
+ NewBits[i] = fixBitInit(RV, CurBit, Bit);
+ }
}
if (Changed)
@@ -682,20 +672,6 @@
return Result + "]";
}
-Init *OpInit::resolveBitReference(Record &R, const RecordVal *IRV,
- unsigned Bit) const {
- Init *Folded = Fold(&R, 0);
-
- if (Folded != this) {
- TypedInit *Typed = dynamic_cast<TypedInit *>(Folded);
- if (Typed) {
- return Typed->resolveBitReference(R, IRV, Bit);
- }
- }
-
- return 0;
-}
-
Init *OpInit::resolveListElementReference(Record &R, const RecordVal *IRV,
unsigned Elt) const {
Init *Resolved = resolveReferences(R, IRV);
@@ -718,6 +694,12 @@
return 0;
}
+Init *OpInit::getBit(unsigned Bit) const {
+ if (getType() == BitRecTy::get())
+ return const_cast<OpInit*>(this);
+ return VarBitInit::get(const_cast<OpInit*>(this), Bit);
+}
+
UnOpInit *UnOpInit::get(UnaryOp opc, Init *lhs, RecTy *Type) {
typedef std::pair<std::pair<unsigned, Init *>, RecTy *> Key;
@@ -922,9 +904,9 @@
case EQ: {
// try to fold eq comparison for 'bit' and 'int', otherwise fallback
// to string objects.
- IntInit* L =
+ IntInit *L =
dynamic_cast<IntInit*>(LHS->convertInitializerTo(IntRecTy::get()));
- IntInit* R =
+ IntInit *R =
dynamic_cast<IntInit*>(RHS->convertInitializerTo(IntRecTy::get()));
if (L && R)
@@ -1324,25 +1306,10 @@
return NameString->getValue();
}
-Init *VarInit::resolveBitReference(Record &R, const RecordVal *IRV,
- unsigned Bit) const {
- if (R.isTemplateArg(getNameInit())) return 0;
- if (IRV && IRV->getNameInit() != getNameInit()) return 0;
-
- RecordVal *RV = R.getValue(getNameInit());
- assert(RV && "Reference to a non-existent variable?");
- assert(dynamic_cast<BitsInit*>(RV->getValue()));
- BitsInit *BI = (BitsInit*)RV->getValue();
-
- assert(Bit < BI->getNumBits() && "Bit reference out of range!");
- Init *B = BI->getBit(Bit);
-
- // If the bit is set to some value, or if we are resolving a reference to a
- // specific variable and that variable is explicitly unset, then replace the
- // VarBitInit with it.
- if (IRV || !dynamic_cast<UnsetInit*>(B))
- return B;
- return 0;
+Init *VarInit::getBit(unsigned Bit) const {
+ if (getType() == BitRecTy::get())
+ return const_cast<VarInit*>(this);
+ return VarBitInit::get(const_cast<VarInit*>(this), Bit);
}
Init *VarInit::resolveListElementReference(Record &R,
@@ -1425,9 +1392,11 @@
}
Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) const {
- if (Init *I = getVariable()->resolveBitReference(R, RV, getBitNum()))
- return I;
- return const_cast<VarBitInit *>(this);
+ Init *I = TI->resolveReferences(R, RV);
+ if (TI != I)
+ return I->getBit(getBitNum());
+
+ return const_cast<VarBitInit*>(this);
}
VarListElementInit *VarListElementInit::get(TypedInit *T,
@@ -1456,11 +1425,10 @@
return const_cast<VarListElementInit *>(this);
}
-Init *VarListElementInit::resolveBitReference(Record &R, const RecordVal *RV,
- unsigned Bit) const {
- // FIXME: This should be implemented, to support references like:
- // bit B = AA[0]{1};
- return 0;
+Init *VarListElementInit::getBit(unsigned Bit) const {
+ if (getType() == BitRecTy::get())
+ return const_cast<VarListElementInit*>(this);
+ return VarBitInit::get(const_cast<VarListElementInit*>(this), Bit);
}
Init *VarListElementInit:: resolveListElementReference(Record &R,
@@ -1513,17 +1481,10 @@
return I;
}
-Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV,
- unsigned Bit) const {
- if (Init *BitsVal = Rec->getFieldInit(R, RV, FieldName))
- if (BitsInit *BI = dynamic_cast<BitsInit*>(BitsVal)) {
- assert(Bit < BI->getNumBits() && "Bit reference out of range!");
- Init *B = BI->getBit(Bit);
-
- if (dynamic_cast<BitInit*>(B)) // If the bit is set.
- return B; // Replace the VarBitInit with it.
- }
- return 0;
+Init *FieldInit::getBit(unsigned Bit) const {
+ if (getType() == BitRecTy::get())
+ return const_cast<FieldInit*>(this);
+ return VarBitInit::get(const_cast<FieldInit*>(this), Bit);
}
Init *FieldInit::resolveListElementReference(Record &R, const RecordVal *RV,
@@ -1751,7 +1712,15 @@
if (RV == &Values[i]) // Skip resolve the same field as the given one
continue;
if (Init *V = Values[i].getValue())
- Values[i].setValue(V->resolveReferences(*this, RV));
+ if (Values[i].setValue(V->resolveReferences(*this, RV)))
+ throw TGError(getLoc(), "Invalid value is found when setting '"
+ + Values[i].getNameInitAsString()
+ + "' after resolving references"
+ + (RV ? " against '" + RV->getNameInitAsString()
+ + "' of ("
+ + RV->getValue()->getAsUnquotedString() + ")"
+ : "")
+ + "\n");
}
Init *OldName = getNameInit();
Init *NewName = Name->resolveReferences(*this, RV);
diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp
index 5e2b66e..aee93e7 100644
--- a/lib/TableGen/TGParser.cpp
+++ b/lib/TableGen/TGParser.cpp
@@ -1044,35 +1044,28 @@
switch (LexCode) {
default: llvm_unreachable("Unhandled code!");
case tgtok::XIf: {
- // FIXME: The `!if' operator doesn't handle non-TypedInit well at
- // all. This can be made much more robust.
- TypedInit *MHSt = dynamic_cast<TypedInit*>(MHS);
- TypedInit *RHSt = dynamic_cast<TypedInit*>(RHS);
-
RecTy *MHSTy = 0;
RecTy *RHSTy = 0;
- if (MHSt == 0 && RHSt == 0) {
- BitsInit *MHSbits = dynamic_cast<BitsInit*>(MHS);
- BitsInit *RHSbits = dynamic_cast<BitsInit*>(RHS);
-
- if (MHSbits && RHSbits &&
- MHSbits->getNumBits() == RHSbits->getNumBits()) {
- Type = BitRecTy::get();
- break;
- } else {
- BitInit *MHSbit = dynamic_cast<BitInit*>(MHS);
- BitInit *RHSbit = dynamic_cast<BitInit*>(RHS);
-
- if (MHSbit && RHSbit) {
- Type = BitRecTy::get();
- break;
- }
- }
- } else if (MHSt != 0 && RHSt != 0) {
+ if (TypedInit *MHSt = dynamic_cast<TypedInit*>(MHS))
MHSTy = MHSt->getType();
+ if (BitsInit *MHSbits = dynamic_cast<BitsInit*>(MHS))
+ MHSTy = BitsRecTy::get(MHSbits->getNumBits());
+ if (dynamic_cast<BitInit*>(MHS))
+ MHSTy = BitRecTy::get();
+
+ if (TypedInit *RHSt = dynamic_cast<TypedInit*>(RHS))
RHSTy = RHSt->getType();
- }
+ if (BitsInit *RHSbits = dynamic_cast<BitsInit*>(RHS))
+ RHSTy = BitsRecTy::get(RHSbits->getNumBits());
+ if (dynamic_cast<BitInit*>(RHS))
+ RHSTy = BitRecTy::get();
+
+ // For UnsetInit, it's typed from the other hand.
+ if (dynamic_cast<UnsetInit*>(MHS))
+ MHSTy = RHSTy;
+ if (dynamic_cast<UnsetInit*>(RHS))
+ RHSTy = MHSTy;
if (!MHSTy || !RHSTy) {
TokError("could not get type for !if");