mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-20 09:30:43 +00:00
77f8274c7d
Make all of the RecTy constructors private, and use get() factory methods instead. Return singleton instances when it makes sense. ListTy instance pointers are stored in the element RecTy instance. BitsRecTy instance pointers, one per length, are stored in a static vector. Also unique DefInit instances. A Record has a unique DefInit which has a unique RecordRecTy instance. This saves some 200k-300k RecTy allocations when parsing ARM.td. It reduces TableGen's heap usage by almost 50%. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@135399 91177308-0d34-0410-b5e6-96231b3b80d8
1612 lines
48 KiB
C++
1612 lines
48 KiB
C++
//===- Record.cpp - Record implementation ---------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implement the tablegen record classes.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Record.h"
|
|
#include "Error.h"
|
|
#include "llvm/Support/DataTypes.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Type implementations
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
BitRecTy BitRecTy::Shared;
|
|
IntRecTy IntRecTy::Shared;
|
|
StringRecTy StringRecTy::Shared;
|
|
CodeRecTy CodeRecTy::Shared;
|
|
DagRecTy DagRecTy::Shared;
|
|
|
|
void RecTy::dump() const { print(errs()); }
|
|
|
|
ListRecTy *RecTy::getListTy() {
|
|
if (!ListTy)
|
|
ListTy = new ListRecTy(this);
|
|
return ListTy;
|
|
}
|
|
|
|
Init *BitRecTy::convertValue(BitsInit *BI) {
|
|
if (BI->getNumBits() != 1) return 0; // Only accept if just one bit!
|
|
return BI->getBit(0);
|
|
}
|
|
|
|
bool BitRecTy::baseClassOf(const BitsRecTy *RHS) const {
|
|
return RHS->getNumBits() == 1;
|
|
}
|
|
|
|
Init *BitRecTy::convertValue(IntInit *II) {
|
|
int64_t Val = II->getValue();
|
|
if (Val != 0 && Val != 1) return 0; // Only accept 0 or 1 for a bit!
|
|
|
|
return new BitInit(Val != 0);
|
|
}
|
|
|
|
Init *BitRecTy::convertValue(TypedInit *VI) {
|
|
if (dynamic_cast<BitRecTy*>(VI->getType()))
|
|
return VI; // Accept variable if it is already of bit type!
|
|
return 0;
|
|
}
|
|
|
|
BitsRecTy *BitsRecTy::get(unsigned Sz) {
|
|
static std::vector<BitsRecTy*> Shared;
|
|
if (Sz >= Shared.size())
|
|
Shared.resize(Sz + 1);
|
|
BitsRecTy *&Ty = Shared[Sz];
|
|
if (!Ty)
|
|
Ty = new BitsRecTy(Sz);
|
|
return Ty;
|
|
}
|
|
|
|
std::string BitsRecTy::getAsString() const {
|
|
return "bits<" + utostr(Size) + ">";
|
|
}
|
|
|
|
Init *BitsRecTy::convertValue(UnsetInit *UI) {
|
|
BitsInit *Ret = new BitsInit(Size);
|
|
|
|
for (unsigned i = 0; i != Size; ++i)
|
|
Ret->setBit(i, new UnsetInit());
|
|
return Ret;
|
|
}
|
|
|
|
Init *BitsRecTy::convertValue(BitInit *UI) {
|
|
if (Size != 1) return 0; // Can only convert single bit.
|
|
BitsInit *Ret = new BitsInit(1);
|
|
Ret->setBit(0, UI);
|
|
return Ret;
|
|
}
|
|
|
|
/// canFitInBitfield - Return true if the number of bits is large enough to hold
|
|
/// the integer value.
|
|
static bool canFitInBitfield(int64_t Value, unsigned NumBits) {
|
|
// For example, with NumBits == 4, we permit Values from [-7 .. 15].
|
|
return (NumBits >= sizeof(Value) * 8) ||
|
|
(Value >> NumBits == 0) || (Value >> (NumBits-1) == -1);
|
|
}
|
|
|
|
/// convertValue from Int initializer to bits type: Split the integer up into the
|
|
/// appropriate bits.
|
|
///
|
|
Init *BitsRecTy::convertValue(IntInit *II) {
|
|
int64_t Value = II->getValue();
|
|
// Make sure this bitfield is large enough to hold the integer value.
|
|
if (!canFitInBitfield(Value, Size))
|
|
return 0;
|
|
|
|
BitsInit *Ret = new BitsInit(Size);
|
|
for (unsigned i = 0; i != Size; ++i)
|
|
Ret->setBit(i, new BitInit(Value & (1LL << i)));
|
|
|
|
return Ret;
|
|
}
|
|
|
|
Init *BitsRecTy::convertValue(BitsInit *BI) {
|
|
// If the number of bits is right, return it. Otherwise we need to expand or
|
|
// truncate.
|
|
if (BI->getNumBits() == Size) return BI;
|
|
return 0;
|
|
}
|
|
|
|
Init *BitsRecTy::convertValue(TypedInit *VI) {
|
|
if (BitsRecTy *BRT = dynamic_cast<BitsRecTy*>(VI->getType()))
|
|
if (BRT->Size == Size) {
|
|
BitsInit *Ret = new BitsInit(Size);
|
|
for (unsigned i = 0; i != Size; ++i)
|
|
Ret->setBit(i, new VarBitInit(VI, i));
|
|
return Ret;
|
|
}
|
|
|
|
if (Size == 1 && dynamic_cast<BitRecTy*>(VI->getType())) {
|
|
BitsInit *Ret = new BitsInit(1);
|
|
Ret->setBit(0, VI);
|
|
return Ret;
|
|
}
|
|
|
|
if (TernOpInit *Tern = dynamic_cast<TernOpInit*>(VI)) {
|
|
if (Tern->getOpcode() == TernOpInit::IF) {
|
|
Init *LHS = Tern->getLHS();
|
|
Init *MHS = Tern->getMHS();
|
|
Init *RHS = Tern->getRHS();
|
|
|
|
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)) {
|
|
BitsInit *Ret = new BitsInit(Size);
|
|
|
|
for (unsigned i = 0; i != Size; ++i)
|
|
Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
|
|
new IntInit((MHSVal & (1LL << i)) ? 1 : 0),
|
|
new IntInit((RHSVal & (1LL << i)) ? 1 : 0),
|
|
VI->getType()));
|
|
|
|
return Ret;
|
|
}
|
|
} else {
|
|
BitsInit *MHSbs = dynamic_cast<BitsInit*>(MHS);
|
|
BitsInit *RHSbs = dynamic_cast<BitsInit*>(RHS);
|
|
|
|
if (MHSbs && RHSbs) {
|
|
BitsInit *Ret = new BitsInit(Size);
|
|
|
|
for (unsigned i = 0; i != Size; ++i)
|
|
Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS,
|
|
MHSbs->getBit(i),
|
|
RHSbs->getBit(i),
|
|
VI->getType()));
|
|
|
|
return Ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Init *IntRecTy::convertValue(BitInit *BI) {
|
|
return new IntInit(BI->getValue());
|
|
}
|
|
|
|
Init *IntRecTy::convertValue(BitsInit *BI) {
|
|
int64_t Result = 0;
|
|
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
|
|
if (BitInit *Bit = dynamic_cast<BitInit*>(BI->getBit(i))) {
|
|
Result |= Bit->getValue() << i;
|
|
} else {
|
|
return 0;
|
|
}
|
|
return new IntInit(Result);
|
|
}
|
|
|
|
Init *IntRecTy::convertValue(TypedInit *TI) {
|
|
if (TI->getType()->typeIsConvertibleTo(this))
|
|
return TI; // Accept variable if already of the right type!
|
|
return 0;
|
|
}
|
|
|
|
Init *StringRecTy::convertValue(UnOpInit *BO) {
|
|
if (BO->getOpcode() == UnOpInit::CAST) {
|
|
Init *L = BO->getOperand()->convertInitializerTo(this);
|
|
if (L == 0) return 0;
|
|
if (L != BO->getOperand())
|
|
return new UnOpInit(UnOpInit::CAST, L, new StringRecTy);
|
|
return BO;
|
|
}
|
|
|
|
return convertValue((TypedInit*)BO);
|
|
}
|
|
|
|
Init *StringRecTy::convertValue(BinOpInit *BO) {
|
|
if (BO->getOpcode() == BinOpInit::STRCONCAT) {
|
|
Init *L = BO->getLHS()->convertInitializerTo(this);
|
|
Init *R = BO->getRHS()->convertInitializerTo(this);
|
|
if (L == 0 || R == 0) return 0;
|
|
if (L != BO->getLHS() || R != BO->getRHS())
|
|
return new BinOpInit(BinOpInit::STRCONCAT, L, R, new StringRecTy);
|
|
return BO;
|
|
}
|
|
|
|
return convertValue((TypedInit*)BO);
|
|
}
|
|
|
|
|
|
Init *StringRecTy::convertValue(TypedInit *TI) {
|
|
if (dynamic_cast<StringRecTy*>(TI->getType()))
|
|
return TI; // Accept variable if already of the right type!
|
|
return 0;
|
|
}
|
|
|
|
std::string ListRecTy::getAsString() const {
|
|
return "list<" + Ty->getAsString() + ">";
|
|
}
|
|
|
|
Init *ListRecTy::convertValue(ListInit *LI) {
|
|
std::vector<Init*> Elements;
|
|
|
|
// Verify that all of the elements of the list are subclasses of the
|
|
// appropriate class!
|
|
for (unsigned i = 0, e = LI->getSize(); i != e; ++i)
|
|
if (Init *CI = LI->getElement(i)->convertInitializerTo(Ty))
|
|
Elements.push_back(CI);
|
|
else
|
|
return 0;
|
|
|
|
ListRecTy *LType = dynamic_cast<ListRecTy*>(LI->getType());
|
|
if (LType == 0) {
|
|
return 0;
|
|
}
|
|
|
|
return new ListInit(Elements, this);
|
|
}
|
|
|
|
Init *ListRecTy::convertValue(TypedInit *TI) {
|
|
// Ensure that TI is compatible with our class.
|
|
if (ListRecTy *LRT = dynamic_cast<ListRecTy*>(TI->getType()))
|
|
if (LRT->getElementType()->typeIsConvertibleTo(getElementType()))
|
|
return TI;
|
|
return 0;
|
|
}
|
|
|
|
Init *CodeRecTy::convertValue(TypedInit *TI) {
|
|
if (TI->getType()->typeIsConvertibleTo(this))
|
|
return TI;
|
|
return 0;
|
|
}
|
|
|
|
Init *DagRecTy::convertValue(TypedInit *TI) {
|
|
if (TI->getType()->typeIsConvertibleTo(this))
|
|
return TI;
|
|
return 0;
|
|
}
|
|
|
|
Init *DagRecTy::convertValue(UnOpInit *BO) {
|
|
if (BO->getOpcode() == UnOpInit::CAST) {
|
|
Init *L = BO->getOperand()->convertInitializerTo(this);
|
|
if (L == 0) return 0;
|
|
if (L != BO->getOperand())
|
|
return new UnOpInit(UnOpInit::CAST, L, new DagRecTy);
|
|
return BO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Init *DagRecTy::convertValue(BinOpInit *BO) {
|
|
if (BO->getOpcode() == BinOpInit::CONCAT) {
|
|
Init *L = BO->getLHS()->convertInitializerTo(this);
|
|
Init *R = BO->getRHS()->convertInitializerTo(this);
|
|
if (L == 0 || R == 0) return 0;
|
|
if (L != BO->getLHS() || R != BO->getRHS())
|
|
return new BinOpInit(BinOpInit::CONCAT, L, R, new DagRecTy);
|
|
return BO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
RecordRecTy *RecordRecTy::get(Record *R) {
|
|
return &dynamic_cast<RecordRecTy&>(*R->getDefInit()->getType());
|
|
}
|
|
|
|
std::string RecordRecTy::getAsString() const {
|
|
return Rec->getName();
|
|
}
|
|
|
|
Init *RecordRecTy::convertValue(DefInit *DI) {
|
|
// Ensure that DI is a subclass of Rec.
|
|
if (!DI->getDef()->isSubClassOf(Rec))
|
|
return 0;
|
|
return DI;
|
|
}
|
|
|
|
Init *RecordRecTy::convertValue(TypedInit *TI) {
|
|
// Ensure that TI is compatible with Rec.
|
|
if (RecordRecTy *RRT = dynamic_cast<RecordRecTy*>(TI->getType()))
|
|
if (RRT->getRecord()->isSubClassOf(getRecord()) ||
|
|
RRT->getRecord() == getRecord())
|
|
return TI;
|
|
return 0;
|
|
}
|
|
|
|
bool RecordRecTy::baseClassOf(const RecordRecTy *RHS) const {
|
|
if (Rec == RHS->getRecord() || RHS->getRecord()->isSubClassOf(Rec))
|
|
return true;
|
|
|
|
const std::vector<Record*> &SC = Rec->getSuperClasses();
|
|
for (unsigned i = 0, e = SC.size(); i != e; ++i)
|
|
if (RHS->getRecord()->isSubClassOf(SC[i]))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/// resolveTypes - Find a common type that T1 and T2 convert to.
|
|
/// Return 0 if no such type exists.
|
|
///
|
|
RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) {
|
|
if (!T1->typeIsConvertibleTo(T2)) {
|
|
if (!T2->typeIsConvertibleTo(T1)) {
|
|
// If one is a Record type, check superclasses
|
|
RecordRecTy *RecTy1 = dynamic_cast<RecordRecTy*>(T1);
|
|
if (RecTy1) {
|
|
// See if T2 inherits from a type T1 also inherits from
|
|
const std::vector<Record *> &T1SuperClasses =
|
|
RecTy1->getRecord()->getSuperClasses();
|
|
for(std::vector<Record *>::const_iterator i = T1SuperClasses.begin(),
|
|
iend = T1SuperClasses.end();
|
|
i != iend;
|
|
++i) {
|
|
RecordRecTy *SuperRecTy1 = RecordRecTy::get(*i);
|
|
RecTy *NewType1 = resolveTypes(SuperRecTy1, T2);
|
|
if (NewType1 != 0) {
|
|
if (NewType1 != SuperRecTy1) {
|
|
delete SuperRecTy1;
|
|
}
|
|
return NewType1;
|
|
}
|
|
}
|
|
}
|
|
RecordRecTy *RecTy2 = dynamic_cast<RecordRecTy*>(T2);
|
|
if (RecTy2) {
|
|
// See if T1 inherits from a type T2 also inherits from
|
|
const std::vector<Record *> &T2SuperClasses =
|
|
RecTy2->getRecord()->getSuperClasses();
|
|
for (std::vector<Record *>::const_iterator i = T2SuperClasses.begin(),
|
|
iend = T2SuperClasses.end();
|
|
i != iend;
|
|
++i) {
|
|
RecordRecTy *SuperRecTy2 = RecordRecTy::get(*i);
|
|
RecTy *NewType2 = resolveTypes(T1, SuperRecTy2);
|
|
if (NewType2 != 0) {
|
|
if (NewType2 != SuperRecTy2) {
|
|
delete SuperRecTy2;
|
|
}
|
|
return NewType2;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
return T2;
|
|
}
|
|
return T1;
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Initializer implementations
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void Init::dump() const { return print(errs()); }
|
|
|
|
Init *BitsInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
|
|
BitsInit *BI = new BitsInit(Bits.size());
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
|
if (Bits[i] >= getNumBits()) {
|
|
delete BI;
|
|
return 0;
|
|
}
|
|
BI->setBit(i, getBit(Bits[i]));
|
|
}
|
|
return BI;
|
|
}
|
|
|
|
std::string BitsInit::getAsString() const {
|
|
std::string Result = "{ ";
|
|
for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
|
|
if (i) Result += ", ";
|
|
if (Init *Bit = getBit(e-i-1))
|
|
Result += Bit->getAsString();
|
|
else
|
|
Result += "*";
|
|
}
|
|
return Result + " }";
|
|
}
|
|
|
|
// resolveReferences - If there are any field references that refer to fields
|
|
// that have been filled in, we can propagate the values now.
|
|
//
|
|
Init *BitsInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
bool Changed = false;
|
|
BitsInit *New = new BitsInit(getNumBits());
|
|
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
|
Init *B;
|
|
Init *CurBit = getBit(i);
|
|
|
|
do {
|
|
B = CurBit;
|
|
CurBit = CurBit->resolveReferences(R, RV);
|
|
Changed |= B != CurBit;
|
|
} while (B != CurBit);
|
|
New->setBit(i, CurBit);
|
|
}
|
|
|
|
if (Changed)
|
|
return New;
|
|
delete New;
|
|
return this;
|
|
}
|
|
|
|
std::string IntInit::getAsString() const {
|
|
return itostr(Value);
|
|
}
|
|
|
|
Init *IntInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
|
|
BitsInit *BI = new BitsInit(Bits.size());
|
|
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
|
if (Bits[i] >= 64) {
|
|
delete BI;
|
|
return 0;
|
|
}
|
|
BI->setBit(i, new BitInit(Value & (INT64_C(1) << Bits[i])));
|
|
}
|
|
return BI;
|
|
}
|
|
|
|
Init *ListInit::convertInitListSlice(const std::vector<unsigned> &Elements) {
|
|
std::vector<Init*> Vals;
|
|
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
|
|
if (Elements[i] >= getSize())
|
|
return 0;
|
|
Vals.push_back(getElement(Elements[i]));
|
|
}
|
|
return new ListInit(Vals, getType());
|
|
}
|
|
|
|
Record *ListInit::getElementAsRecord(unsigned i) const {
|
|
assert(i < Values.size() && "List element index out of range!");
|
|
DefInit *DI = dynamic_cast<DefInit*>(Values[i]);
|
|
if (DI == 0) throw "Expected record in list!";
|
|
return DI->getDef();
|
|
}
|
|
|
|
Init *ListInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
std::vector<Init*> Resolved;
|
|
Resolved.reserve(getSize());
|
|
bool Changed = false;
|
|
|
|
for (unsigned i = 0, e = getSize(); i != e; ++i) {
|
|
Init *E;
|
|
Init *CurElt = getElement(i);
|
|
|
|
do {
|
|
E = CurElt;
|
|
CurElt = CurElt->resolveReferences(R, RV);
|
|
Changed |= E != CurElt;
|
|
} while (E != CurElt);
|
|
Resolved.push_back(E);
|
|
}
|
|
|
|
if (Changed)
|
|
return new ListInit(Resolved, getType());
|
|
return this;
|
|
}
|
|
|
|
Init *ListInit::resolveListElementReference(Record &R, const RecordVal *IRV,
|
|
unsigned Elt) {
|
|
if (Elt >= getSize())
|
|
return 0; // Out of range reference.
|
|
Init *E = getElement(Elt);
|
|
// If the element 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 VarListElementInit with it.
|
|
if (IRV || !dynamic_cast<UnsetInit*>(E))
|
|
return E;
|
|
return 0;
|
|
}
|
|
|
|
std::string ListInit::getAsString() const {
|
|
std::string Result = "[";
|
|
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
|
|
if (i) Result += ", ";
|
|
Result += Values[i]->getAsString();
|
|
}
|
|
return Result + "]";
|
|
}
|
|
|
|
Init *OpInit::resolveBitReference(Record &R, const RecordVal *IRV,
|
|
unsigned Bit) {
|
|
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) {
|
|
Init *Folded = Fold(&R, 0);
|
|
|
|
if (Folded != this) {
|
|
TypedInit *Typed = dynamic_cast<TypedInit *>(Folded);
|
|
if (Typed) {
|
|
return Typed->resolveListElementReference(R, IRV, Elt);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
|
|
switch (getOpcode()) {
|
|
default: assert(0 && "Unknown unop");
|
|
case CAST: {
|
|
if (getType()->getAsString() == "string") {
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
if (LHSs) {
|
|
return LHSs;
|
|
}
|
|
|
|
DefInit *LHSd = dynamic_cast<DefInit*>(LHS);
|
|
if (LHSd) {
|
|
return new StringInit(LHSd->getDef()->getName());
|
|
}
|
|
} else {
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
if (LHSs) {
|
|
std::string Name = LHSs->getValue();
|
|
|
|
// From TGParser::ParseIDValue
|
|
if (CurRec) {
|
|
if (const RecordVal *RV = CurRec->getValue(Name)) {
|
|
if (RV->getType() != getType())
|
|
throw "type mismatch in cast";
|
|
return new VarInit(Name, RV->getType());
|
|
}
|
|
|
|
std::string TemplateArgName = CurRec->getName()+":"+Name;
|
|
if (CurRec->isTemplateArg(TemplateArgName)) {
|
|
const RecordVal *RV = CurRec->getValue(TemplateArgName);
|
|
assert(RV && "Template arg doesn't exist??");
|
|
|
|
if (RV->getType() != getType())
|
|
throw "type mismatch in cast";
|
|
|
|
return new VarInit(TemplateArgName, RV->getType());
|
|
}
|
|
}
|
|
|
|
if (CurMultiClass) {
|
|
std::string MCName = CurMultiClass->Rec.getName()+"::"+Name;
|
|
if (CurMultiClass->Rec.isTemplateArg(MCName)) {
|
|
const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
|
|
assert(RV && "Template arg doesn't exist??");
|
|
|
|
if (RV->getType() != getType())
|
|
throw "type mismatch in cast";
|
|
|
|
return new VarInit(MCName, RV->getType());
|
|
}
|
|
}
|
|
|
|
if (Record *D = (CurRec->getRecords()).getDef(Name))
|
|
return DefInit::get(D);
|
|
|
|
throw TGError(CurRec->getLoc(), "Undefined reference:'" + Name + "'\n");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case HEAD: {
|
|
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
|
|
if (LHSl) {
|
|
if (LHSl->getSize() == 0) {
|
|
assert(0 && "Empty list in car");
|
|
return 0;
|
|
}
|
|
return LHSl->getElement(0);
|
|
}
|
|
break;
|
|
}
|
|
case TAIL: {
|
|
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
|
|
if (LHSl) {
|
|
if (LHSl->getSize() == 0) {
|
|
assert(0 && "Empty list in cdr");
|
|
return 0;
|
|
}
|
|
ListInit *Result = new ListInit(LHSl->begin()+1, LHSl->end(),
|
|
LHSl->getType());
|
|
return Result;
|
|
}
|
|
break;
|
|
}
|
|
case EMPTY: {
|
|
ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
|
|
if (LHSl) {
|
|
if (LHSl->getSize() == 0) {
|
|
return new IntInit(1);
|
|
} else {
|
|
return new IntInit(0);
|
|
}
|
|
}
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
if (LHSs) {
|
|
if (LHSs->getValue().empty()) {
|
|
return new IntInit(1);
|
|
} else {
|
|
return new IntInit(0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Init *UnOpInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
Init *lhs = LHS->resolveReferences(R, RV);
|
|
|
|
if (LHS != lhs)
|
|
return (new UnOpInit(getOpcode(), lhs, getType()))->Fold(&R, 0);
|
|
return Fold(&R, 0);
|
|
}
|
|
|
|
std::string UnOpInit::getAsString() const {
|
|
std::string Result;
|
|
switch (Opc) {
|
|
case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break;
|
|
case HEAD: Result = "!head"; break;
|
|
case TAIL: Result = "!tail"; break;
|
|
case EMPTY: Result = "!empty"; break;
|
|
}
|
|
return Result + "(" + LHS->getAsString() + ")";
|
|
}
|
|
|
|
Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
|
|
switch (getOpcode()) {
|
|
default: assert(0 && "Unknown binop");
|
|
case CONCAT: {
|
|
DagInit *LHSs = dynamic_cast<DagInit*>(LHS);
|
|
DagInit *RHSs = dynamic_cast<DagInit*>(RHS);
|
|
if (LHSs && RHSs) {
|
|
DefInit *LOp = dynamic_cast<DefInit*>(LHSs->getOperator());
|
|
DefInit *ROp = dynamic_cast<DefInit*>(RHSs->getOperator());
|
|
if (LOp == 0 || ROp == 0 || LOp->getDef() != ROp->getDef())
|
|
throw "Concated Dag operators do not match!";
|
|
std::vector<Init*> Args;
|
|
std::vector<std::string> ArgNames;
|
|
for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) {
|
|
Args.push_back(LHSs->getArg(i));
|
|
ArgNames.push_back(LHSs->getArgName(i));
|
|
}
|
|
for (unsigned i = 0, e = RHSs->getNumArgs(); i != e; ++i) {
|
|
Args.push_back(RHSs->getArg(i));
|
|
ArgNames.push_back(RHSs->getArgName(i));
|
|
}
|
|
return new DagInit(LHSs->getOperator(), "", Args, ArgNames);
|
|
}
|
|
break;
|
|
}
|
|
case STRCONCAT: {
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
|
|
if (LHSs && RHSs)
|
|
return new StringInit(LHSs->getValue() + RHSs->getValue());
|
|
break;
|
|
}
|
|
case EQ: {
|
|
// try to fold eq comparison for 'bit' and 'int', otherwise fallback
|
|
// to string objects.
|
|
IntInit* L =
|
|
dynamic_cast<IntInit*>(LHS->convertInitializerTo(IntRecTy::get()));
|
|
IntInit* R =
|
|
dynamic_cast<IntInit*>(RHS->convertInitializerTo(IntRecTy::get()));
|
|
|
|
if (L && R)
|
|
return new IntInit(L->getValue() == R->getValue());
|
|
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
|
|
|
|
// Make sure we've resolved
|
|
if (LHSs && RHSs)
|
|
return new IntInit(LHSs->getValue() == RHSs->getValue());
|
|
|
|
break;
|
|
}
|
|
case SHL:
|
|
case SRA:
|
|
case SRL: {
|
|
IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
|
|
IntInit *RHSi = dynamic_cast<IntInit*>(RHS);
|
|
if (LHSi && RHSi) {
|
|
int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
|
|
int64_t Result;
|
|
switch (getOpcode()) {
|
|
default: assert(0 && "Bad opcode!");
|
|
case SHL: Result = LHSv << RHSv; break;
|
|
case SRA: Result = LHSv >> RHSv; break;
|
|
case SRL: Result = (uint64_t)LHSv >> (uint64_t)RHSv; break;
|
|
}
|
|
return new IntInit(Result);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Init *BinOpInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
Init *lhs = LHS->resolveReferences(R, RV);
|
|
Init *rhs = RHS->resolveReferences(R, RV);
|
|
|
|
if (LHS != lhs || RHS != rhs)
|
|
return (new BinOpInit(getOpcode(), lhs, rhs, getType()))->Fold(&R, 0);
|
|
return Fold(&R, 0);
|
|
}
|
|
|
|
std::string BinOpInit::getAsString() const {
|
|
std::string Result;
|
|
switch (Opc) {
|
|
case CONCAT: Result = "!con"; break;
|
|
case SHL: Result = "!shl"; break;
|
|
case SRA: Result = "!sra"; break;
|
|
case SRL: Result = "!srl"; break;
|
|
case EQ: Result = "!eq"; break;
|
|
case STRCONCAT: Result = "!strconcat"; break;
|
|
}
|
|
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
|
|
}
|
|
|
|
static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
|
|
Record *CurRec, MultiClass *CurMultiClass);
|
|
|
|
static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg,
|
|
RecTy *Type, Record *CurRec,
|
|
MultiClass *CurMultiClass) {
|
|
std::vector<Init *> NewOperands;
|
|
|
|
TypedInit *TArg = dynamic_cast<TypedInit*>(Arg);
|
|
|
|
// If this is a dag, recurse
|
|
if (TArg && TArg->getType()->getAsString() == "dag") {
|
|
Init *Result = ForeachHelper(LHS, Arg, RHSo, Type,
|
|
CurRec, CurMultiClass);
|
|
if (Result != 0) {
|
|
return Result;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < RHSo->getNumOperands(); ++i) {
|
|
OpInit *RHSoo = dynamic_cast<OpInit*>(RHSo->getOperand(i));
|
|
|
|
if (RHSoo) {
|
|
Init *Result = EvaluateOperation(RHSoo, LHS, Arg,
|
|
Type, CurRec, CurMultiClass);
|
|
if (Result != 0) {
|
|
NewOperands.push_back(Result);
|
|
} else {
|
|
NewOperands.push_back(Arg);
|
|
}
|
|
} else if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
|
|
NewOperands.push_back(Arg);
|
|
} else {
|
|
NewOperands.push_back(RHSo->getOperand(i));
|
|
}
|
|
}
|
|
|
|
// Now run the operator and use its result as the new leaf
|
|
OpInit *NewOp = RHSo->clone(NewOperands);
|
|
Init *NewVal = NewOp->Fold(CurRec, CurMultiClass);
|
|
if (NewVal != NewOp) {
|
|
delete NewOp;
|
|
return NewVal;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
|
|
Record *CurRec, MultiClass *CurMultiClass) {
|
|
DagInit *MHSd = dynamic_cast<DagInit*>(MHS);
|
|
ListInit *MHSl = dynamic_cast<ListInit*>(MHS);
|
|
|
|
DagRecTy *DagType = dynamic_cast<DagRecTy*>(Type);
|
|
ListRecTy *ListType = dynamic_cast<ListRecTy*>(Type);
|
|
|
|
OpInit *RHSo = dynamic_cast<OpInit*>(RHS);
|
|
|
|
if (!RHSo) {
|
|
throw TGError(CurRec->getLoc(), "!foreach requires an operator\n");
|
|
}
|
|
|
|
TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
|
|
|
|
if (!LHSt) {
|
|
throw TGError(CurRec->getLoc(), "!foreach requires typed variable\n");
|
|
}
|
|
|
|
if ((MHSd && DagType) || (MHSl && ListType)) {
|
|
if (MHSd) {
|
|
Init *Val = MHSd->getOperator();
|
|
Init *Result = EvaluateOperation(RHSo, LHS, Val,
|
|
Type, CurRec, CurMultiClass);
|
|
if (Result != 0) {
|
|
Val = Result;
|
|
}
|
|
|
|
std::vector<std::pair<Init *, std::string> > args;
|
|
for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) {
|
|
Init *Arg;
|
|
std::string ArgName;
|
|
Arg = MHSd->getArg(i);
|
|
ArgName = MHSd->getArgName(i);
|
|
|
|
// Process args
|
|
Init *Result = EvaluateOperation(RHSo, LHS, Arg, Type,
|
|
CurRec, CurMultiClass);
|
|
if (Result != 0) {
|
|
Arg = Result;
|
|
}
|
|
|
|
// TODO: Process arg names
|
|
args.push_back(std::make_pair(Arg, ArgName));
|
|
}
|
|
|
|
return new DagInit(Val, "", args);
|
|
}
|
|
if (MHSl) {
|
|
std::vector<Init *> NewOperands;
|
|
std::vector<Init *> NewList(MHSl->begin(), MHSl->end());
|
|
|
|
for (ListInit::iterator li = NewList.begin(),
|
|
liend = NewList.end();
|
|
li != liend;
|
|
++li) {
|
|
Init *Item = *li;
|
|
NewOperands.clear();
|
|
for(int i = 0; i < RHSo->getNumOperands(); ++i) {
|
|
// First, replace the foreach variable with the list item
|
|
if (LHS->getAsString() == RHSo->getOperand(i)->getAsString()) {
|
|
NewOperands.push_back(Item);
|
|
} else {
|
|
NewOperands.push_back(RHSo->getOperand(i));
|
|
}
|
|
}
|
|
|
|
// Now run the operator and use its result as the new list item
|
|
OpInit *NewOp = RHSo->clone(NewOperands);
|
|
Init *NewItem = NewOp->Fold(CurRec, CurMultiClass);
|
|
if (NewItem != NewOp) {
|
|
*li = NewItem;
|
|
delete NewOp;
|
|
}
|
|
}
|
|
return new ListInit(NewList, MHSl->getType());
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
|
|
switch (getOpcode()) {
|
|
default: assert(0 && "Unknown binop");
|
|
case SUBST: {
|
|
DefInit *LHSd = dynamic_cast<DefInit*>(LHS);
|
|
VarInit *LHSv = dynamic_cast<VarInit*>(LHS);
|
|
StringInit *LHSs = dynamic_cast<StringInit*>(LHS);
|
|
|
|
DefInit *MHSd = dynamic_cast<DefInit*>(MHS);
|
|
VarInit *MHSv = dynamic_cast<VarInit*>(MHS);
|
|
StringInit *MHSs = dynamic_cast<StringInit*>(MHS);
|
|
|
|
DefInit *RHSd = dynamic_cast<DefInit*>(RHS);
|
|
VarInit *RHSv = dynamic_cast<VarInit*>(RHS);
|
|
StringInit *RHSs = dynamic_cast<StringInit*>(RHS);
|
|
|
|
if ((LHSd && MHSd && RHSd)
|
|
|| (LHSv && MHSv && RHSv)
|
|
|| (LHSs && MHSs && RHSs)) {
|
|
if (RHSd) {
|
|
Record *Val = RHSd->getDef();
|
|
if (LHSd->getAsString() == RHSd->getAsString()) {
|
|
Val = MHSd->getDef();
|
|
}
|
|
return DefInit::get(Val);
|
|
}
|
|
if (RHSv) {
|
|
std::string Val = RHSv->getName();
|
|
if (LHSv->getAsString() == RHSv->getAsString()) {
|
|
Val = MHSv->getName();
|
|
}
|
|
return new VarInit(Val, getType());
|
|
}
|
|
if (RHSs) {
|
|
std::string Val = RHSs->getValue();
|
|
|
|
std::string::size_type found;
|
|
std::string::size_type idx = 0;
|
|
do {
|
|
found = Val.find(LHSs->getValue(), idx);
|
|
if (found != std::string::npos) {
|
|
Val.replace(found, LHSs->getValue().size(), MHSs->getValue());
|
|
}
|
|
idx = found + MHSs->getValue().size();
|
|
} while (found != std::string::npos);
|
|
|
|
return new StringInit(Val);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FOREACH: {
|
|
Init *Result = ForeachHelper(LHS, MHS, RHS, getType(),
|
|
CurRec, CurMultiClass);
|
|
if (Result != 0) {
|
|
return Result;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IF: {
|
|
IntInit *LHSi = dynamic_cast<IntInit*>(LHS);
|
|
if (Init *I = LHS->convertInitializerTo(IntRecTy::get()))
|
|
LHSi = dynamic_cast<IntInit*>(I);
|
|
if (LHSi) {
|
|
if (LHSi->getValue()) {
|
|
return MHS;
|
|
} else {
|
|
return RHS;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
Init *TernOpInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
Init *lhs = LHS->resolveReferences(R, RV);
|
|
|
|
if (Opc == IF && lhs != LHS) {
|
|
IntInit *Value = dynamic_cast<IntInit*>(lhs);
|
|
if (Init *I = lhs->convertInitializerTo(IntRecTy::get()))
|
|
Value = dynamic_cast<IntInit*>(I);
|
|
if (Value != 0) {
|
|
// Short-circuit
|
|
if (Value->getValue()) {
|
|
Init *mhs = MHS->resolveReferences(R, RV);
|
|
return (new TernOpInit(getOpcode(), lhs, mhs,
|
|
RHS, getType()))->Fold(&R, 0);
|
|
} else {
|
|
Init *rhs = RHS->resolveReferences(R, RV);
|
|
return (new TernOpInit(getOpcode(), lhs, MHS,
|
|
rhs, getType()))->Fold(&R, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
Init *mhs = MHS->resolveReferences(R, RV);
|
|
Init *rhs = RHS->resolveReferences(R, RV);
|
|
|
|
if (LHS != lhs || MHS != mhs || RHS != rhs)
|
|
return (new TernOpInit(getOpcode(), lhs, mhs, rhs, getType()))->Fold(&R, 0);
|
|
return Fold(&R, 0);
|
|
}
|
|
|
|
std::string TernOpInit::getAsString() const {
|
|
std::string Result;
|
|
switch (Opc) {
|
|
case SUBST: Result = "!subst"; break;
|
|
case FOREACH: Result = "!foreach"; break;
|
|
case IF: Result = "!if"; break;
|
|
}
|
|
return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", "
|
|
+ RHS->getAsString() + ")";
|
|
}
|
|
|
|
RecTy *TypedInit::getFieldType(const std::string &FieldName) const {
|
|
RecordRecTy *RecordType = dynamic_cast<RecordRecTy *>(getType());
|
|
if (RecordType) {
|
|
RecordVal *Field = RecordType->getRecord()->getValue(FieldName);
|
|
if (Field) {
|
|
return Field->getType();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Init *TypedInit::convertInitializerBitRange(const std::vector<unsigned> &Bits) {
|
|
BitsRecTy *T = dynamic_cast<BitsRecTy*>(getType());
|
|
if (T == 0) return 0; // Cannot subscript a non-bits variable.
|
|
unsigned NumBits = T->getNumBits();
|
|
|
|
BitsInit *BI = new BitsInit(Bits.size());
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
|
if (Bits[i] >= NumBits) {
|
|
delete BI;
|
|
return 0;
|
|
}
|
|
BI->setBit(i, new VarBitInit(this, Bits[i]));
|
|
}
|
|
return BI;
|
|
}
|
|
|
|
Init *TypedInit::convertInitListSlice(const std::vector<unsigned> &Elements) {
|
|
ListRecTy *T = dynamic_cast<ListRecTy*>(getType());
|
|
if (T == 0) return 0; // Cannot subscript a non-list variable.
|
|
|
|
if (Elements.size() == 1)
|
|
return new VarListElementInit(this, Elements[0]);
|
|
|
|
std::vector<Init*> ListInits;
|
|
ListInits.reserve(Elements.size());
|
|
for (unsigned i = 0, e = Elements.size(); i != e; ++i)
|
|
ListInits.push_back(new VarListElementInit(this, Elements[i]));
|
|
return new ListInit(ListInits, T);
|
|
}
|
|
|
|
|
|
Init *VarInit::resolveBitReference(Record &R, const RecordVal *IRV,
|
|
unsigned Bit) {
|
|
if (R.isTemplateArg(getName())) return 0;
|
|
if (IRV && IRV->getName() != getName()) return 0;
|
|
|
|
RecordVal *RV = R.getValue(getName());
|
|
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::resolveListElementReference(Record &R, const RecordVal *IRV,
|
|
unsigned Elt) {
|
|
if (R.isTemplateArg(getName())) return 0;
|
|
if (IRV && IRV->getName() != getName()) return 0;
|
|
|
|
RecordVal *RV = R.getValue(getName());
|
|
assert(RV && "Reference to a non-existent variable?");
|
|
ListInit *LI = dynamic_cast<ListInit*>(RV->getValue());
|
|
if (!LI) {
|
|
VarInit *VI = dynamic_cast<VarInit*>(RV->getValue());
|
|
assert(VI && "Invalid list element!");
|
|
return new VarListElementInit(VI, Elt);
|
|
}
|
|
|
|
if (Elt >= LI->getSize())
|
|
return 0; // Out of range reference.
|
|
Init *E = LI->getElement(Elt);
|
|
// If the element 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 VarListElementInit with it.
|
|
if (IRV || !dynamic_cast<UnsetInit*>(E))
|
|
return E;
|
|
return 0;
|
|
}
|
|
|
|
|
|
RecTy *VarInit::getFieldType(const std::string &FieldName) const {
|
|
if (RecordRecTy *RTy = dynamic_cast<RecordRecTy*>(getType()))
|
|
if (const RecordVal *RV = RTy->getRecord()->getValue(FieldName))
|
|
return RV->getType();
|
|
return 0;
|
|
}
|
|
|
|
Init *VarInit::getFieldInit(Record &R, const RecordVal *RV,
|
|
const std::string &FieldName) const {
|
|
if (dynamic_cast<RecordRecTy*>(getType()))
|
|
if (const RecordVal *Val = R.getValue(VarName)) {
|
|
if (RV != Val && (RV || dynamic_cast<UnsetInit*>(Val->getValue())))
|
|
return 0;
|
|
Init *TheInit = Val->getValue();
|
|
assert(TheInit != this && "Infinite loop detected!");
|
|
if (Init *I = TheInit->getFieldInit(R, RV, FieldName))
|
|
return I;
|
|
else
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/// resolveReferences - This method is used by classes that refer to other
|
|
/// variables which may not be defined at the time the expression is formed.
|
|
/// If a value is set for the variable later, this method will be called on
|
|
/// users of the value to allow the value to propagate out.
|
|
///
|
|
Init *VarInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
if (RecordVal *Val = R.getValue(VarName))
|
|
if (RV == Val || (RV == 0 && !dynamic_cast<UnsetInit*>(Val->getValue())))
|
|
return Val->getValue();
|
|
return this;
|
|
}
|
|
|
|
std::string VarBitInit::getAsString() const {
|
|
return TI->getAsString() + "{" + utostr(Bit) + "}";
|
|
}
|
|
|
|
Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
if (Init *I = getVariable()->resolveBitReference(R, RV, getBitNum()))
|
|
return I;
|
|
return this;
|
|
}
|
|
|
|
std::string VarListElementInit::getAsString() const {
|
|
return TI->getAsString() + "[" + utostr(Element) + "]";
|
|
}
|
|
|
|
Init *VarListElementInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
if (Init *I = getVariable()->resolveListElementReference(R, RV,
|
|
getElementNum()))
|
|
return I;
|
|
return this;
|
|
}
|
|
|
|
Init *VarListElementInit::resolveBitReference(Record &R, const RecordVal *RV,
|
|
unsigned Bit) {
|
|
// FIXME: This should be implemented, to support references like:
|
|
// bit B = AA[0]{1};
|
|
return 0;
|
|
}
|
|
|
|
Init *VarListElementInit::
|
|
resolveListElementReference(Record &R, const RecordVal *RV, unsigned Elt) {
|
|
// FIXME: This should be implemented, to support references like:
|
|
// int B = AA[0][1];
|
|
return 0;
|
|
}
|
|
|
|
DefInit *DefInit::get(Record *R) {
|
|
return R->getDefInit();
|
|
}
|
|
|
|
RecTy *DefInit::getFieldType(const std::string &FieldName) const {
|
|
if (const RecordVal *RV = Def->getValue(FieldName))
|
|
return RV->getType();
|
|
return 0;
|
|
}
|
|
|
|
Init *DefInit::getFieldInit(Record &R, const RecordVal *RV,
|
|
const std::string &FieldName) const {
|
|
return Def->getValue(FieldName)->getValue();
|
|
}
|
|
|
|
|
|
std::string DefInit::getAsString() const {
|
|
return Def->getName();
|
|
}
|
|
|
|
Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV,
|
|
unsigned Bit) {
|
|
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::resolveListElementReference(Record &R, const RecordVal *RV,
|
|
unsigned Elt) {
|
|
if (Init *ListVal = Rec->getFieldInit(R, RV, FieldName))
|
|
if (ListInit *LI = dynamic_cast<ListInit*>(ListVal)) {
|
|
if (Elt >= LI->getSize()) return 0;
|
|
Init *E = LI->getElement(Elt);
|
|
|
|
// If the element 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 VarListElementInit with it.
|
|
if (RV || !dynamic_cast<UnsetInit*>(E))
|
|
return E;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Init *FieldInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
Init *NewRec = RV ? Rec->resolveReferences(R, RV) : Rec;
|
|
|
|
Init *BitsVal = NewRec->getFieldInit(R, RV, FieldName);
|
|
if (BitsVal) {
|
|
Init *BVR = BitsVal->resolveReferences(R, RV);
|
|
return BVR->isComplete() ? BVR : this;
|
|
}
|
|
|
|
if (NewRec != Rec) {
|
|
return new FieldInit(NewRec, FieldName);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Init *DagInit::resolveReferences(Record &R, const RecordVal *RV) {
|
|
std::vector<Init*> NewArgs;
|
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
|
NewArgs.push_back(Args[i]->resolveReferences(R, RV));
|
|
|
|
Init *Op = Val->resolveReferences(R, RV);
|
|
|
|
if (Args != NewArgs || Op != Val)
|
|
return new DagInit(Op, ValName, NewArgs, ArgNames);
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
std::string DagInit::getAsString() const {
|
|
std::string Result = "(" + Val->getAsString();
|
|
if (!ValName.empty())
|
|
Result += ":" + ValName;
|
|
if (Args.size()) {
|
|
Result += " " + Args[0]->getAsString();
|
|
if (!ArgNames[0].empty()) Result += ":$" + ArgNames[0];
|
|
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
|
|
Result += ", " + Args[i]->getAsString();
|
|
if (!ArgNames[i].empty()) Result += ":$" + ArgNames[i];
|
|
}
|
|
}
|
|
return Result + ")";
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Other implementations
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
RecordVal::RecordVal(const std::string &N, RecTy *T, unsigned P)
|
|
: Name(N), Ty(T), Prefix(P) {
|
|
Value = Ty->convertValue(new UnsetInit());
|
|
assert(Value && "Cannot create unset value for current type!");
|
|
}
|
|
|
|
void RecordVal::dump() const { errs() << *this; }
|
|
|
|
void RecordVal::print(raw_ostream &OS, bool PrintSem) const {
|
|
if (getPrefix()) OS << "field ";
|
|
OS << *getType() << " " << getName();
|
|
|
|
if (getValue())
|
|
OS << " = " << *getValue();
|
|
|
|
if (PrintSem) OS << ";\n";
|
|
}
|
|
|
|
unsigned Record::LastID = 0;
|
|
|
|
DefInit *Record::getDefInit() {
|
|
if (!TheInit)
|
|
TheInit = new DefInit(this, new RecordRecTy(this));
|
|
return TheInit;
|
|
}
|
|
|
|
void Record::setName(const std::string &Name) {
|
|
if (TrackedRecords.getDef(getName()) == this) {
|
|
TrackedRecords.removeDef(getName());
|
|
this->Name = Name;
|
|
TrackedRecords.addDef(this);
|
|
} else {
|
|
TrackedRecords.removeClass(getName());
|
|
this->Name = Name;
|
|
TrackedRecords.addClass(this);
|
|
}
|
|
}
|
|
|
|
/// resolveReferencesTo - If anything in this record refers to RV, replace the
|
|
/// reference to RV with the RHS of RV. If RV is null, we resolve all possible
|
|
/// references.
|
|
void Record::resolveReferencesTo(const RecordVal *RV) {
|
|
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
|
|
if (Init *V = Values[i].getValue())
|
|
Values[i].setValue(V->resolveReferences(*this, RV));
|
|
}
|
|
}
|
|
|
|
void Record::dump() const { errs() << *this; }
|
|
|
|
raw_ostream &llvm::operator<<(raw_ostream &OS, const Record &R) {
|
|
OS << R.getName();
|
|
|
|
const std::vector<std::string> &TArgs = R.getTemplateArgs();
|
|
if (!TArgs.empty()) {
|
|
OS << "<";
|
|
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
|
if (i) OS << ", ";
|
|
const RecordVal *RV = R.getValue(TArgs[i]);
|
|
assert(RV && "Template argument record not found??");
|
|
RV->print(OS, false);
|
|
}
|
|
OS << ">";
|
|
}
|
|
|
|
OS << " {";
|
|
const std::vector<Record*> &SC = R.getSuperClasses();
|
|
if (!SC.empty()) {
|
|
OS << "\t//";
|
|
for (unsigned i = 0, e = SC.size(); i != e; ++i)
|
|
OS << " " << SC[i]->getName();
|
|
}
|
|
OS << "\n";
|
|
|
|
const std::vector<RecordVal> &Vals = R.getValues();
|
|
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
|
|
if (Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName()))
|
|
OS << Vals[i];
|
|
for (unsigned i = 0, e = Vals.size(); i != e; ++i)
|
|
if (!Vals[i].getPrefix() && !R.isTemplateArg(Vals[i].getName()))
|
|
OS << Vals[i];
|
|
|
|
return OS << "}\n";
|
|
}
|
|
|
|
/// getValueInit - Return the initializer for a value with the specified name,
|
|
/// or throw an exception if the field does not exist.
|
|
///
|
|
Init *Record::getValueInit(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
return R->getValue();
|
|
}
|
|
|
|
|
|
/// getValueAsString - This method looks up the specified field and returns its
|
|
/// value as a string, throwing an exception if the field does not exist or if
|
|
/// the value is not a string.
|
|
///
|
|
std::string Record::getValueAsString(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (const StringInit *SI = dynamic_cast<const StringInit*>(R->getValue()))
|
|
return SI->getValue();
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a string initializer!";
|
|
}
|
|
|
|
/// getValueAsBitsInit - This method looks up the specified field and returns
|
|
/// its value as a BitsInit, throwing an exception if the field does not exist
|
|
/// or if the value is not the right type.
|
|
///
|
|
BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (BitsInit *BI = dynamic_cast<BitsInit*>(R->getValue()))
|
|
return BI;
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a BitsInit initializer!";
|
|
}
|
|
|
|
/// getValueAsListInit - This method looks up the specified field and returns
|
|
/// its value as a ListInit, throwing an exception if the field does not exist
|
|
/// or if the value is not the right type.
|
|
///
|
|
ListInit *Record::getValueAsListInit(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (ListInit *LI = dynamic_cast<ListInit*>(R->getValue()))
|
|
return LI;
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a list initializer!";
|
|
}
|
|
|
|
/// getValueAsListOfDefs - This method looks up the specified field and returns
|
|
/// its value as a vector of records, throwing an exception if the field does
|
|
/// not exist or if the value is not the right type.
|
|
///
|
|
std::vector<Record*>
|
|
Record::getValueAsListOfDefs(StringRef FieldName) const {
|
|
ListInit *List = getValueAsListInit(FieldName);
|
|
std::vector<Record*> Defs;
|
|
for (unsigned i = 0; i < List->getSize(); i++) {
|
|
if (DefInit *DI = dynamic_cast<DefInit*>(List->getElement(i))) {
|
|
Defs.push_back(DI->getDef());
|
|
} else {
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' list is not entirely DefInit!";
|
|
}
|
|
}
|
|
return Defs;
|
|
}
|
|
|
|
/// getValueAsInt - This method looks up the specified field and returns its
|
|
/// value as an int64_t, throwing an exception if the field does not exist or if
|
|
/// the value is not the right type.
|
|
///
|
|
int64_t Record::getValueAsInt(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (IntInit *II = dynamic_cast<IntInit*>(R->getValue()))
|
|
return II->getValue();
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have an int initializer!";
|
|
}
|
|
|
|
/// getValueAsListOfInts - This method looks up the specified field and returns
|
|
/// its value as a vector of integers, throwing an exception if the field does
|
|
/// not exist or if the value is not the right type.
|
|
///
|
|
std::vector<int64_t>
|
|
Record::getValueAsListOfInts(StringRef FieldName) const {
|
|
ListInit *List = getValueAsListInit(FieldName);
|
|
std::vector<int64_t> Ints;
|
|
for (unsigned i = 0; i < List->getSize(); i++) {
|
|
if (IntInit *II = dynamic_cast<IntInit*>(List->getElement(i))) {
|
|
Ints.push_back(II->getValue());
|
|
} else {
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a list of ints initializer!";
|
|
}
|
|
}
|
|
return Ints;
|
|
}
|
|
|
|
/// getValueAsListOfStrings - This method looks up the specified field and
|
|
/// returns its value as a vector of strings, throwing an exception if the
|
|
/// field does not exist or if the value is not the right type.
|
|
///
|
|
std::vector<std::string>
|
|
Record::getValueAsListOfStrings(StringRef FieldName) const {
|
|
ListInit *List = getValueAsListInit(FieldName);
|
|
std::vector<std::string> Strings;
|
|
for (unsigned i = 0; i < List->getSize(); i++) {
|
|
if (StringInit *II = dynamic_cast<StringInit*>(List->getElement(i))) {
|
|
Strings.push_back(II->getValue());
|
|
} else {
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a list of strings initializer!";
|
|
}
|
|
}
|
|
return Strings;
|
|
}
|
|
|
|
/// getValueAsDef - This method looks up the specified field and returns its
|
|
/// value as a Record, throwing an exception if the field does not exist or if
|
|
/// the value is not the right type.
|
|
///
|
|
Record *Record::getValueAsDef(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (DefInit *DI = dynamic_cast<DefInit*>(R->getValue()))
|
|
return DI->getDef();
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a def initializer!";
|
|
}
|
|
|
|
/// getValueAsBit - This method looks up the specified field and returns its
|
|
/// value as a bit, throwing an exception if the field does not exist or if
|
|
/// the value is not the right type.
|
|
///
|
|
bool Record::getValueAsBit(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (BitInit *BI = dynamic_cast<BitInit*>(R->getValue()))
|
|
return BI->getValue();
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a bit initializer!";
|
|
}
|
|
|
|
/// getValueAsDag - This method looks up the specified field and returns its
|
|
/// value as an Dag, throwing an exception if the field does not exist or if
|
|
/// the value is not the right type.
|
|
///
|
|
DagInit *Record::getValueAsDag(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (DagInit *DI = dynamic_cast<DagInit*>(R->getValue()))
|
|
return DI;
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a dag initializer!";
|
|
}
|
|
|
|
std::string Record::getValueAsCode(StringRef FieldName) const {
|
|
const RecordVal *R = getValue(FieldName);
|
|
if (R == 0 || R->getValue() == 0)
|
|
throw "Record `" + getName() + "' does not have a field named `" +
|
|
FieldName.str() + "'!\n";
|
|
|
|
if (const CodeInit *CI = dynamic_cast<const CodeInit*>(R->getValue()))
|
|
return CI->getValue();
|
|
throw "Record `" + getName() + "', field `" + FieldName.str() +
|
|
"' does not have a code initializer!";
|
|
}
|
|
|
|
|
|
void MultiClass::dump() const {
|
|
errs() << "Record:\n";
|
|
Rec.dump();
|
|
|
|
errs() << "Defs:\n";
|
|
for (RecordVector::const_iterator r = DefPrototypes.begin(),
|
|
rend = DefPrototypes.end();
|
|
r != rend;
|
|
++r) {
|
|
(*r)->dump();
|
|
}
|
|
}
|
|
|
|
|
|
void RecordKeeper::dump() const { errs() << *this; }
|
|
|
|
raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
|
|
OS << "------------- Classes -----------------\n";
|
|
const std::map<std::string, Record*> &Classes = RK.getClasses();
|
|
for (std::map<std::string, Record*>::const_iterator I = Classes.begin(),
|
|
E = Classes.end(); I != E; ++I)
|
|
OS << "class " << *I->second;
|
|
|
|
OS << "------------- Defs -----------------\n";
|
|
const std::map<std::string, Record*> &Defs = RK.getDefs();
|
|
for (std::map<std::string, Record*>::const_iterator I = Defs.begin(),
|
|
E = Defs.end(); I != E; ++I)
|
|
OS << "def " << *I->second;
|
|
return OS;
|
|
}
|
|
|
|
|
|
/// getAllDerivedDefinitions - This method returns all concrete definitions
|
|
/// that derive from the specified class name. If a class with the specified
|
|
/// name does not exist, an error is printed and true is returned.
|
|
std::vector<Record*>
|
|
RecordKeeper::getAllDerivedDefinitions(const std::string &ClassName) const {
|
|
Record *Class = getClass(ClassName);
|
|
if (!Class)
|
|
throw "ERROR: Couldn't find the `" + ClassName + "' class!\n";
|
|
|
|
std::vector<Record*> Defs;
|
|
for (std::map<std::string, Record*>::const_iterator I = getDefs().begin(),
|
|
E = getDefs().end(); I != E; ++I)
|
|
if (I->second->isSubClassOf(Class))
|
|
Defs.push_back(I->second);
|
|
|
|
return Defs;
|
|
}
|
|
|