This checkin basically amounts to a complete rewrite of the type-resolution

machinery.  This dramatically simplifies how things works, removes irritating
little corner cases, and overall improves speed and reliability.

Highlights of this change are:

1. The exponential algorithm built into the code is now gone.  For example
   the time to disassemble one bytecode file from the mesa benchmark went
   from taking 12.5s to taking 0.16s.
2. The linker bugs should be dramatically reduced.  The one remaining bug
   has to do with constant handling, which I actually introduced in
   "union-find" checkins.
3. The code is much easier to follow, as a result of fewer special cases.
   It's probably also smaller.  yaay.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8842 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2003-10-03 18:46:24 +00:00
parent 4797826e17
commit 7685ac8d35
5 changed files with 188 additions and 346 deletions

View File

@ -38,24 +38,20 @@ protected:
virtual ~AbstractTypeUser() {} // Derive from me
public:
// refineAbstractType - The callback method invoked when an abstract type
// has been found to be more concrete. A class must override this method to
// update its internal state to reference NewType instead of OldType. Soon
// after this method is invoked, OldType shall be deleted, so referencing it
// is quite unwise.
//
// Another case that is important to consider is when a type is refined, but
// stays in the same place in memory. In this case OldTy will equal NewTy.
// This callback just notifies ATU's that the underlying structure of the type
// has changed... but any previously used properties are still valid.
//
// Note that it is possible to refine a type with parameters OldTy==NewTy, and
// OldTy is no longer abstract. In this case, abstract type users should
// release their hold on a type, because it went from being abstract to
// concrete.
//
/// refineAbstractType - The callback method invoked when an abstract type is
/// resolved to another type. An object must override this method to update
/// its internal state to reference NewType instead of OldType.
///
virtual void refineAbstractType(const DerivedType *OldTy,
const Type *NewTy) = 0;
/// The other case which AbstractTypeUsers must be aware of is when a type
/// makes the transition from being abstract (where it has clients on it's
/// AbstractTypeUsers list) to concrete (where it does not). This method
/// notifies ATU's when this occurs for a type.
///
virtual void typeBecameConcrete(const DerivedType *AbsTy) = 0;
// for debugging...
virtual void dump() const = 0;
};

View File

