X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FVMCore%2FType.cpp;h=b815eec665b3c1b45a778dbd1fefcac3d2f99a26;hb=3e456abde2360a7fe4e528844acc8161e53fb80e;hp=b70cd5f4312d2660a0dcf3689028dcccb5a2cbf2;hpb=a54b7cbd452b3adb2f51346140d996b29c2cdb30;p=oota-llvm.git diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index b70cd5f4312..b815eec665b 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -11,19 +11,23 @@ // //===----------------------------------------------------------------------===// -#include "llvm/AbstractTypeUser.h" #include "llvm/DerivedTypes.h" -#include "llvm/SymbolTable.h" #include "llvm/Constants.h" +#include "llvm/Assembly/Writer.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Threading.h" +#include "llvm/System/Mutex.h" +#include "llvm/System/RWMutex.h" #include +#include using namespace llvm; // DEBUG_MERGE_TYPES - Enable this #define to see how and when derived types are @@ -36,62 +40,120 @@ AbstractTypeUser::~AbstractTypeUser() {} //===----------------------------------------------------------------------===// -// Type PATypeHolder Implementation +// Type Class Implementation //===----------------------------------------------------------------------===// -/// get - This implements the forwarding part of the union-find algorithm for -/// abstract types. Before every access to the Type*, we check to see if the -/// type we are pointing to is forwarding to a new type. If so, we drop our -/// reference to the type. -/// -Type* PATypeHolder::get() const { - const Type *NewTy = Ty->getForwardedType(); - if (!NewTy) return const_cast(Ty); - return *const_cast(this) = NewTy; -} +// Reader/writer lock used for guarding access to the type maps. +static ManagedStatic TypeMapLock; -//===----------------------------------------------------------------------===// -// Type Class Implementation -//===----------------------------------------------------------------------===// +// Recursive lock used for guarding access to AbstractTypeUsers. +static ManagedStatic AbstractTypeUsersLock; // Concrete/Abstract TypeDescriptions - We lazily calculate type descriptions // for types as they are needed. Because resolution of types must invalidate // all of the abstract type descriptions, we keep them in a seperate map to make // this easy. -static ManagedStatic > ConcreteTypeDescriptions; -static ManagedStatic > AbstractTypeDescriptions; +static ManagedStatic ConcreteTypeDescriptions; +static ManagedStatic AbstractTypeDescriptions; + +/// Because of the way Type subclasses are allocated, this function is necessary +/// to use the correct kind of "delete" operator to deallocate the Type object. +/// Some type objects (FunctionTy, StructTy) allocate additional space after +/// the space for their derived type to hold the contained types array of +/// PATypeHandles. Using this allocation scheme means all the PATypeHandles are +/// allocated with the type object, decreasing allocations and eliminating the +/// need for a std::vector to be used in the Type class itself. +/// @brief Type destruction function +void Type::destroy() const { + + // Structures and Functions allocate their contained types past the end of + // the type object itself. These need to be destroyed differently than the + // other types. + if (isa(this) || isa(this)) { + // First, make sure we destruct any PATypeHandles allocated by these + // subclasses. They must be manually destructed. + for (unsigned i = 0; i < NumContainedTys; ++i) + ContainedTys[i].PATypeHandle::~PATypeHandle(); + + // Now call the destructor for the subclass directly because we're going + // to delete this as an array of char. + if (isa(this)) + static_cast(this)->FunctionType::~FunctionType(); + else + static_cast(this)->StructType::~StructType(); -Type::Type(const char *Name, TypeID id) - : ID(id), Abstract(false), SubclassData(0), RefCount(0), ForwardType(0) { - assert(Name && Name[0] && "Should use other ctor if no name!"); - (*ConcreteTypeDescriptions)[this] = Name; -} + // Finally, remove the memory as an array deallocation of the chars it was + // constructed from. + operator delete(const_cast(this)); + return; + } + + // For all the other type subclasses, there is either no contained types or + // just one (all Sequentials). For Sequentials, the PATypeHandle is not + // allocated past the type object, its included directly in the SequentialType + // class. This means we can safely just do "normal" delete of this object and + // all the destructors that need to run will be run. + delete this; +} const Type *Type::getPrimitiveType(TypeID IDNumber) { switch (IDNumber) { - case VoidTyID : return VoidTy; - case FloatTyID : return FloatTy; - case DoubleTyID: return DoubleTy; - case LabelTyID : return LabelTy; + case VoidTyID : return VoidTy; + case FloatTyID : return FloatTy; + case DoubleTyID : return DoubleTy; + case X86_FP80TyID : return X86_FP80Ty; + case FP128TyID : return FP128Ty; + case PPC_FP128TyID : return PPC_FP128Ty; + case LabelTyID : return LabelTy; + case MetadataTyID : return MetadataTy; default: return 0; } } +const Type *Type::getVAArgsPromotedType() const { + if (ID == IntegerTyID && getSubclassData() < 32) + return Type::Int32Ty; + else if (ID == FloatTyID) + return Type::DoubleTy; + else + return this; +} + +/// getScalarType - If this is a vector type, return the element type, +/// otherwise return this. +const Type *Type::getScalarType() const { + if (const VectorType *VTy = dyn_cast(this)) + return VTy->getElementType(); + return this; +} + +/// isIntOrIntVector - Return true if this is an integer type or a vector of +/// integer types. +/// +bool Type::isIntOrIntVector() const { + if (isInteger()) + return true; + if (ID != Type::VectorTyID) return false; + + return cast(this)->getElementType()->isInteger(); +} + /// isFPOrFPVector - Return true if this is a FP type or a vector of FP types. /// bool Type::isFPOrFPVector() const { - if (ID == Type::FloatTyID || ID == Type::DoubleTyID) return true; - if (ID != Type::PackedTyID) return false; + if (ID == Type::FloatTyID || ID == Type::DoubleTyID || + ID == Type::FP128TyID || ID == Type::X86_FP80TyID || + ID == Type::PPC_FP128TyID) + return true; + if (ID != Type::VectorTyID) return false; - return cast(this)->getElementType()->isFloatingPoint(); + return cast(this)->getElementType()->isFloatingPoint(); } -// canLosslesllyBitCastTo - Return true if this type can be converted to -// 'Ty' without any reinterpretation of bits. For example, uint to int. +// canLosslesslyBitCastTo - Return true if this type can be converted to +// 'Ty' without any reinterpretation of bits. For example, i8* to i32*. // bool Type::canLosslesslyBitCastTo(const Type *Ty) const { // Identity cast means no change so return true @@ -102,10 +164,10 @@ bool Type::canLosslesslyBitCastTo(const Type *Ty) const { if (!this->isFirstClassType() || !Ty->isFirstClassType()) return false; - // Packed -> Packed conversions are always lossless if the two packed types + // Vector -> Vector conversions are always lossless if the two vector types // have the same size, otherwise not. - if (const PackedType *thisPTy = dyn_cast(this)) - if (const PackedType *thatPTy = dyn_cast(Ty)) + if (const VectorType *thisPTy = dyn_cast(this)) + if (const VectorType *thatPTy = dyn_cast(Ty)) return thisPTy->getBitWidth() == thatPTy->getBitWidth(); // At this point we have only various mismatches of the first class types @@ -120,20 +182,48 @@ unsigned Type::getPrimitiveSizeInBits() const { switch (getTypeID()) { case Type::FloatTyID: return 32; case Type::DoubleTyID: return 64; + case Type::X86_FP80TyID: return 80; + case Type::FP128TyID: return 128; + case Type::PPC_FP128TyID: return 128; case Type::IntegerTyID: return cast(this)->getBitWidth(); - case Type::PackedTyID: return cast(this)->getBitWidth(); + case Type::VectorTyID: return cast(this)->getBitWidth(); default: return 0; } } +/// getScalarSizeInBits - If this is a vector type, return the +/// getPrimitiveSizeInBits value for the element type. Otherwise return the +/// getPrimitiveSizeInBits value for this type. +unsigned Type::getScalarSizeInBits() const { + return getScalarType()->getPrimitiveSizeInBits(); +} + +/// getFPMantissaWidth - Return the width of the mantissa of this type. This +/// is only valid on floating point types. If the FP type does not +/// have a stable mantissa (e.g. ppc long double), this method returns -1. +int Type::getFPMantissaWidth() const { + if (const VectorType *VTy = dyn_cast(this)) + return VTy->getElementType()->getFPMantissaWidth(); + assert(isFloatingPoint() && "Not a floating point type!"); + if (ID == FloatTyID) return 24; + if (ID == DoubleTyID) return 53; + if (ID == X86_FP80TyID) return 64; + if (ID == FP128TyID) return 113; + assert(ID == PPC_FP128TyID && "unknown fp type"); + return -1; +} + /// isSizedDerivedType - Derived types like structures and arrays are sized /// iff all of the members of the type are sized as well. Since asking for /// their size is relatively uncommon, move this operation out of line. bool Type::isSizedDerivedType() const { + if (isa(this)) + return true; + if (const ArrayType *ATy = dyn_cast(this)) return ATy->getElementType()->isSized(); - if (const PackedType *PTy = dyn_cast(this)) + if (const VectorType *PTy = dyn_cast(this)) return PTy->getElementType()->isSized(); if (!isa(this)) @@ -179,142 +269,14 @@ void Type::typeBecameConcrete(const DerivedType *AbsTy) { } -// getTypeDescription - This is a recursive function that walks a type hierarchy -// calculating the description for a type. -// -static std::string getTypeDescription(const Type *Ty, - std::vector &TypeStack) { - if (isa(Ty)) { // Base case for the recursion - std::map::iterator I = - AbstractTypeDescriptions->lower_bound(Ty); - if (I != AbstractTypeDescriptions->end() && I->first == Ty) - return I->second; - std::string Desc = "opaque"; - AbstractTypeDescriptions->insert(std::make_pair(Ty, Desc)); - return Desc; - } - - if (!Ty->isAbstract()) { // Base case for the recursion - std::map::iterator I = - ConcreteTypeDescriptions->find(Ty); - if (I != ConcreteTypeDescriptions->end()) return I->second; - } - - // Check to see if the Type is already on the stack... - unsigned Slot = 0, CurSize = TypeStack.size(); - while (Slot < CurSize && TypeStack[Slot] != Ty) ++Slot; // Scan for type - - // This is another base case for the recursion. In this case, we know - // that we have looped back to a type that we have previously visited. - // Generate the appropriate upreference to handle this. - // - if (Slot < CurSize) - return "\\" + utostr(CurSize-Slot); // Here's the upreference - - // Recursive case: derived types... - std::string Result; - TypeStack.push_back(Ty); // Add us to the stack.. - - switch (Ty->getTypeID()) { - case Type::IntegerTyID: { - const IntegerType *ITy = cast(Ty); - if (ITy->getBitWidth() == 1) - Result = "bool"; // FIXME: eventually this becomes i1 - else - Result = "i" + utostr(ITy->getBitWidth()); - break; - } - case Type::FunctionTyID: { - const FunctionType *FTy = cast(Ty); - if (!Result.empty()) - Result += " "; - Result += getTypeDescription(FTy->getReturnType(), TypeStack) + " ("; - unsigned Idx = 1; - for (FunctionType::param_iterator I = FTy->param_begin(), - E = FTy->param_end(); I != E; ++I) { - if (I != FTy->param_begin()) - Result += ", "; - Result += FunctionType::getParamAttrsText(FTy->getParamAttrs(Idx)); - Idx++; - Result += getTypeDescription(*I, TypeStack); - } - if (FTy->isVarArg()) { - if (FTy->getNumParams()) Result += ", "; - Result += "..."; - } - Result += ")"; - if (FTy->getParamAttrs(0)) { - Result += " " + FunctionType::getParamAttrsText(FTy->getParamAttrs(0)); - } - break; - } - case Type::PackedStructTyID: - case Type::StructTyID: { - const StructType *STy = cast(Ty); - if (STy->isPacked()) - Result = "<{ "; - else - Result = "{ "; - for (StructType::element_iterator I = STy->element_begin(), - E = STy->element_end(); I != E; ++I) { - if (I != STy->element_begin()) - Result += ", "; - Result += getTypeDescription(*I, TypeStack); - } - Result += " }"; - if (STy->isPacked()) - Result += ">"; - break; - } - case Type::PointerTyID: { - const PointerType *PTy = cast(Ty); - Result = getTypeDescription(PTy->getElementType(), TypeStack) + " *"; - break; - } - case Type::ArrayTyID: { - const ArrayType *ATy = cast(Ty); - unsigned NumElements = ATy->getNumElements(); - Result = "["; - Result += utostr(NumElements) + " x "; - Result += getTypeDescription(ATy->getElementType(), TypeStack) + "]"; - break; - } - case Type::PackedTyID: { - const PackedType *PTy = cast(Ty); - unsigned NumElements = PTy->getNumElements(); - Result = "<"; - Result += utostr(NumElements) + " x "; - Result += getTypeDescription(PTy->getElementType(), TypeStack) + ">"; - break; - } - default: - Result = ""; - assert(0 && "Unhandled type in getTypeDescription!"); - } - - TypeStack.pop_back(); // Remove self from stack... - - return Result; -} - - - -static const std::string &getOrCreateDesc(std::map&Map, - const Type *Ty) { - std::map::iterator I = Map.find(Ty); - if (I != Map.end()) return I->second; - - std::vector TypeStack; - std::string Result = getTypeDescription(Ty, TypeStack); - return Map[Ty] = Result; -} - - -const std::string &Type::getDescription() const { - if (isAbstract()) - return getOrCreateDesc(*AbstractTypeDescriptions, this); - else - return getOrCreateDesc(*ConcreteTypeDescriptions, this); +std::string Type::getDescription() const { + TypePrinting &Map = + isAbstract() ? *AbstractTypeDescriptions : *ConcreteTypeDescriptions; + + std::string DescStr; + raw_string_ostream DescOS(DescStr); + Map.print(this, DescOS); + return DescOS.str(); } @@ -322,16 +284,24 @@ bool StructType::indexValid(const Value *V) const { // Structure indexes require 32-bit integer constants. if (V->getType() == Type::Int32Ty) if (const ConstantInt *CU = dyn_cast(V)) - return CU->getZExtValue() < ContainedTys.size(); + return indexValid(CU->getZExtValue()); return false; } +bool StructType::indexValid(unsigned V) const { + return V < NumContainedTys; +} + // getTypeAtIndex - Given an index value into the type, return the type of the // element. For a structure type, this must be a constant value... // const Type *StructType::getTypeAtIndex(const Value *V) const { - assert(indexValid(V) && "Invalid structure index!"); unsigned Idx = (unsigned)cast(V)->getZExtValue(); + return getTypeAtIndex(Idx); +} + +const Type *StructType::getTypeAtIndex(unsigned Idx) const { + assert(indexValid(Idx) && "Invalid structure index!"); return ContainedTys[Idx]; } @@ -339,78 +309,99 @@ const Type *StructType::getTypeAtIndex(const Value *V) const { // Primitive 'Type' data //===----------------------------------------------------------------------===// -#define DeclarePrimType(TY, Str) \ - namespace { \ - struct VISIBILITY_HIDDEN TY##Type : public Type { \ - TY##Type() : Type(Str, Type::TY##TyID) {} \ - }; \ - } \ - static ManagedStatic The##TY##Ty; \ - const Type *Type::TY##Ty = &*The##TY##Ty - -#define DeclareIntegerType(TY, BitWidth) \ - namespace { \ - struct VISIBILITY_HIDDEN TY##Type : public IntegerType { \ - TY##Type() : IntegerType(BitWidth) {} \ - }; \ - } \ - static ManagedStatic The##TY##Ty; \ - const Type *Type::TY##Ty = &*The##TY##Ty - -DeclarePrimType(Void, "void"); -DeclarePrimType(Float, "float"); -DeclarePrimType(Double, "double"); -DeclarePrimType(Label, "label"); -DeclareIntegerType(Int1, 1); -DeclareIntegerType(Int8, 8); -DeclareIntegerType(Int16, 16); -DeclareIntegerType(Int32, 32); -DeclareIntegerType(Int64, 64); -#undef DeclarePrimType - +const Type *Type::VoidTy = new Type(Type::VoidTyID); +const Type *Type::FloatTy = new Type(Type::FloatTyID); +const Type *Type::DoubleTy = new Type(Type::DoubleTyID); +const Type *Type::X86_FP80Ty = new Type(Type::X86_FP80TyID); +const Type *Type::FP128Ty = new Type(Type::FP128TyID); +const Type *Type::PPC_FP128Ty = new Type(Type::PPC_FP128TyID); +const Type *Type::LabelTy = new Type(Type::LabelTyID); +const Type *Type::MetadataTy = new Type(Type::MetadataTyID); + +namespace { + struct BuiltinIntegerType : public IntegerType { + explicit BuiltinIntegerType(unsigned W) : IntegerType(W) {} + }; +} +const IntegerType *Type::Int1Ty = new BuiltinIntegerType(1); +const IntegerType *Type::Int8Ty = new BuiltinIntegerType(8); +const IntegerType *Type::Int16Ty = new BuiltinIntegerType(16); +const IntegerType *Type::Int32Ty = new BuiltinIntegerType(32); +const IntegerType *Type::Int64Ty = new BuiltinIntegerType(64); //===----------------------------------------------------------------------===// // Derived Type Constructors //===----------------------------------------------------------------------===// +/// isValidReturnType - Return true if the specified type is valid as a return +/// type. +bool FunctionType::isValidReturnType(const Type *RetTy) { + if (RetTy->isFirstClassType()) { + if (const PointerType *PTy = dyn_cast(RetTy)) + return PTy->getElementType() != Type::MetadataTy; + return true; + } + if (RetTy == Type::VoidTy || RetTy == Type::MetadataTy || + isa(RetTy)) + return true; + + // If this is a multiple return case, verify that each return is a first class + // value and that there is at least one value. + const StructType *SRetTy = dyn_cast(RetTy); + if (SRetTy == 0 || SRetTy->getNumElements() == 0) + return false; + + for (unsigned i = 0, e = SRetTy->getNumElements(); i != e; ++i) + if (!SRetTy->getElementType(i)->isFirstClassType()) + return false; + return true; +} + +/// isValidArgumentType - Return true if the specified type is valid as an +/// argument type. +bool FunctionType::isValidArgumentType(const Type *ArgTy) { + if ((!ArgTy->isFirstClassType() && !isa(ArgTy)) || + (isa(ArgTy) && + cast(ArgTy)->getElementType() == Type::MetadataTy)) + return false; + + return true; +} + FunctionType::FunctionType(const Type *Result, const std::vector &Params, - bool IsVarArgs, const ParamAttrsList &Attrs) + bool IsVarArgs) : DerivedType(FunctionTyID), isVarArgs(IsVarArgs) { - assert((Result->isFirstClassType() || Result == Type::VoidTy || - isa(Result)) && - "LLVM functions cannot return aggregates"); + ContainedTys = reinterpret_cast(this+1); + NumContainedTys = Params.size() + 1; // + 1 for result type + assert(isValidReturnType(Result) && "invalid return type for function"); + + bool isAbstract = Result->isAbstract(); - ContainedTys.reserve(Params.size()+1); - ContainedTys.push_back(PATypeHandle(Result, this)); + new (&ContainedTys[0]) PATypeHandle(Result, this); for (unsigned i = 0; i != Params.size(); ++i) { - assert((Params[i]->isFirstClassType() || isa(Params[i])) && - "Function arguments must be value types!"); - - ContainedTys.push_back(PATypeHandle(Params[i], this)); + assert(isValidArgumentType(Params[i]) && + "Not a valid type for function argument!"); + new (&ContainedTys[i+1]) PATypeHandle(Params[i], this); isAbstract |= Params[i]->isAbstract(); } - // Set the ParameterAttributes - if (!Attrs.empty()) - ParamAttrs = new ParamAttrsList(Attrs); - else - ParamAttrs = 0; - // Calculate whether or not this type is abstract setAbstract(isAbstract); - } StructType::StructType(const std::vector &Types, bool isPacked) : CompositeType(StructTyID) { + ContainedTys = reinterpret_cast(this + 1); + NumContainedTys = Types.size(); setSubclassData(isPacked); - ContainedTys.reserve(Types.size()); bool isAbstract = false; for (unsigned i = 0; i < Types.size(); ++i) { - assert(Types[i] != Type::VoidTy && "Void type for structure field!!"); - ContainedTys.push_back(PATypeHandle(Types[i], this)); + assert(Types[i] && " type for structure field!"); + assert(isValidElementType(Types[i]) && + "Invalid type for structure element!"); + new (&ContainedTys[i]) PATypeHandle(Types[i], this); isAbstract |= Types[i]->isAbstract(); } @@ -426,17 +417,20 @@ ArrayType::ArrayType(const Type *ElType, uint64_t NumEl) setAbstract(ElType->isAbstract()); } -PackedType::PackedType(const Type *ElType, unsigned NumEl) - : SequentialType(PackedTyID, ElType) { +VectorType::VectorType(const Type *ElType, unsigned NumEl) + : SequentialType(VectorTyID, ElType) { NumElements = NumEl; + setAbstract(ElType->isAbstract()); + assert(NumEl > 0 && "NumEl of a VectorType must be greater than 0"); + assert(isValidElementType(ElType) && + "Elements of a VectorType must be a primitive type"); - assert(NumEl > 0 && "NumEl of a PackedType must be greater than 0"); - assert((ElType->isIntegral() || ElType->isFloatingPoint()) && - "Elements of a PackedType must be a primitive type"); } -PointerType::PointerType(const Type *E) : SequentialType(PointerTyID, E) { +PointerType::PointerType(const Type *E, unsigned AddrSpace) + : SequentialType(PointerTyID, E) { + AddressSpace = AddrSpace; // Calculate whether or not this type is abstract setAbstract(E->isAbstract()); } @@ -448,26 +442,31 @@ OpaqueType::OpaqueType() : DerivedType(OpaqueTyID) { #endif } +void PATypeHolder::destroy() { + Ty = 0; +} + // dropAllTypeUses - When this (abstract) type is resolved to be equal to // another (more concrete) type, we must eliminate all references to other // types, to avoid some circular reference problems. void DerivedType::dropAllTypeUses() { - if (!ContainedTys.empty()) { + if (NumContainedTys != 0) { // The type must stay abstract. To do this, we insert a pointer to a type // that will never get resolved, thus will always be abstract. static Type *AlwaysOpaqueTy = OpaqueType::get(); static PATypeHolder Holder(AlwaysOpaqueTy); ContainedTys[0] = AlwaysOpaqueTy; - // Change the rest of the types to be intty's. It doesn't matter what we + // Change the rest of the types to be Int32Ty's. It doesn't matter what we // pick so long as it doesn't point back to this type. We choose something // concrete to avoid overhead for adding to AbstracTypeUser lists and stuff. - for (unsigned i = 1, e = ContainedTys.size(); i != e; ++i) + for (unsigned i = 1, e = NumContainedTys; i != e; ++i) ContainedTys[i] = Type::Int32Ty; } } +namespace { /// TypePromotionGraph and graph traits - this is designed to allow us to do /// efficient SCC processing of type graphs. This is the exact same as @@ -478,6 +477,8 @@ struct TypePromotionGraph { TypePromotionGraph(Type *T) : Ty(T) {} }; +} + namespace llvm { template <> struct GraphTraits { typedef Type NodeType; @@ -562,8 +563,8 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, if (isa(Ty)) return false; // Two unequal opaque types are never equal - std::map::iterator It = EqTypes.lower_bound(Ty); - if (It != EqTypes.end() && It->first == Ty) + std::map::iterator It = EqTypes.find(Ty); + if (It != EqTypes.end()) return It->second == Ty2; // Looping back on a type, check for equality // Otherwise, add the mapping to the table to make sure we don't get @@ -578,8 +579,9 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, const IntegerType *ITy2 = cast(Ty2); return ITy->getBitWidth() == ITy2->getBitWidth(); } else if (const PointerType *PTy = dyn_cast(Ty)) { - return TypesEqual(PTy->getElementType(), - cast(Ty2)->getElementType(), EqTypes); + const PointerType *PTy2 = cast(Ty2); + return PTy->getAddressSpace() == PTy2->getAddressSpace() && + TypesEqual(PTy->getElementType(), PTy2->getElementType(), EqTypes); } else if (const StructType *STy = dyn_cast(Ty)) { const StructType *STy2 = cast(Ty2); if (STy->getNumElements() != STy2->getNumElements()) return false; @@ -592,21 +594,17 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, const ArrayType *ATy2 = cast(Ty2); return ATy->getNumElements() == ATy2->getNumElements() && TypesEqual(ATy->getElementType(), ATy2->getElementType(), EqTypes); - } else if (const PackedType *PTy = dyn_cast(Ty)) { - const PackedType *PTy2 = cast(Ty2); + } else if (const VectorType *PTy = dyn_cast(Ty)) { + const VectorType *PTy2 = cast(Ty2); return PTy->getNumElements() == PTy2->getNumElements() && TypesEqual(PTy->getElementType(), PTy2->getElementType(), EqTypes); } else if (const FunctionType *FTy = dyn_cast(Ty)) { const FunctionType *FTy2 = cast(Ty2); if (FTy->isVarArg() != FTy2->isVarArg() || FTy->getNumParams() != FTy2->getNumParams() || - FTy->getNumAttrs() != FTy2->getNumAttrs() || - FTy->getParamAttrs(0) != FTy2->getParamAttrs(0) || !TypesEqual(FTy->getReturnType(), FTy2->getReturnType(), EqTypes)) return false; for (unsigned i = 0, e = FTy2->getNumParams(); i != e; ++i) { - if (FTy->getParamAttrs(i+1) != FTy->getParamAttrs(i+1)) - return false; if (!TypesEqual(FTy->getParamType(i), FTy2->getParamType(i), EqTypes)) return false; } @@ -627,11 +625,11 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2) { // ever reach a non-abstract type, we know that we don't need to search the // subgraph. static bool AbstractTypeHasCycleThrough(const Type *TargetTy, const Type *CurTy, - std::set &VisitedTypes) { + SmallPtrSet &VisitedTypes) { if (TargetTy == CurTy) return true; if (!CurTy->isAbstract()) return false; - if (!VisitedTypes.insert(CurTy).second) + if (!VisitedTypes.insert(CurTy)) return false; // Already been here. for (Type::subtype_iterator I = CurTy->subtype_begin(), @@ -642,10 +640,10 @@ static bool AbstractTypeHasCycleThrough(const Type *TargetTy, const Type *CurTy, } static bool ConcreteTypeHasCycleThrough(const Type *TargetTy, const Type *CurTy, - std::set &VisitedTypes) { + SmallPtrSet &VisitedTypes) { if (TargetTy == CurTy) return true; - if (!VisitedTypes.insert(CurTy).second) + if (!VisitedTypes.insert(CurTy)) return false; // Already been here. for (Type::subtype_iterator I = CurTy->subtype_begin(), @@ -658,7 +656,7 @@ static bool ConcreteTypeHasCycleThrough(const Type *TargetTy, const Type *CurTy, /// TypeHasCycleThroughItself - Return true if the specified type has a cycle /// back to itself. static bool TypeHasCycleThroughItself(const Type *Ty) { - std::set VisitedTypes; + SmallPtrSet VisitedTypes; if (Ty->isAbstract()) { // Optimized case for abstract types. for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end(); @@ -698,12 +696,15 @@ static unsigned getSubElementHash(const Type *Ty) { case Type::ArrayTyID: HashVal ^= cast(SubTy)->getNumElements(); break; - case Type::PackedTyID: - HashVal ^= cast(SubTy)->getNumElements(); + case Type::VectorTyID: + HashVal ^= cast(SubTy)->getNumElements(); break; case Type::StructTyID: HashVal ^= cast(SubTy)->getNumElements(); break; + case Type::PointerTyID: + HashVal ^= cast(SubTy)->getAddressSpace(); + break; } } return HashVal ? HashVal : 1; // Do not return zero unless opaque subty. @@ -723,6 +724,27 @@ protected: std::multimap TypesByHash; public: + ~TypeMapBase() { + // PATypeHolder won't destroy non-abstract types. + // We can't destroy them by simply iterating, because + // they may contain references to each-other. +#if 0 + for (std::multimap::iterator I + = TypesByHash.begin(), E = TypesByHash.end(); I != E; ++I) { + Type *Ty = const_cast(I->second.Ty); + I->second.destroy(); + // We can't invoke destroy or delete, because the type may + // contain references to already freed types. + // So we have to destruct the object the ugly way. + if (Ty) { + Ty->AbstractTypeUsers.clear(); + static_cast(Ty)->Type::~Type(); + operator delete(Ty); + } + } +#endif + } + void RemoveFromTypesByHash(unsigned Hash, const Type *Ty) { std::multimap::iterator I = TypesByHash.lower_bound(Hash); @@ -786,15 +808,7 @@ public: print("add"); } - void clear(std::vector &DerivedTypes) { - for (typename std::map::iterator I = Map.begin(), - E = Map.end(); I != E; ++I) - DerivedTypes.push_back(I->second.get()); - TypesByHash.clear(); - Map.clear(); - } - - /// RefineAbstractType - This method is called after we have merged a type + /// RefineAbstractType - This method is called after we have merged a type /// with another one. We must now either merge the type away with /// some other type or reinstall it in the map with it's new configuration. void RefineAbstractType(TypeClass *Ty, const DerivedType *OldType, @@ -816,14 +830,14 @@ public: // The old record is now out-of-date, because one of the children has been // updated. Remove the obsolete entry from the map. unsigned NumErased = Map.erase(ValType::get(Ty)); - assert(NumErased && "Element not found!"); + assert(NumErased && "Element not found!"); NumErased = NumErased; // Remember the structural hash for the type before we start hacking on it, // in case we need it later. unsigned OldTypeHash = ValType::hashTypeStructure(Ty); // Find the type element we are refining... and change it now! - for (unsigned i = 0, e = Ty->ContainedTys.size(); i != e; ++i) + for (unsigned i = 0, e = Ty->getNumContainedTypes(); i != e; ++i) if (Ty->ContainedTys[i] == OldType) Ty->ContainedTys[i] = NewType; unsigned NewTypeHash = ValType::hashTypeStructure(Ty); @@ -843,7 +857,7 @@ public: // We already have this type in the table. Get rid of the newly refined // type. TypeClass *NewTy = cast((Type*)I->second.get()); - Ty->refineAbstractTypeTo(NewTy); + Ty->unlockedRefineAbstractTypeTo(NewTy); return; } } else { @@ -879,7 +893,7 @@ public: } TypesByHash.erase(Entry); } - Ty->refineAbstractTypeTo(NewTy); + Ty->unlockedRefineAbstractTypeTo(NewTy); return; } } @@ -929,7 +943,7 @@ public: // namespace llvm { class IntegerValType { - uint16_t bits; + uint32_t bits; public: IntegerValType(uint16_t numbits) : bits(numbits) {} @@ -963,50 +977,71 @@ const IntegerType *IntegerType::get(unsigned NumBits) { default: break; } - + IntegerValType IVT(NumBits); - IntegerType *ITy = IntegerTypes->get(IVT); - if (ITy) return ITy; // Found a match, return it! - - // Value not found. Derive a new type! - ITy = new IntegerType(NumBits); - IntegerTypes->add(IVT, ITy); + IntegerType *ITy = 0; + if (llvm_is_multithreaded()) { + // First, see if the type is already in the table, for which + // a reader lock suffices. + TypeMapLock->reader_acquire(); + ITy = IntegerTypes->get(IVT); + TypeMapLock->reader_release(); + + if (!ITy) { + // OK, not in the table, get a writer lock. + TypeMapLock->writer_acquire(); + ITy = IntegerTypes->get(IVT); + + // We need to _recheck_ the table in case someone + // put it in between when we released the reader lock + // and when we gained the writer lock! + if (!ITy) { + // Value not found. Derive a new type! + ITy = new IntegerType(NumBits); + IntegerTypes->add(IVT, ITy); + } + + TypeMapLock->writer_release(); + } + } else { + ITy = IntegerTypes->get(IVT); + if (ITy) return ITy; // Found a match, return it! + // Value not found. Derive a new type! + ITy = new IntegerType(NumBits); + IntegerTypes->add(IVT, ITy); + } #ifdef DEBUG_MERGE_TYPES DOUT << "Derived new type: " << *ITy << "\n"; #endif return ITy; } +bool IntegerType::isPowerOf2ByteWidth() const { + unsigned BitWidth = getBitWidth(); + return (BitWidth > 7) && isPowerOf2_32(BitWidth); +} + +APInt IntegerType::getMask() const { + return APInt::getAllOnesValue(getBitWidth()); +} + // FunctionValType - Define a class to hold the key that goes into the TypeMap // namespace llvm { class FunctionValType { const Type *RetTy; std::vector ArgTypes; - std::vector ParamAttrs; bool isVarArg; public: FunctionValType(const Type *ret, const std::vector &args, - bool IVA, const FunctionType::ParamAttrsList &attrs) - : RetTy(ret), isVarArg(IVA) { - for (unsigned i = 0; i < args.size(); ++i) - ArgTypes.push_back(args[i]); - for (unsigned i = 0; i < attrs.size(); ++i) - ParamAttrs.push_back(attrs[i]); - } + bool isVA) : RetTy(ret), ArgTypes(args), isVarArg(isVA) {} static FunctionValType get(const FunctionType *FT); static unsigned hashTypeStructure(const FunctionType *FT) { - return FT->getNumParams()*64+FT->getNumAttrs()*2+FT->isVarArg(); - } - - // Subclass should override this... to update self as usual - 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; + unsigned Result = FT->getNumParams()*2 + FT->isVarArg(); + return Result; } inline bool operator<(const FunctionValType &MTV) const { @@ -1015,7 +1050,8 @@ public: if (isVarArg < MTV.isVarArg) return true; if (isVarArg > MTV.isVarArg) return false; if (ArgTypes < MTV.ArgTypes) return true; - return ArgTypes == MTV.ArgTypes && ParamAttrs < MTV.ParamAttrs; + if (ArgTypes > MTV.ArgTypes) return false; + return false; } }; } @@ -1026,63 +1062,55 @@ static ManagedStatic > FunctionTypes; FunctionValType FunctionValType::get(const FunctionType *FT) { // Build up a FunctionValType std::vector ParamTypes; - std::vector ParamAttrs; ParamTypes.reserve(FT->getNumParams()); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) ParamTypes.push_back(FT->getParamType(i)); - for (unsigned i = 0, e = FT->getNumAttrs(); i != e; ++i) - ParamAttrs.push_back(FT->getParamAttrs(i)); - return FunctionValType(FT->getReturnType(), ParamTypes, FT->isVarArg(), - ParamAttrs); + return FunctionValType(FT->getReturnType(), ParamTypes, FT->isVarArg()); } // FunctionType::get - The factory function for the FunctionType class... FunctionType *FunctionType::get(const Type *ReturnType, const std::vector &Params, - bool isVarArg, - const std::vector &Attrs) { - bool noAttrs = true; - for (unsigned i = 0, e = Attrs.size(); i < e; ++i) - if (Attrs[i] != FunctionType::NoAttributeSet) { - noAttrs = false; - break; + bool isVarArg) { + FunctionValType VT(ReturnType, Params, isVarArg); + FunctionType *FT = 0; + + if (llvm_is_multithreaded()) { + TypeMapLock->reader_acquire(); + FT = FunctionTypes->get(VT); + TypeMapLock->reader_release(); + + if (!FT) { + TypeMapLock->writer_acquire(); + + // Have to check again here, because it might have + // been inserted between when we release the reader + // lock and when we acquired the writer lock. + FT = FunctionTypes->get(VT); + if (!FT) { + FT = (FunctionType*) operator new(sizeof(FunctionType) + + sizeof(PATypeHandle)*(Params.size()+1)); + new (FT) FunctionType(ReturnType, Params, isVarArg); + FunctionTypes->add(VT, FT); + } + TypeMapLock->writer_release(); } - const std::vector NullAttrs; - const std::vector *TheAttrs = &Attrs; - if (noAttrs) - TheAttrs = &NullAttrs; - FunctionValType VT(ReturnType, Params, isVarArg, *TheAttrs); - FunctionType *MT = FunctionTypes->get(VT); - if (MT) return MT; - - MT = new FunctionType(ReturnType, Params, isVarArg, *TheAttrs); - FunctionTypes->add(VT, MT); - + } else { + FT = FunctionTypes->get(VT); + if (FT) + return FT; + + FT = (FunctionType*) operator new(sizeof(FunctionType) + + sizeof(PATypeHandle)*(Params.size()+1)); + new (FT) FunctionType(ReturnType, Params, isVarArg); + FunctionTypes->add(VT, FT); + } + #ifdef DEBUG_MERGE_TYPES - DOUT << "Derived new type: " << MT << "\n"; + DOUT << "Derived new type: " << FT << "\n"; #endif - return MT; -} - -FunctionType::ParameterAttributes -FunctionType::getParamAttrs(unsigned Idx) const { - if (!ParamAttrs) - return NoAttributeSet; - if (Idx >= ParamAttrs->size()) - return NoAttributeSet; - return (*ParamAttrs)[Idx]; -} - -std::string FunctionType::getParamAttrsText(ParameterAttributes Attr) { - std::string Result; - if (Attr & ZExtAttribute) - Result += "zext "; - if (Attr & SExtAttribute) - Result += "sext "; - if (Attr & NoReturnAttribute) - Result += "noreturn "; - return Result; + return FT; } //===----------------------------------------------------------------------===// @@ -1103,88 +1131,132 @@ public: return (unsigned)AT->getNumElements(); } - // Subclass should override this... to update self as usual - void doRefinement(const DerivedType *OldType, const Type *NewType) { - assert(ValTy == OldType); - ValTy = NewType; - } - inline bool operator<(const ArrayValType &MTV) const { if (Size < MTV.Size) return true; return Size == MTV.Size && ValTy < MTV.ValTy; } }; } -static ManagedStatic > ArrayTypes; +static ManagedStatic > ArrayTypes; ArrayType *ArrayType::get(const Type *ElementType, uint64_t NumElements) { - assert(ElementType && "Can't get array of null types!"); + assert(ElementType && "Can't get array of types!"); + assert(isValidElementType(ElementType) && "Invalid type for array element!"); ArrayValType AVT(ElementType, NumElements); - ArrayType *AT = ArrayTypes->get(AVT); - if (AT) return AT; // Found a match, return it! - - // Value not found. Derive a new type! - ArrayTypes->add(AVT, AT = new ArrayType(ElementType, NumElements)); - + ArrayType *AT = 0; + + if (llvm_is_multithreaded()) { + TypeMapLock->reader_acquire(); + AT = ArrayTypes->get(AVT); + TypeMapLock->reader_release(); + + if (!AT) { + TypeMapLock->writer_acquire(); + + // Recheck. Might have changed between release and acquire. + AT = ArrayTypes->get(AVT); + if (!AT) { + // Value not found. Derive a new type! + ArrayTypes->add(AVT, AT = new ArrayType(ElementType, NumElements)); + } + TypeMapLock->writer_release(); + } + } else { + AT = ArrayTypes->get(AVT); + if (AT) return AT; // Found a match, return it! + + // Value not found. Derive a new type! + ArrayTypes->add(AVT, AT = new ArrayType(ElementType, NumElements)); + } #ifdef DEBUG_MERGE_TYPES DOUT << "Derived new type: " << *AT << "\n"; #endif return AT; } +bool ArrayType::isValidElementType(const Type *ElemTy) { + if (ElemTy == Type::VoidTy || ElemTy == Type::LabelTy || + ElemTy == Type::MetadataTy) + return false; + + if (const PointerType *PTy = dyn_cast(ElemTy)) + if (PTy->getElementType() == Type::MetadataTy) + return false; + + return true; +} + //===----------------------------------------------------------------------===// -// Packed Type Factory... +// Vector Type Factory... // namespace llvm { -class PackedValType { +class VectorValType { const Type *ValTy; unsigned Size; public: - PackedValType(const Type *val, int sz) : ValTy(val), Size(sz) {} + VectorValType(const Type *val, int sz) : ValTy(val), Size(sz) {} - static PackedValType get(const PackedType *PT) { - return PackedValType(PT->getElementType(), PT->getNumElements()); + static VectorValType get(const VectorType *PT) { + return VectorValType(PT->getElementType(), PT->getNumElements()); } - static unsigned hashTypeStructure(const PackedType *PT) { + static unsigned hashTypeStructure(const VectorType *PT) { return PT->getNumElements(); } - // Subclass should override this... to update self as usual - void doRefinement(const DerivedType *OldType, const Type *NewType) { - assert(ValTy == OldType); - ValTy = NewType; - } - - inline bool operator<(const PackedValType &MTV) const { + inline bool operator<(const VectorValType &MTV) const { if (Size < MTV.Size) return true; return Size == MTV.Size && ValTy < MTV.ValTy; } }; } -static ManagedStatic > PackedTypes; - -PackedType *PackedType::get(const Type *ElementType, unsigned NumElements) { - assert(ElementType && "Can't get packed of null types!"); - assert(isPowerOf2_32(NumElements) && "Vector length should be a power of 2!"); +static ManagedStatic > VectorTypes; - PackedValType PVT(ElementType, NumElements); - PackedType *PT = PackedTypes->get(PVT); - if (PT) return PT; // Found a match, return it! - - // Value not found. Derive a new type! - PackedTypes->add(PVT, PT = new PackedType(ElementType, NumElements)); +VectorType *VectorType::get(const Type *ElementType, unsigned NumElements) { + assert(ElementType && "Can't get vector of types!"); + VectorValType PVT(ElementType, NumElements); + VectorType *PT = 0; + + if (llvm_is_multithreaded()) { + TypeMapLock->reader_acquire(); + PT = VectorTypes->get(PVT); + TypeMapLock->reader_release(); + + if (!PT) { + TypeMapLock->writer_acquire(); + PT = VectorTypes->get(PVT); + // Recheck. Might have changed between release and acquire. + if (!PT) { + VectorTypes->add(PVT, PT = new VectorType(ElementType, NumElements)); + } + TypeMapLock->writer_acquire(); + } + } else { + PT = VectorTypes->get(PVT); + if (PT) return PT; // Found a match, return it! + + // Value not found. Derive a new type! + VectorTypes->add(PVT, PT = new VectorType(ElementType, NumElements)); + } #ifdef DEBUG_MERGE_TYPES DOUT << "Derived new type: " << *PT << "\n"; #endif return PT; } +bool VectorType::isValidElementType(const Type *ElemTy) { + if (ElemTy->isInteger() || ElemTy->isFloatingPoint() || + isa(ElemTy)) + return true; + + return false; +} + //===----------------------------------------------------------------------===// // Struct Type Factory... // @@ -1212,12 +1284,6 @@ public: return ST->getNumElements(); } - // Subclass should override this... to update self as usual - void doRefinement(const DerivedType *OldType, const Type *NewType) { - for (unsigned i = 0; i < ElTypes.size(); ++i) - if (ElTypes[i] == OldType) ElTypes[i] = NewType; - } - inline bool operator<(const StructValType &STV) const { if (ElTypes < STV.ElTypes) return true; else if (ElTypes > STV.ElTypes) return false; @@ -1231,18 +1297,64 @@ static ManagedStatic > StructTypes; StructType *StructType::get(const std::vector &ETypes, bool isPacked) { StructValType STV(ETypes, isPacked); - StructType *ST = StructTypes->get(STV); - if (ST) return ST; - - // Value not found. Derive a new type! - StructTypes->add(STV, ST = new StructType(ETypes, isPacked)); - + StructType *ST = 0; + + if (llvm_is_multithreaded()) { + TypeMapLock->reader_acquire(); + ST = StructTypes->get(STV); + TypeMapLock->reader_release(); + + if (!ST) { + TypeMapLock->writer_acquire(); + ST = StructTypes->get(STV); + // Recheck. Might have changed between release and acquire. + if (!ST) { + // Value not found. Derive a new type! + ST = (StructType*) operator new(sizeof(StructType) + + sizeof(PATypeHandle) * ETypes.size()); + new (ST) StructType(ETypes, isPacked); + StructTypes->add(STV, ST); + } + TypeMapLock->writer_release(); + } + } else { + ST = StructTypes->get(STV); + if (ST) return ST; + + // Value not found. Derive a new type! + ST = (StructType*) operator new(sizeof(StructType) + + sizeof(PATypeHandle) * ETypes.size()); + new (ST) StructType(ETypes, isPacked); + StructTypes->add(STV, ST); + } #ifdef DEBUG_MERGE_TYPES DOUT << "Derived new type: " << *ST << "\n"; #endif return ST; } +StructType *StructType::get(const Type *type, ...) { + va_list ap; + std::vector StructFields; + va_start(ap, type); + while (type) { + StructFields.push_back(type); + type = va_arg(ap, llvm::Type*); + } + return llvm::StructType::get(StructFields); +} + +bool StructType::isValidElementType(const Type *ElemTy) { + if (ElemTy == Type::VoidTy || ElemTy == Type::LabelTy || + ElemTy == Type::MetadataTy) + return false; + + if (const PointerType *PTy = dyn_cast(ElemTy)) + if (PTy->getElementType() == Type::MetadataTy) + return false; + + return true; +} //===----------------------------------------------------------------------===// @@ -1254,60 +1366,106 @@ StructType *StructType::get(const std::vector &ETypes, namespace llvm { class PointerValType { const Type *ValTy; + unsigned AddressSpace; public: - PointerValType(const Type *val) : ValTy(val) {} + PointerValType(const Type *val, unsigned as) : ValTy(val), AddressSpace(as) {} static PointerValType get(const PointerType *PT) { - return PointerValType(PT->getElementType()); + return PointerValType(PT->getElementType(), PT->getAddressSpace()); } static unsigned hashTypeStructure(const PointerType *PT) { return getSubElementHash(PT); } - // Subclass should override this... to update self as usual - void doRefinement(const DerivedType *OldType, const Type *NewType) { - assert(ValTy == OldType); - ValTy = NewType; - } - bool operator<(const PointerValType &MTV) const { - return ValTy < MTV.ValTy; + if (AddressSpace < MTV.AddressSpace) return true; + return AddressSpace == MTV.AddressSpace && ValTy < MTV.ValTy; } }; } static ManagedStatic > PointerTypes; -PointerType *PointerType::get(const Type *ValueType) { +PointerType *PointerType::get(const Type *ValueType, unsigned AddressSpace) { assert(ValueType && "Can't get a pointer to type!"); assert(ValueType != Type::VoidTy && - "Pointer to void is not valid, use sbyte* instead!"); - assert(ValueType != Type::LabelTy && "Pointer to label is not valid!"); - PointerValType PVT(ValueType); - - PointerType *PT = PointerTypes->get(PVT); - if (PT) return PT; - - // Value not found. Derive a new type! - PointerTypes->add(PVT, PT = new PointerType(ValueType)); + "Pointer to void is not valid, use i8* instead!"); + assert(isValidElementType(ValueType) && "Invalid type for pointer element!"); + PointerValType PVT(ValueType, AddressSpace); + PointerType *PT = 0; + + if (llvm_is_multithreaded()) { + TypeMapLock->reader_acquire(); + PT = PointerTypes->get(PVT); + TypeMapLock->reader_release(); + + if (!PT) { + TypeMapLock->writer_acquire(); + PT = PointerTypes->get(PVT); + // Recheck. Might have changed between release and acquire. + if (!PT) { + // Value not found. Derive a new type! + PointerTypes->add(PVT, PT = new PointerType(ValueType, AddressSpace)); + } + TypeMapLock->writer_release(); + } + } else { + PT = PointerTypes->get(PVT); + if (PT) return PT; + + // Value not found. Derive a new type! + PointerTypes->add(PVT, PT = new PointerType(ValueType, AddressSpace)); + } #ifdef DEBUG_MERGE_TYPES DOUT << "Derived new type: " << *PT << "\n"; #endif return PT; } +PointerType *Type::getPointerTo(unsigned addrs) const { + return PointerType::get(this, addrs); +} + +bool PointerType::isValidElementType(const Type *ElemTy) { + if (ElemTy == Type::VoidTy || ElemTy == Type::LabelTy) + return false; + + if (const PointerType *PTy = dyn_cast(ElemTy)) + if (PTy->getElementType() == Type::MetadataTy) + return false; + + return true; +} + + //===----------------------------------------------------------------------===// // Derived Type Refinement Functions //===----------------------------------------------------------------------===// +// addAbstractTypeUser - Notify an abstract type that there is a new user of +// it. This function is called primarily by the PATypeHandle class. +void Type::addAbstractTypeUser(AbstractTypeUser *U) const { + assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!"); + if (llvm_is_multithreaded()) { + AbstractTypeUsersLock->acquire(); + AbstractTypeUsers.push_back(U); + AbstractTypeUsersLock->release(); + } else { + AbstractTypeUsers.push_back(U); + } +} + + // removeAbstractTypeUser - Notify an abstract type that a user of the class // no longer has a handle to the type. This function is called primarily by // the PATypeHandle class. When there are no users of the abstract type, it // is annihilated, because there is no way to get a reference to it ever again. // void Type::removeAbstractTypeUser(AbstractTypeUser *U) const { + if (llvm_is_multithreaded()) AbstractTypeUsersLock->acquire(); + // Search from back to front because we will notify users from back to // front. Also, it is likely that there will be a stack like behavior to // users that register and unregister users. @@ -1331,23 +1489,27 @@ void Type::removeAbstractTypeUser(AbstractTypeUser *U) const { DOUT << "DELETEing unused abstract type: <" << *this << ">[" << (void*)this << "]" << "\n"; #endif - delete this; // No users of this abstract type! + + this->destroy(); } + + if (llvm_is_multithreaded()) AbstractTypeUsersLock->release(); } - -// refineAbstractTypeTo - This function is used when it is discovered that -// the 'this' abstract type is actually equivalent to the NewType specified. -// This causes all users of 'this' to switch to reference the more concrete type -// NewType and for 'this' to be deleted. +// unlockedRefineAbstractTypeTo - This function is used when it is discovered +// that the 'this' abstract type is actually equivalent to the NewType +// specified. This causes all users of 'this' to switch to reference the more +// concrete type NewType and for 'this' to be deleted. Only used for internal +// callers. // -void DerivedType::refineAbstractTypeTo(const Type *NewType) { +void DerivedType::unlockedRefineAbstractTypeTo(const Type *NewType) { 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(); + if (AbstractTypeDescriptions.isConstructed()) + AbstractTypeDescriptions->clear(); #ifdef DEBUG_MERGE_TYPES DOUT << "REFINING abstract type [" << (void*)this << " " @@ -1359,8 +1521,7 @@ void DerivedType::refineAbstractTypeTo(const Type *NewType) { // refined, that we will not continue using a dead reference... // PATypeHolder NewTy(NewType); - - // Any PATypeHolders referring to this type will now automatically forward to + // Any PATypeHolders referring to this type will now automatically forward o // the type we are resolved to. ForwardType = NewType; if (NewType->isAbstract()) @@ -1383,10 +1544,11 @@ void DerivedType::refineAbstractTypeTo(const Type *NewType) { // will not cause users to drop off of the use list. If we resolve to ourself // we succeed! // + if (llvm_is_multithreaded()) AbstractTypeUsersLock->acquire(); while (!AbstractTypeUsers.empty() && NewTy != this) { AbstractTypeUser *User = AbstractTypeUsers.back(); - unsigned OldSize = AbstractTypeUsers.size(); + unsigned OldSize = AbstractTypeUsers.size(); OldSize=OldSize; #ifdef DEBUG_MERGE_TYPES DOUT << " REFINING user " << OldSize-1 << "[" << (void*)User << "] of abstract type [" << (void*)this << " " @@ -1398,6 +1560,7 @@ void DerivedType::refineAbstractTypeTo(const Type *NewType) { assert(AbstractTypeUsers.size() != OldSize && "AbsTyUser did not remove self from user list!"); } + if (llvm_is_multithreaded()) AbstractTypeUsersLock->release(); // If we were successful removing all users from the type, 'this' will be // deleted when the last PATypeHolder is destroyed or updated from this type. @@ -1405,6 +1568,21 @@ void DerivedType::refineAbstractTypeTo(const Type *NewType) { // destroyed. } +// refineAbstractTypeTo - This function is used by external callers to notify +// us that this abstract type is equivalent to another type. +// +void DerivedType::refineAbstractTypeTo(const Type *NewType) { + if (llvm_is_multithreaded()) { + // All recursive calls will go through unlockedRefineAbstractTypeTo, + // to avoid deadlock problems. + TypeMapLock->writer_acquire(); + unlockedRefineAbstractTypeTo(NewType); + TypeMapLock->writer_release(); + } else { + unlockedRefineAbstractTypeTo(NewType); + } +} + // notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type that // the current type has transitioned from being abstract to being concrete. // @@ -1413,7 +1591,8 @@ void DerivedType::notifyUsesThatTypeBecameConcrete() { DOUT << "typeIsREFINED type: " << (void*)this << " " << *this << "\n"; #endif - unsigned OldSize = AbstractTypeUsers.size(); + if (llvm_is_multithreaded()) AbstractTypeUsersLock->acquire(); + unsigned OldSize = AbstractTypeUsers.size(); OldSize=OldSize; while (!AbstractTypeUsers.empty()) { AbstractTypeUser *ATU = AbstractTypeUsers.back(); ATU->typeBecameConcrete(this); @@ -1421,6 +1600,7 @@ void DerivedType::notifyUsesThatTypeBecameConcrete() { assert(AbstractTypeUsers.size() < OldSize-- && "AbstractTypeUser did not remove itself from the use list!"); } + if (llvm_is_multithreaded()) AbstractTypeUsersLock->release(); } // refineAbstractType - Called when a contained type is found to be more @@ -1454,13 +1634,13 @@ void ArrayType::typeBecameConcrete(const DerivedType *AbsTy) { // concrete - this could potentially change us from an abstract type to a // concrete type. // -void PackedType::refineAbstractType(const DerivedType *OldType, +void VectorType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { - PackedTypes->RefineAbstractType(this, OldType, NewType); + VectorTypes->RefineAbstractType(this, OldType, NewType); } -void PackedType::typeBecameConcrete(const DerivedType *AbsTy) { - PackedTypes->TypeBecameConcrete(this, AbsTy); +void VectorType::typeBecameConcrete(const DerivedType *AbsTy) { + VectorTypes->TypeBecameConcrete(this, AbsTy); } // refineAbstractType - Called when a contained type is found to be more @@ -1490,8 +1670,8 @@ void PointerType::typeBecameConcrete(const DerivedType *AbsTy) { } bool SequentialType::indexValid(const Value *V) const { - if (const IntegerType *IT = dyn_cast(V->getType())) - return IT->getBitWidth() == 32 || IT->getBitWidth() == 64; + if (isa(V->getType())) + return true; return false; } @@ -1508,4 +1688,9 @@ std::ostream &operator<<(std::ostream &OS, const Type &T) { T.print(OS); return OS; } + +raw_ostream &operator<<(raw_ostream &OS, const Type &T) { + T.print(OS); + return OS; +} }