@ -26,9 +26,6 @@ class DerivedType : public Type, public AbstractTypeUser {
///
mutable unsigned RefCount;
// isRefining - Used for recursive types
char isRefining;
// AbstractTypeUsers - Implement a list of the users that need to be notified
// if I am a type, and I get resolved into a more concrete type.
//
@ -36,17 +33,17 @@ class DerivedType : public Type, public AbstractTypeUser {
mutable std::vector<AbstractTypeUser *> AbstractTypeUsers;
protected:
DerivedType(PrimitiveID id) : Type("", id), RefCount(0), isRefining(0) {
DerivedType(PrimitiveID id) : Type("", id), RefCount(0) {
}
~DerivedType() {
assert(AbstractTypeUsers.empty());
}
// typeIsRefined - Notify AbstractTypeUsers of this type that the current type
// has been refined a bit. The pointer is still valid and still should be
// used, but the subtypes have changed.
//
void typeIsRefined();
/// notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type
/// that the current type has transitioned from being abstract to being
/// concrete.
///
void notifyUsesThatTypeBecameConcrete();
// dropAllTypeUses - When this (abstract) type is resolved to be equal to
// another (more concrete) type, we must eliminate all references to other
@ -146,6 +143,11 @@ protected:
virtual void dropAllTypeUses(bool inMap);
public:
/// FunctionType::get - This static method is the primary way of constructing
/// a FunctionType
static FunctionType *get(const Type *Result,
const std::vector<const Type*> &Params,
bool isVarArg);
inline bool isVarArg() const { return isVarArgs; }
inline const Type *getReturnType() const { return ResultType; }
@ -166,16 +168,10 @@ public:
}
virtual unsigned getNumContainedTypes() const { return ParamTys.size()+1; }
// refineAbstractType - Called when a contained type is found to be more
// concrete - this could potentially change us from an abstract type to a
// concrete type.
//
// Implement the AbstractTypeUser interface.
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
static FunctionType *get(const Type *Result,
const std::vector<const Type*> &Params,
bool isVarArg);
virtual void typeBecameConcrete(const DerivedType *AbsTy);
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const FunctionType *T) { return true; }
static inline bool classof(const Type *T) {
@ -244,6 +240,10 @@ protected:
virtual void dropAllTypeUses(bool inMap);
public:
/// StructType::get - This static method is the primary way to create a
/// StructType.
static StructType *get(const std::vector<const Type*> &Params);
inline const ElementTypes &getElementTypes() const { return ETypes; }
virtual const Type *getContainedType(unsigned i) const {
@ -262,13 +262,9 @@ public:
//
virtual const Type *getIndexType() const { return Type::UByteTy; }
// refineAbstractType - Called when a contained type is found to be more
// concrete - this could potentially change us from an abstract type to a
// concrete type.
//
// Implement the AbstractTypeUser interface.
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
static StructType *get(const std::vector<const Type*> &Params);
virtual void typeBecameConcrete(const DerivedType *AbsTy);
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const StructType *T) { return true; }
@ -353,15 +349,15 @@ protected:
virtual void dropAllTypeUses(bool inMap);
public:
/// ArrayType::get - This static method is the primary way to construct an
/// ArrayType
static ArrayType *get(const Type *ElementType, unsigned NumElements);
inline unsigned getNumElements() const { return NumElements; }
// refineAbstractType - Called when a contained type is found to be more
// concrete - this could potentially change us from an abstract type to a
// concrete type.
//
// Implement the AbstractTypeUser interface.
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
static ArrayType *get(const Type *ElementType, unsigned NumElements);
virtual void typeBecameConcrete(const DerivedType *AbsTy);
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const ArrayType *T) { return true; }
@ -393,16 +389,14 @@ protected:
// type from the internal tables of available types.
virtual void dropAllTypeUses(bool inMap);
public:
// PointerType::get - Named constructor for pointer types...
/// PointerType::get - This is the only way to construct a new pointer type.
static PointerType *get(const Type *ElementType);
// refineAbstractType - Called when a contained type is found to be more
// concrete - this could potentially change us from an abstract type to a
// concrete type.
//
// Implement the AbstractTypeUser interface.
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
virtual void typeBecameConcrete(const DerivedType *AbsTy);
// Methods for support type inquiry through isa, cast, and dyn_cast:
// Implement support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const PointerType *T) { return true; }
static inline bool classof(const Type *T) {
return T->getPrimitiveID() == PointerTyID;
@ -430,23 +424,20 @@ protected:
virtual void dropAllTypeUses(bool inMap) {} // No type uses
public:
// get - Static factory method for the OpaqueType class...
// OpaqueType::get - Static factory method for the OpaqueType class...
static OpaqueType *get() {
return new OpaqueType(); // All opaque types are distinct
}
// refineAbstractType - Called when a contained type is found to be more
// concrete - this could potentially change us from an abstract type to a
// concrete type.
//
// Implement the AbstractTypeUser interface.
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
// This class never uses other types!
abort();
abort(); // FIXME: this is not really an AbstractTypeUser!
}
virtual void typeBecameConcrete(const DerivedType *AbsTy) {
abort(); // FIXME: this is not really an AbstractTypeUser!
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
// Implement support for type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const OpaqueType *T) { return true; }
static inline bool classof(const Type *T) {
return T->getPrimitiveID() == OpaqueTyID;

View File

@ -118,6 +118,7 @@ private:
// This function is called when one of the types in the type plane are refined
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
virtual void typeBecameConcrete(const DerivedType *AbsTy);
};
#endif

View File

@ -195,7 +195,7 @@ void SymbolTable::refineAbstractType(const DerivedType *OldType,
// Search to see if we have any values of the type oldtype. If so, we need to
// move them into the newtype plane...
iterator TPI = find(OldType);
if (OldType != NewType && TPI != end()) {
if (TPI != end()) {
// Get a handle to the new type plane...
iterator NewTypeIt = find(NewType);
if (NewTypeIt == super::end()) { // If no plane exists, add one
@ -281,12 +281,6 @@ void SymbolTable::refineAbstractType(const DerivedType *OldType,
// Remove the plane that is no longer used
erase(TPI);
} else if (TPI != end()) {
assert(OldType == NewType);
#if DEBUG_ABSTYPE
std::cerr << "Removing SELF type " << OldType->getDescription() << "\n";
#endif
OldType->removeAbstractTypeUser(this);
}
TPI = find(Type::TypeTy);
@ -315,6 +309,27 @@ void SymbolTable::refineAbstractType(const DerivedType *OldType,
}
}
void SymbolTable::typeBecameConcrete(const DerivedType *AbsTy) {
iterator TPI = find(AbsTy);
// If there are any values in the symbol table of this type, then the type
// plan is a use of the abstract type which must be dropped.
if (TPI != end())
AbsTy->removeAbstractTypeUser(this);
TPI = find(Type::TypeTy);
if (TPI != end()) {
// Loop over all of the types in the symbol table, dropping any abstract
// type user entries for AbsTy which occur because there are names for the
// type.
//
VarMap &TyPlane = TPI->second;
for (VarMap::iterator I = TyPlane.begin(), E = TyPlane.end(); I != E; ++I)
if (I->second == (Value*)AbsTy) // FIXME when Types aren't const.
AbsTy->removeAbstractTypeUser(this);
}
}
static void DumpVal(const std::pair<const std::string, Value *> &V) {
std::cout << " '" << V.first << "' = ";
V.second->dump();

View File

@ -498,8 +498,8 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2) {
// our map if an abstract type gets refined somehow...
//
template<class ValType, class TypeClass>
class TypeMap : public AbstractTypeUser {
typedef std::map<ValType, PATypeHandle> MapTy;
class TypeMap {
typedef std::map<ValType, TypeClass *> MapTy;
MapTy Map;
public:
typedef typename MapTy::iterator iterator;
@ -507,11 +507,11 @@ public:
inline TypeClass *get(const ValType &V) {
iterator I = Map.find(V);
return I != Map.end() ? (TypeClass*)I->second.get() : 0;
return I != Map.end() ? I->second : 0;
}
inline void add(const ValType &V, TypeClass *T) {
Map.insert(std::make_pair(V, PATypeHandle(T, this)));
Map.insert(std::make_pair(V, T));
print("add");
}
@ -519,57 +519,48 @@ public:
iterator I = Map.find(ValType::get(Ty));
if (I == Map.end()) print("ERROR!");
assert(I != Map.end() && "Didn't find type entry!");
assert(T->second == Ty && "Type entry wrong?");
assert(I->second == Ty && "Type entry wrong?");
return I;
}
void finishRefinement(TypeClass *Ty) {
//const TypeClass *Ty = (const TypeClass*)TyIt->second.get();
void finishRefinement(TypeClass *Ty, iterator TyIt) {
// FIXME: this could eventually just pass in the iterator!
assert(TyIt->second == Ty && "Did not specify entry for the correct type!");
// The old record is now out-of-date, because one of the children has been
// updated. Remove the obsolete entry from the map.
Map.erase(TyIt);
// Now we check to see if there is an existing entry in the table which is
// structurally identical to the newly refined type. If so, this type gets
// refined to the pre-existing type.
//
for (iterator I = Map.begin(), E = Map.end(); I != E; ++I)
if (I->second.get() != Ty && TypesEqual(Ty, I->second.get())) {
if (TypesEqual(Ty, I->second)) {
assert(Ty->isAbstract() && "Replacing a non-abstract type?");
TypeClass *NewTy = (TypeClass*)I->second.get();
#if 0
//Map.erase(TyIt); // The old entry is now dead!
#endif
TypeClass *NewTy = I->second;
// Refined to a different type altogether?
Ty->refineAbstractTypeToInternal(NewTy, false);
return;
}
// If there is no existing type of the same structure, we reinsert an
// updated record into the map.
Map.insert(std::make_pair(ValType::get(Ty), Ty));
// If the type is currently thought to be abstract, rescan all of our
// subtypes to see if the type has just become concrete!
if (Ty->isAbstract())
if (Ty->isAbstract()) {
Ty->setAbstract(Ty->isTypeAbstract());
// This method may be called with either an abstract or a concrete type.
// Concrete types might get refined if a subelement type got refined which
// was previously marked as abstract, but was realized to be concrete. This
// can happen for recursive types.
Ty->typeIsRefined(); // Same type, different contents...
// If the type just became concrete, notify all users!
if (!Ty->isAbstract())
Ty->notifyUsesThatTypeBecameConcrete();
}
}
// refineAbstractType - This is called when one of the contained abstract
// types gets refined... this simply removes the abstract type from our table.
// We expect that whoever refined the type will add it back to the table,
// corrected.
//
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
#ifdef DEBUG_MERGE_TYPES
std::cerr << "Removing Old type from Tab: " << (void*)OldTy << ", "
<< *OldTy << " replacement == " << (void*)NewTy
<< ", " << *NewTy << "\n";
#endif
for (iterator I = Map.begin(), E = Map.end(); I != E; ++I)
if (I->second.get() == OldTy) {
// Check to see if the type just became concrete. If so, remove self
// from user list.
I->second.removeUserFromConcrete();
I->second = cast<TypeClass>(NewTy);
}
}
void remove(const ValType &OldVal) {
iterator I = Map.find(OldVal);
assert(I != Map.end() && "TypeMap::remove, element not found!");
@ -587,8 +578,8 @@ public:
unsigned i = 0;
for (typename MapTy::const_iterator I = Map.begin(), E = Map.end();
I != E; ++I)
std::cerr << " " << (++i) << ". " << (void*)I->second.get() << " "
<< *I->second.get() << "\n";
std::cerr << " " << (++i) << ". " << (void*)I->second << " "
<< *I->second << "\n";
#endif
}
@ -596,50 +587,6 @@ public:
};
// ValTypeBase - This is the base class that is used by the various
// instantiations of TypeMap. This class is an AbstractType user that notifies
// the underlying TypeMap when it gets modified.
//
template<class ValType, class TypeClass>
class ValTypeBase : public AbstractTypeUser {
TypeMap<ValType, TypeClass> &MyTable;
protected:
inline ValTypeBase(TypeMap<ValType, TypeClass> &tab) : MyTable(tab) {}
// Subclass should override this... to update self as usual
virtual void doRefinement(const DerivedType *OldTy, const Type *NewTy) = 0;
// typeBecameConcrete - This callback occurs when a contained type refines
// to itself, but becomes concrete in the process. Our subclass should remove
// itself from the ATU list of the specified type.
//
virtual void typeBecameConcrete(const DerivedType *Ty) = 0;
virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
assert(OldTy == NewTy || OldTy->isAbstract());
if (!OldTy->isAbstract())
typeBecameConcrete(OldTy);
TypeMap<ValType, TypeClass> &Table = MyTable; // Copy MyTable reference
ValType Tmp(*(ValType*)this); // Copy this.
PATypeHandle OldType(Table.get(*(ValType*)this), this);
Table.remove(*(ValType*)this); // Destroy's this!
// Refine temporary to new state...
if (OldTy != NewTy)
Tmp.doRefinement(OldTy, NewTy);
// FIXME: when types are not const!
Table.add((ValType&)Tmp, (TypeClass*)OldType.get());
}
void dump() const {
std::cerr << "ValTypeBase instance!\n";
}
};
//===----------------------------------------------------------------------===//
// Function Type Factory and Value Class...
@ -647,52 +594,42 @@ protected:
// FunctionValType - Define a class to hold the key that goes into the TypeMap
//
class FunctionValType : public ValTypeBase<FunctionValType, FunctionType> {
PATypeHandle RetTy;
std::vector<PATypeHandle> ArgTypes;
class FunctionValType {
const Type *RetTy;
std::vector<const Type*> ArgTypes;
bool isVarArg;
public:
FunctionValType(const Type *ret, const std::vector<const Type*> &args,
bool IVA, TypeMap<FunctionValType, FunctionType> &Tab)
: ValTypeBase<FunctionValType, FunctionType>(Tab), RetTy(ret, this),
isVarArg(IVA) {
bool IVA) : RetTy(ret), isVarArg(IVA) {
for (unsigned i = 0; i < args.size(); ++i)
ArgTypes.push_back(PATypeHandle(args[i], this));
ArgTypes.push_back(args[i]);
}
// We *MUST* have an explicit copy ctor so that the TypeHandles think that
// this FunctionValType owns them, not the old one!
//
FunctionValType(const FunctionValType &MVT)
: ValTypeBase<FunctionValType, FunctionType>(MVT), RetTy(MVT.RetTy, this),
isVarArg(MVT.isVarArg) {
FunctionValType(const FunctionValType &MVT)
: RetTy(MVT.RetTy), isVarArg(MVT.isVarArg) {
ArgTypes.reserve(MVT.ArgTypes.size());
for (unsigned i = 0; i < MVT.ArgTypes.size(); ++i)
ArgTypes.push_back(PATypeHandle(MVT.ArgTypes[i], this));
ArgTypes.push_back(MVT.ArgTypes[i]);
}
static FunctionValType get(const FunctionType *FT);
// Subclass should override this... to update self as usual
virtual void doRefinement(const DerivedType *OldType, const Type *NewType) {
void doRefinement(const DerivedType *OldType, const Type *NewType) {
if (RetTy == OldType) RetTy = NewType;
for (unsigned i = 0, e = ArgTypes.size(); i != e; ++i)
if (ArgTypes[i] == OldType) ArgTypes[i] = NewType;
}
virtual void typeBecameConcrete(const DerivedType *Ty) {
if (RetTy == Ty) RetTy.removeUserFromConcrete();
for (unsigned i = 0; i < ArgTypes.size(); ++i)
if (ArgTypes[i] == Ty) ArgTypes[i].removeUserFromConcrete();
}
inline bool operator<(const FunctionValType &MTV) const {
if (RetTy.get() < MTV.RetTy.get()) return true;
if (RetTy.get() > MTV.RetTy.get()) return false;
if (RetTy < MTV.RetTy) return true;
if (RetTy > MTV.RetTy) return false;
if (ArgTypes < MTV.ArgTypes) return true;
return (ArgTypes == MTV.ArgTypes) && isVarArg < MTV.isVarArg;
return ArgTypes == MTV.ArgTypes && isVarArg < MTV.isVarArg;
}
};
@ -705,8 +642,7 @@ FunctionValType FunctionValType::get(const FunctionType *FT) {
ParamTypes.reserve(FT->getParamTypes().size());
for (unsigned i = 0, e = FT->getParamTypes().size(); i != e; ++i)
ParamTypes.push_back(FT->getParamType(i));
return FunctionValType(FT->getReturnType(), ParamTypes, FT->isVarArg(),
FunctionTypes);
return FunctionValType(FT->getReturnType(), ParamTypes, FT->isVarArg());
}
@ -714,7 +650,7 @@ FunctionValType FunctionValType::get(const FunctionType *FT) {
FunctionType *FunctionType::get(const Type *ReturnType,
const std::vector<const Type*> &Params,
bool isVarArg) {
FunctionValType VT(ReturnType, Params, isVarArg, FunctionTypes);
FunctionValType VT(ReturnType, Params, isVarArg);
FunctionType *MT = FunctionTypes.get(VT);
if (MT) return MT;
@ -739,52 +675,40 @@ void FunctionType::dropAllTypeUses(bool inMap) {
//===----------------------------------------------------------------------===//
// Array Type Factory...
//
class ArrayValType : public ValTypeBase<ArrayValType, ArrayType> {
PATypeHandle ValTy;
class ArrayValType {
const Type *ValTy;
unsigned Size;
public:
ArrayValType(const Type *val, int sz, TypeMap<ArrayValType, ArrayType> &Tab)
: ValTypeBase<ArrayValType, ArrayType>(Tab), ValTy(val, this), Size(sz) {}
ArrayValType(const Type *val, int sz) : ValTy(val), Size(sz) {}
// We *MUST* have an explicit copy ctor so that the ValTy thinks that this
// ArrayValType owns it, not the old one!
//
ArrayValType(const ArrayValType &AVT)
: ValTypeBase<ArrayValType, ArrayType>(AVT), ValTy(AVT.ValTy, this),
Size(AVT.Size) {}
static ArrayValType get(const ArrayType *AT);
ArrayValType(const ArrayValType &AVT) : ValTy(AVT.ValTy), Size(AVT.Size) {}
static ArrayValType get(const ArrayType *AT) {
return ArrayValType(AT->getElementType(), AT->getNumElements());
}
// Subclass should override this... to update self as usual
virtual void doRefinement(const DerivedType *OldType, const Type *NewType) {
void doRefinement(const DerivedType *OldType, const Type *NewType) {
assert(ValTy == OldType);
ValTy = NewType;
}
virtual void typeBecameConcrete(const DerivedType *Ty) {
assert(ValTy == Ty &&
"Contained type became concrete but we're not using it!");
ValTy.removeUserFromConcrete();
}
inline bool operator<(const ArrayValType &MTV) const {
if (Size < MTV.Size) return true;
return Size == MTV.Size && ValTy.get() < MTV.ValTy.get();
return Size == MTV.Size && ValTy < MTV.ValTy;
}
};
static TypeMap<ArrayValType, ArrayType> ArrayTypes;
ArrayValType ArrayValType::get(const ArrayType *AT) {
return ArrayValType(AT->getElementType(), AT->getNumElements(), ArrayTypes);
}
ArrayType *ArrayType::get(const Type *ElementType, unsigned NumElements) {
assert(ElementType && "Can't get array of null types!");
ArrayValType AVT(ElementType, NumElements, ArrayTypes);
ArrayValType AVT(ElementType, NumElements);
ArrayType *AT = ArrayTypes.get(AVT);
if (AT) return AT; // Found a match, return it!
@ -813,41 +737,29 @@ void ArrayType::dropAllTypeUses(bool inMap) {
// StructValType - Define a class to hold the key that goes into the TypeMap
//
class StructValType : public ValTypeBase<StructValType, StructType> {
std::vector<PATypeHandle> ElTypes;
class StructValType {
std::vector<const Type*> ElTypes;
public:
StructValType(const std::vector<const Type*> &args,
TypeMap<StructValType, StructType> &Tab)
: ValTypeBase<StructValType, StructType>(Tab) {
ElTypes.reserve(args.size());
for (unsigned i = 0, e = args.size(); i != e; ++i)
ElTypes.push_back(PATypeHandle(args[i], this));
}
StructValType(const std::vector<const Type*> &args) : ElTypes(args) {}
// We *MUST* have an explicit copy ctor so that the TypeHandles think that
// this StructValType owns them, not the old one!
//
StructValType(const StructValType &SVT)
: ValTypeBase<StructValType, StructType>(SVT){
ElTypes.reserve(SVT.ElTypes.size());
for (unsigned i = 0, e = SVT.ElTypes.size(); i != e; ++i)
ElTypes.push_back(PATypeHandle(SVT.ElTypes[i], this));
}
// Explicit copy ctor not needed
StructValType(const StructValType &SVT) : ElTypes(SVT.ElTypes) {}
static StructValType get(const StructType *ST);
static StructValType get(const StructType *ST) {
std::vector<const Type *> ElTypes;
ElTypes.reserve(ST->getElementTypes().size());
for (unsigned i = 0, e = ST->getElementTypes().size(); i != e; ++i)
ElTypes.push_back(ST->getElementTypes()[i]);
return StructValType(ElTypes);
}
// Subclass should override this... to update self as usual
virtual void doRefinement(const DerivedType *OldType, const Type *NewType) {
void doRefinement(const DerivedType *OldType, const Type *NewType) {
for (unsigned i = 0; i < ElTypes.size(); ++i)
if (ElTypes[i] == OldType) ElTypes[i] = NewType;
}
virtual void typeBecameConcrete(const DerivedType *Ty) {
for (unsigned i = 0, e = ElTypes.size(); i != e; ++i)
if (ElTypes[i] == Ty)
ElTypes[i].removeUserFromConcrete();
}
inline bool operator<(const StructValType &STV) const {
return ElTypes < STV.ElTypes;
}
@ -855,19 +767,8 @@ public:
static TypeMap<StructValType, StructType> StructTypes;
StructValType StructValType::get(const StructType *ST) {
std::vector<const Type *> ElTypes;
ElTypes.reserve(ST->getElementTypes().size());
for (unsigned i = 0, e = ST->getElementTypes().size(); i != e; ++i)
ElTypes.push_back(ST->getElementTypes()[i]);
return StructValType(ElTypes, StructTypes);
}
StructType *StructType::get(const std::vector<const Type*> &ETypes) {
StructValType STV(ETypes, StructTypes);
StructValType STV(ETypes);
StructType *ST = StructTypes.get(STV);
if (ST) return ST;
@ -896,47 +797,34 @@ void StructType::dropAllTypeUses(bool inMap) {
// PointerValType - Define a class to hold the key that goes into the TypeMap
//
class PointerValType : public ValTypeBase<PointerValType, PointerType> {
PATypeHandle ValTy;
class PointerValType {
const Type *ValTy;
public:
PointerValType(const Type *val, TypeMap<PointerValType, PointerType> &Tab)
: ValTypeBase<PointerValType, PointerType>(Tab), ValTy(val, this) {}
PointerValType(const Type *val) : ValTy(val) {}
// We *MUST* have an explicit copy ctor so that the ValTy thinks that this
// PointerValType owns it, not the old one!
//
PointerValType(const PointerValType &PVT)
: ValTypeBase<PointerValType, PointerType>(PVT), ValTy(PVT.ValTy, this) {}
// FIXME: delete explicit copy ctor
PointerValType(const PointerValType &PVT) : ValTy(PVT.ValTy) {}
static PointerValType get(const PointerType *PT);
static PointerValType get(const PointerType *PT) {
return PointerValType(PT->getElementType());
}
// Subclass should override this... to update self as usual
virtual void doRefinement(const DerivedType *OldType, const Type *NewType) {
void doRefinement(const DerivedType *OldType, const Type *NewType) {
assert(ValTy == OldType);
ValTy = NewType;
}
virtual void typeBecameConcrete(const DerivedType *Ty) {
assert(ValTy == Ty &&
"Contained type became concrete but we're not using it!");
ValTy.removeUserFromConcrete();
}
inline bool operator<(const PointerValType &MTV) const {
return ValTy.get() < MTV.ValTy.get();
bool operator<(const PointerValType &MTV) const {
return ValTy < MTV.ValTy;
}
};
static TypeMap<PointerValType, PointerType> PointerTypes;
PointerValType PointerValType::get(const PointerType *PT) {
return PointerValType(PT->getElementType(), PointerTypes);
}
PointerType *PointerType::get(const Type *ValueType) {
assert(ValueType && "Can't get a pointer to <null> type!");
PointerValType PVT(ValueType, PointerTypes);
PointerValType PVT(ValueType);
PointerType *PT = PointerTypes.get(PVT);
if (PT) return PT;
@ -1011,7 +899,8 @@ void DerivedType::removeAbstractTypeUser(AbstractTypeUser *U) const {
void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){
assert(isAbstract() && "refineAbstractTypeTo: Current type is not abstract!");
assert(this != NewType && "Can't refine to myself!");
assert(ForwardType == 0 && "This type has already been refined!");
// The descriptions may be out of date. Conservatively clear them all!
AbstractTypeDescriptions.clear();
@ -1021,12 +910,13 @@ void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){
<< *NewType << "]!\n";
#endif
// Make sure to put the type to be refined to into a holder so that if IT gets
// refined, that we will not continue using a dead reference...
//
PATypeHolder NewTy(NewType);
// Any PATypeHolders referring to this type will now automatically forward to
// the type we are resolved to.
ForwardType = NewType;
if (NewType->isAbstract())
cast<DerivedType>(NewType)->addRef();
@ -1060,18 +950,6 @@ void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){
#endif
User->refineAbstractType(this, NewTy);
#ifdef DEBUG_MERGE_TYPES
if (AbstractTypeUsers.size() == OldSize) {
User->refineAbstractType(this, NewTy);
if (AbstractTypeUsers.back() != User)
std::cerr << "User changed!\n";
std::cerr << "Top of user list is:\n";
AbstractTypeUsers.back()->dump();
std::cerr <<"\nOld User=\n";
User->dump();
}
#endif
assert(AbstractTypeUsers.size() != OldSize &&
"AbsTyUser did not remove self from user list!");
}
@ -1082,69 +960,22 @@ void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){
// destroyed.
}
// typeIsRefined - Notify AbstractTypeUsers of this type that the current type
// has been refined a bit. The pointer is still valid and still should be
// used, but the subtypes have changed.
// notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type that
// the current type has transitioned from being abstract to being concrete.
//
void DerivedType::typeIsRefined() {
assert(isRefining >= 0 && isRefining <= 2 && "isRefining out of bounds!");
if (isRefining == 1) return; // Kill recursion here...
++isRefining;
void DerivedType::notifyUsesThatTypeBecameConcrete() {
#ifdef DEBUG_MERGE_TYPES
std::cerr << "typeIsREFINED type: " << (void*)this << " " << *this << "\n";
#endif
// In this loop we have to be very careful not to get into infinite loops and
// other problem cases. Specifically, we loop through all of the abstract
// type users in the user list, notifying them that the type has been refined.
// At their choice, they may or may not choose to remove themselves from the
// list of users. Regardless of whether they do or not, we have to be sure
// that we only notify each user exactly once. Because the refineAbstractType
// method can cause an arbitrary permutation to the user list, we cannot loop
// through it in any particular order and be guaranteed that we will be
// successful at this aim. Because of this, we keep track of all the users we
// have visited and only visit users we have not seen. Because this user list
// should be small, we use a vector instead of a full featured set to keep
// track of what users we have notified so far.
//
std::vector<AbstractTypeUser*> Refined;
while (1) {
unsigned i;
for (i = AbstractTypeUsers.size(); i != 0; --i)
if (find(Refined.begin(), Refined.end(), AbstractTypeUsers[i-1]) ==
Refined.end())
break; // Found an unrefined user?
if (i == 0) break; // Noone to refine left, break out of here!
unsigned OldSize = AbstractTypeUsers.size();
while (!AbstractTypeUsers.empty()) {
AbstractTypeUser *ATU = AbstractTypeUsers.back();
ATU->typeBecameConcrete(this);
AbstractTypeUser *ATU = AbstractTypeUsers[--i];
Refined.push_back(ATU); // Keep track of which users we have refined!
#ifdef DEBUG_MERGE_TYPES
std::cerr << " typeIsREFINED user " << i << "[" << ATU
<< "] of abstract type [" << (void*)this << " "
<< *this << "]\n";
#endif
ATU->refineAbstractType(this, this);
assert(AbstractTypeUsers.size() < OldSize-- &&
"AbstractTypeUser did not remove itself from the use list!");
}
--isRefining;
#ifndef _NDEBUG
if (!(isAbstract() || AbstractTypeUsers.empty()))
for (unsigned i = 0; i < AbstractTypeUsers.size(); ++i) {
if (AbstractTypeUsers[i] != this) {
// Debugging hook
std::cerr << "FOUND FAILURE\nUser: ";
AbstractTypeUsers[i]->dump();
std::cerr << "\nCatch:\n";
AbstractTypeUsers[i]->refineAbstractType(this, this);
assert(0 && "Type became concrete,"
" but it still has abstract type users hanging around!");
}
}
#endif
}
@ -1165,10 +996,8 @@ void FunctionType::refineAbstractType(const DerivedType *OldType,
#endif
// Look up our current type map entry..
#if 0
TypeMap<FunctionValType, FunctionType>::iterator TMI =
FunctionTypes.getEntryForType(this);
#endif
// Find the type element we are refining...
if (ResultType == OldType) {
@ -1181,7 +1010,11 @@ void FunctionType::refineAbstractType(const DerivedType *OldType,
ParamTys[i] = NewType;
}
FunctionTypes.finishRefinement(this);
FunctionTypes.finishRefinement(this, TMI);
}
void FunctionType::typeBecameConcrete(const DerivedType *AbsTy) {
refineAbstractType(AbsTy, AbsTy);
}
@ -1199,17 +1032,19 @@ void ArrayType::refineAbstractType(const DerivedType *OldType,
<< *NewType << "])\n";
#endif
#if 0
// Look up our current type map entry..
TypeMap<ArrayValType, ArrayType>::iterator TMI =
ArrayTypes.getEntryForType(this);
#endif
assert(getElementType() == OldType);
ElementType.removeUserFromConcrete();
ElementType = NewType;
ArrayTypes.finishRefinement(this);
ArrayTypes.finishRefinement(this, TMI);
}
void ArrayType::typeBecameConcrete(const DerivedType *AbsTy) {
refineAbstractType(AbsTy, AbsTy);
}
@ -1227,11 +1062,9 @@ void StructType::refineAbstractType(const DerivedType *OldType,
<< *NewType << "])\n";
#endif
#if 0
// Look up our current type map entry..
TypeMap<StructValType, StructType>::iterator TMI =
StructTypes.getEntryForType(this);
#endif
for (int i = ETypes.size()-1; i >= 0; --i)
if (ETypes[i] == OldType) {
@ -1241,7 +1074,11 @@ void StructType::refineAbstractType(const DerivedType *OldType,
ETypes[i] = NewType;
}
StructTypes.finishRefinement(this);
StructTypes.finishRefinement(this, TMI);
}
void StructType::typeBecameConcrete(const DerivedType *AbsTy) {
refineAbstractType(AbsTy, AbsTy);
}
// refineAbstractType - Called when a contained type is found to be more
@ -1258,16 +1095,18 @@ void PointerType::refineAbstractType(const DerivedType *OldType,
<< *NewType << "])\n";
#endif
#if 0
// Look up our current type map entry..
TypeMap<PointerValType, PointerType>::iterator TMI =
PointerTypes.getEntryForType(this);
#endif
assert(ElementType == OldType);
ElementType.removeUserFromConcrete();
ElementType = NewType;
PointerTypes.finishRefinement(this);
PointerTypes.finishRefinement(this, TMI);
}
void PointerType::typeBecameConcrete(const DerivedType *AbsTy) {
refineAbstractType(AbsTy, AbsTy);
}