//
//===----------------------------------------------------------------------===//
+#include "LLVMContextImpl.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
+#include "llvm/Assembly/Writer.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Metadata.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/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Mutex.h"
+#include "llvm/System/RWMutex.h"
+#include "llvm/System/Threading.h"
#include <algorithm>
#include <cstdarg>
using namespace llvm;
// Type Class Implementation
//===----------------------------------------------------------------------===//
+// Lock used for guarding access to the type maps.
+static ManagedStatic<sys::SmartMutex<true> > TypeMapLock;
+
+// Recursive lock used for guarding access to AbstractTypeUsers.
+// NOTE: The true template parameter means this will no-op when we're not in
+// multithreaded mode.
+static ManagedStatic<sys::SmartMutex<true> > 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<std::map<const Type*,
- std::string> > ConcreteTypeDescriptions;
-static ManagedStatic<std::map<const Type*,
- std::string> > AbstractTypeDescriptions;
+static ManagedStatic<TypePrinting> ConcreteTypeDescriptions;
+static ManagedStatic<TypePrinting> 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.
case FP128TyID : return FP128Ty;
case PPC_FP128TyID : return PPC_FP128Ty;
case LabelTyID : return LabelTy;
+ case MetadataTyID : return MetadataTy;
default:
return 0;
}
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<VectorType>(this))
+ return VTy->getElementType();
+ return this;
+}
+
/// isIntOrIntVector - Return true if this is an integer type or a vector of
/// integer types.
///
return cast<VectorType>(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
}
}
+/// 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<VectorType>(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.
}
void Type::refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
- abort();
+ llvm_unreachable("Attempting to refine a derived type!");
}
void Type::typeBecameConcrete(const DerivedType *AbsTy) {
- abort();
+ llvm_unreachable("DerivedType is already a concrete type!");
}
-// 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<const Type *> &TypeStack) {
- if (isa<OpaqueType>(Ty)) { // Base case for the recursion
- std::map<const Type*, std::string>::iterator I =
- AbstractTypeDescriptions->find(Ty);
- if (I != AbstractTypeDescriptions->end())
- 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<const Type*, std::string>::iterator I =
- ConcreteTypeDescriptions->find(Ty);
- if (I != ConcreteTypeDescriptions->end())
- return I->second;
-
- if (Ty->isPrimitiveType()) {
- switch (Ty->getTypeID()) {
- default: assert(0 && "Unknown prim type!");
- case Type::VoidTyID: return (*ConcreteTypeDescriptions)[Ty] = "void";
- case Type::FloatTyID: return (*ConcreteTypeDescriptions)[Ty] = "float";
- case Type::DoubleTyID: return (*ConcreteTypeDescriptions)[Ty] = "double";
- case Type::X86_FP80TyID:
- return (*ConcreteTypeDescriptions)[Ty] = "x86_fp80";
- case Type::FP128TyID: return (*ConcreteTypeDescriptions)[Ty] = "fp128";
- case Type::PPC_FP128TyID:
- return (*ConcreteTypeDescriptions)[Ty] = "ppc_fp128";
- case Type::LabelTyID: return (*ConcreteTypeDescriptions)[Ty] = "label";
- }
- }
- }
-
- // 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<IntegerType>(Ty);
- Result = "i" + utostr(ITy->getBitWidth());
- break;
- }
- case Type::FunctionTyID: {
- const FunctionType *FTy = cast<FunctionType>(Ty);
- if (!Result.empty())
- Result += " ";
- Result += getTypeDescription(FTy->getReturnType(), TypeStack) + " (";
- for (FunctionType::param_iterator I = FTy->param_begin(),
- E = FTy->param_end(); I != E; ++I) {
- if (I != FTy->param_begin())
- Result += ", ";
- Result += getTypeDescription(*I, TypeStack);
- }
- if (FTy->isVarArg()) {
- if (FTy->getNumParams()) Result += ", ";
- Result += "...";
- }
- Result += ")";
- break;
- }
- case Type::StructTyID: {
- const StructType *STy = cast<StructType>(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<PointerType>(Ty);
- Result = getTypeDescription(PTy->getElementType(), TypeStack);
- if (unsigned AddressSpace = PTy->getAddressSpace())
- Result += " addrspace(" + utostr(AddressSpace) + ")";
- Result += " *";
- break;
- }
- case Type::ArrayTyID: {
- const ArrayType *ATy = cast<ArrayType>(Ty);
- unsigned NumElements = ATy->getNumElements();
- Result = "[";
- Result += utostr(NumElements) + " x ";
- Result += getTypeDescription(ATy->getElementType(), TypeStack) + "]";
- break;
- }
- case Type::VectorTyID: {
- const VectorType *PTy = cast<VectorType>(Ty);
- unsigned NumElements = PTy->getNumElements();
- Result = "<";
- Result += utostr(NumElements) + " x ";
- Result += getTypeDescription(PTy->getElementType(), TypeStack) + ">";
- break;
- }
- default:
- Result = "<error>";
- assert(0 && "Unhandled type in getTypeDescription!");
- }
-
- TypeStack.pop_back(); // Remove self from stack...
-
- return Result;
-}
-
-
-
-static const std::string &getOrCreateDesc(std::map<const Type*,std::string>&Map,
- const Type *Ty) {
- std::map<const Type*, std::string>::iterator I = Map.find(Ty);
- if (I != Map.end()) return I->second;
-
- std::vector<const Type *> 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();
}
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 {
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 (RetTy->isFirstClassType()) {
+ if (const PointerType *PTy = dyn_cast<PointerType>(RetTy))
+ return PTy->getElementType() != Type::MetadataTy;
return true;
- if (RetTy == Type::VoidTy || isa<OpaqueType>(RetTy))
+ }
+ if (RetTy == Type::VoidTy || RetTy == Type::MetadataTy ||
+ isa<OpaqueType>(RetTy))
return true;
// If this is a multiple return case, verify that each return is a first class
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<OpaqueType>(ArgTy)) ||
+ (isa<PointerType>(ArgTy) &&
+ cast<PointerType>(ArgTy)->getElementType() == Type::MetadataTy))
+ return false;
+
+ return true;
+}
+
FunctionType::FunctionType(const Type *Result,
const std::vector<const Type*> &Params,
bool IsVarArgs)
ContainedTys = reinterpret_cast<PATypeHandle*>(this+1);
NumContainedTys = Params.size() + 1; // + 1 for result type
assert(isValidReturnType(Result) && "invalid return type for function");
-
-
+
+
bool isAbstract = Result->isAbstract();
new (&ContainedTys[0]) PATypeHandle(Result, this);
for (unsigned i = 0; i != Params.size(); ++i) {
- assert((Params[i]->isFirstClassType() || isa<OpaqueType>(Params[i])) &&
- "Function arguments must be value types!");
- new (&ContainedTys[i+1]) 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();
}
setSubclassData(isPacked);
bool isAbstract = false;
for (unsigned i = 0; i < Types.size(); ++i) {
- assert(Types[i] != Type::VoidTy && "Void type for structure field!!");
- new (&ContainedTys[i]) PATypeHandle(Types[i], this);
+ assert(Types[i] && "<null> type for structure field!");
+ assert(isValidElementType(Types[i]) &&
+ "Invalid type for structure element!");
+ new (&ContainedTys[i]) PATypeHandle(Types[i], this);
isAbstract |= Types[i]->isAbstract();
}
NumElements = NumEl;
setAbstract(ElType->isAbstract());
assert(NumEl > 0 && "NumEl of a VectorType must be greater than 0");
- assert((ElType->isInteger() || ElType->isFloatingPoint() ||
- isa<OpaqueType>(ElType)) &&
+ assert(isValidElementType(ElType) &&
"Elements of a VectorType must be a primitive type");
}
#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.
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);
+ static Type *AlwaysOpaqueTy = 0;
+ static PATypeHolder* Holder = 0;
+ Type *tmp = AlwaysOpaqueTy;
+ if (llvm_is_multithreaded()) {
+ sys::MemoryFence();
+ if (!tmp) {
+ llvm_acquire_global_lock();
+ tmp = AlwaysOpaqueTy;
+ if (!tmp) {
+ tmp = OpaqueType::get();
+ PATypeHolder* tmp2 = new PATypeHolder(AlwaysOpaqueTy);
+ sys::MemoryFence();
+ AlwaysOpaqueTy = tmp;
+ Holder = tmp2;
+ }
+
+ llvm_release_global_lock();
+ }
+ } else {
+ AlwaysOpaqueTy = OpaqueType::get();
+ Holder = new PATypeHolder(AlwaysOpaqueTy);
+ }
+
ContainedTys[0] = AlwaysOpaqueTy;
// Change the rest of the types to be Int32Ty's. It doesn't matter what we
}
return true;
} else {
- assert(0 && "Unknown derived type!");
+ llvm_unreachable("Unknown derived type!");
return false;
}
}
return false;
}
-/// getSubElementHash - Generate a hash value for all of the SubType's of this
-/// type. The hash value is guaranteed to be zero if any of the subtypes are
-/// an opaque type. Otherwise we try to mix them in as well as possible, but do
-/// not look at the subtype's subtype's.
-static unsigned getSubElementHash(const Type *Ty) {
- unsigned HashVal = 0;
- for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
- I != E; ++I) {
- HashVal *= 32;
- const Type *SubTy = I->get();
- HashVal += SubTy->getTypeID();
- switch (SubTy->getTypeID()) {
- default: break;
- case Type::OpaqueTyID: return 0; // Opaque -> hash = 0 no matter what.
- case Type::IntegerTyID:
- HashVal ^= (cast<IntegerType>(SubTy)->getBitWidth() << 3);
- break;
- case Type::FunctionTyID:
- HashVal ^= cast<FunctionType>(SubTy)->getNumParams()*2 +
- cast<FunctionType>(SubTy)->isVarArg();
- break;
- case Type::ArrayTyID:
- HashVal ^= cast<ArrayType>(SubTy)->getNumElements();
- break;
- case Type::VectorTyID:
- HashVal ^= cast<VectorType>(SubTy)->getNumElements();
- break;
- case Type::StructTyID:
- HashVal ^= cast<StructType>(SubTy)->getNumElements();
- break;
- case Type::PointerTyID:
- HashVal ^= cast<PointerType>(SubTy)->getAddressSpace();
- break;
- }
- }
- return HashVal ? HashVal : 1; // Do not return zero unless opaque subty.
-}
-
-//===----------------------------------------------------------------------===//
-// Derived Type Factory Functions
-//===----------------------------------------------------------------------===//
-
-namespace llvm {
-class TypeMapBase {
-protected:
- /// TypesByHash - Keep track of types by their structure hash value. Note
- /// that we only keep track of types that have cycles through themselves in
- /// this map.
- ///
- std::multimap<unsigned, PATypeHolder> TypesByHash;
-
-public:
- void RemoveFromTypesByHash(unsigned Hash, const Type *Ty) {
- std::multimap<unsigned, PATypeHolder>::iterator I =
- TypesByHash.lower_bound(Hash);
- for (; I != TypesByHash.end() && I->first == Hash; ++I) {
- if (I->second == Ty) {
- TypesByHash.erase(I);
- return;
- }
- }
-
- // This must be do to an opaque type that was resolved. Switch down to hash
- // code of zero.
- assert(Hash && "Didn't find type entry!");
- RemoveFromTypesByHash(0, Ty);
- }
-
- /// TypeBecameConcrete - When Ty gets a notification that TheType just became
- /// concrete, drop uses and make Ty non-abstract if we should.
- void TypeBecameConcrete(DerivedType *Ty, const DerivedType *TheType) {
- // If the element just became concrete, remove 'ty' from the abstract
- // type user list for the type. Do this for as many times as Ty uses
- // OldType.
- for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
- I != E; ++I)
- if (I->get() == TheType)
- TheType->removeAbstractTypeUser(Ty);
-
- // If the type is currently thought to be abstract, rescan all of our
- // subtypes to see if the type has just become concrete! Note that this
- // may send out notifications to AbstractTypeUsers that types become
- // concrete.
- if (Ty->isAbstract())
- Ty->PromoteAbstractToConcrete();
- }
-};
-}
-
-
-// TypeMap - Make sure that only one instance of a particular type may be
-// created on any given run of the compiler... note that this involves updating
-// our map if an abstract type gets refined somehow.
-//
-namespace llvm {
-template<class ValType, class TypeClass>
-class TypeMap : public TypeMapBase {
- std::map<ValType, PATypeHolder> Map;
-public:
- typedef typename std::map<ValType, PATypeHolder>::iterator iterator;
- ~TypeMap() { print("ON EXIT"); }
-
- inline TypeClass *get(const ValType &V) {
- iterator I = Map.find(V);
- return I != Map.end() ? cast<TypeClass>((Type*)I->second.get()) : 0;
- }
-
- inline void add(const ValType &V, TypeClass *Ty) {
- Map.insert(std::make_pair(V, Ty));
-
- // If this type has a cycle, remember it.
- TypesByHash.insert(std::make_pair(ValType::hashTypeStructure(Ty), Ty));
- print("add");
- }
-
- /// 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,
- const Type *NewType) {
-#ifdef DEBUG_MERGE_TYPES
- DOUT << "RefineAbstractType(" << (void*)OldType << "[" << *OldType
- << "], " << (void*)NewType << " [" << *NewType << "])\n";
-#endif
-
- // Otherwise, we are changing one subelement type into another. Clearly the
- // OldType must have been abstract, making us abstract.
- assert(Ty->isAbstract() && "Refining a non-abstract type!");
- assert(OldType != NewType);
-
- // Make a temporary type holder for the type so that it doesn't disappear on
- // us when we erase the entry from the map.
- PATypeHolder TyHolder = Ty;
-
- // 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!"); 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->getNumContainedTypes(); i != e; ++i)
- if (Ty->ContainedTys[i] == OldType)
- Ty->ContainedTys[i] = NewType;
- unsigned NewTypeHash = ValType::hashTypeStructure(Ty);
-
- // If there are no cycles going through this node, we can do a simple,
- // efficient lookup in the map, instead of an inefficient nasty linear
- // lookup.
- if (!TypeHasCycleThroughItself(Ty)) {
- typename std::map<ValType, PATypeHolder>::iterator I;
- bool Inserted;
-
- tie(I, Inserted) = Map.insert(std::make_pair(ValType::get(Ty), Ty));
- if (!Inserted) {
- // Refined to a different type altogether?
- RemoveFromTypesByHash(OldTypeHash, Ty);
-
- // We already have this type in the table. Get rid of the newly refined
- // type.
- TypeClass *NewTy = cast<TypeClass>((Type*)I->second.get());
- Ty->refineAbstractTypeTo(NewTy);
- return;
- }
- } else {
- // 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.
- //
- std::multimap<unsigned, PATypeHolder>::iterator I, E, Entry;
- tie(I, E) = TypesByHash.equal_range(NewTypeHash);
- Entry = E;
- for (; I != E; ++I) {
- if (I->second == Ty) {
- // Remember the position of the old type if we see it in our scan.
- Entry = I;
- } else {
- if (TypesEqual(Ty, I->second)) {
- TypeClass *NewTy = cast<TypeClass>((Type*)I->second.get());
-
- // Remove the old entry form TypesByHash. If the hash values differ
- // now, remove it from the old place. Otherwise, continue scanning
- // withing this hashcode to reduce work.
- if (NewTypeHash != OldTypeHash) {
- RemoveFromTypesByHash(OldTypeHash, Ty);
- } else {
- if (Entry == E) {
- // Find the location of Ty in the TypesByHash structure if we
- // haven't seen it already.
- while (I->second != Ty) {
- ++I;
- assert(I != E && "Structure doesn't contain type??");
- }
- Entry = I;
- }
- TypesByHash.erase(Entry);
- }
- Ty->refineAbstractTypeTo(NewTy);
- 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 hash codes differ, update TypesByHash
- if (NewTypeHash != OldTypeHash) {
- RemoveFromTypesByHash(OldTypeHash, Ty);
- TypesByHash.insert(std::make_pair(NewTypeHash, Ty));
- }
-
- // If the type is currently thought to be abstract, rescan all of our
- // subtypes to see if the type has just become concrete! Note that this
- // may send out notifications to AbstractTypeUsers that types become
- // concrete.
- if (Ty->isAbstract())
- Ty->PromoteAbstractToConcrete();
- }
-
- void print(const char *Arg) const {
-#ifdef DEBUG_MERGE_TYPES
- DOUT << "TypeMap<>::" << Arg << " table contents:\n";
- unsigned i = 0;
- for (typename std::map<ValType, PATypeHolder>::const_iterator I
- = Map.begin(), E = Map.end(); I != E; ++I)
- DOUT << " " << (++i) << ". " << (void*)I->second.get() << " "
- << *I->second.get() << "\n";
-#endif
- }
-
- void dump() const { print("dump output"); }
-};
-}
-
-
//===----------------------------------------------------------------------===//
// Function Type Factory and Value Class...
//
-//===----------------------------------------------------------------------===//
-// Integer Type Factory...
-//
-namespace llvm {
-class IntegerValType {
- uint32_t bits;
-public:
- IntegerValType(uint16_t numbits) : bits(numbits) {}
-
- static IntegerValType get(const IntegerType *Ty) {
- return IntegerValType(Ty->getBitWidth());
- }
-
- static unsigned hashTypeStructure(const IntegerType *Ty) {
- return (unsigned)Ty->getBitWidth();
- }
-
- inline bool operator<(const IntegerValType &IVT) const {
- return bits < IVT.bits;
- }
-};
-}
-
static ManagedStatic<TypeMap<IntegerValType, IntegerType> > IntegerTypes;
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;
+
+ // First, see if the type is already in the table, for which
+ // a reader lock suffices.
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ ITy = IntegerTypes->get(IVT);
+
+ if (!ITy) {
+ // 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 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<const Type*> ArgTypes;
- bool isVarArg;
-public:
- FunctionValType(const Type *ret, const std::vector<const Type*> &args,
- bool isVA) : RetTy(ret), ArgTypes(args), isVarArg(isVA) {}
-
- static FunctionValType get(const FunctionType *FT);
-
- static unsigned hashTypeStructure(const FunctionType *FT) {
- unsigned Result = FT->getNumParams()*2 + FT->isVarArg();
- return Result;
- }
-
- inline bool operator<(const FunctionValType &MTV) const {
- if (RetTy < MTV.RetTy) return true;
- if (RetTy > MTV.RetTy) return false;
- if (isVarArg < MTV.isVarArg) return true;
- if (isVarArg > MTV.isVarArg) return false;
- if (ArgTypes < MTV.ArgTypes) return true;
- if (ArgTypes > MTV.ArgTypes) return false;
- return false;
- }
-};
-}
-
-// Define the actual map itself now...
-static ManagedStatic<TypeMap<FunctionValType, FunctionType> > FunctionTypes;
-
FunctionValType FunctionValType::get(const FunctionType *FT) {
// Build up a FunctionValType
std::vector<const Type *> ParamTypes;
const std::vector<const Type*> &Params,
bool isVarArg) {
FunctionValType VT(ReturnType, Params, isVarArg);
- FunctionType *FT = FunctionTypes->get(VT);
- if (FT)
- return FT;
-
- FT = (FunctionType*) operator new(sizeof(FunctionType) +
+ FunctionType *FT = 0;
+
+ LLVMContextImpl *pImpl = ReturnType->getContext().pImpl;
+
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ FT = pImpl->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);
+ new (FT) FunctionType(ReturnType, Params, isVarArg);
+ pImpl->FunctionTypes.add(VT, FT);
+ }
#ifdef DEBUG_MERGE_TYPES
DOUT << "Derived new type: " << FT << "\n";
return FT;
}
-//===----------------------------------------------------------------------===//
-// Array Type Factory...
-//
-namespace llvm {
-class ArrayValType {
- const Type *ValTy;
- uint64_t Size;
-public:
- ArrayValType(const Type *val, uint64_t sz) : ValTy(val), Size(sz) {}
-
- static ArrayValType get(const ArrayType *AT) {
- return ArrayValType(AT->getElementType(), AT->getNumElements());
- }
-
- static unsigned hashTypeStructure(const ArrayType *AT) {
- return (unsigned)AT->getNumElements();
- }
-
- inline bool operator<(const ArrayValType &MTV) const {
- if (Size < MTV.Size) return true;
- return Size == MTV.Size && ValTy < MTV.ValTy;
- }
-};
-}
-static ManagedStatic<TypeMap<ArrayValType, ArrayType> > 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 <null> 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;
+ LLVMContextImpl *pImpl = ElementType->getContext().pImpl;
+
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ AT = pImpl->ArrayTypes.get(AVT);
+
+ if (!AT) {
+ // Value not found. Derive a new type!
+ pImpl->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;
-//===----------------------------------------------------------------------===//
-// Vector Type Factory...
-//
-namespace llvm {
-class VectorValType {
- const Type *ValTy;
- unsigned Size;
-public:
- VectorValType(const Type *val, int sz) : ValTy(val), Size(sz) {}
-
- static VectorValType get(const VectorType *PT) {
- return VectorValType(PT->getElementType(), PT->getNumElements());
- }
-
- static unsigned hashTypeStructure(const VectorType *PT) {
- return PT->getNumElements();
- }
+ if (const PointerType *PTy = dyn_cast<PointerType>(ElemTy))
+ if (PTy->getElementType() == Type::MetadataTy)
+ return false;
- inline bool operator<(const VectorValType &MTV) const {
- if (Size < MTV.Size) return true;
- return Size == MTV.Size && ValTy < MTV.ValTy;
- }
-};
+ return true;
}
-static ManagedStatic<TypeMap<VectorValType, VectorType> > VectorTypes;
-
VectorType *VectorType::get(const Type *ElementType, unsigned NumElements) {
- assert(ElementType && "Can't get vector of null types!");
+ assert(ElementType && "Can't get vector of <null> types!");
VectorValType PVT(ElementType, NumElements);
- VectorType *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));
-
+ VectorType *PT = 0;
+
+ LLVMContextImpl *pImpl = ElementType->getContext().pImpl;
+
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ PT = pImpl->VectorTypes.get(PVT);
+
+ if (!PT) {
+ pImpl->VectorTypes.add(PVT, PT = new VectorType(ElementType, NumElements));
+ }
#ifdef DEBUG_MERGE_TYPES
DOUT << "Derived new type: " << *PT << "\n";
#endif
return PT;
}
-//===----------------------------------------------------------------------===//
-// Struct Type Factory...
-//
-
-namespace llvm {
-// StructValType - Define a class to hold the key that goes into the TypeMap
-//
-class StructValType {
- std::vector<const Type*> ElTypes;
- bool packed;
-public:
- StructValType(const std::vector<const Type*> &args, bool isPacked)
- : ElTypes(args), packed(isPacked) {}
-
- static StructValType get(const StructType *ST) {
- std::vector<const Type *> ElTypes;
- ElTypes.reserve(ST->getNumElements());
- for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i)
- ElTypes.push_back(ST->getElementType(i));
-
- return StructValType(ElTypes, ST->isPacked());
- }
-
- static unsigned hashTypeStructure(const StructType *ST) {
- return ST->getNumElements();
- }
+bool VectorType::isValidElementType(const Type *ElemTy) {
+ if (ElemTy->isInteger() || ElemTy->isFloatingPoint() ||
+ isa<OpaqueType>(ElemTy))
+ return true;
- inline bool operator<(const StructValType &STV) const {
- if (ElTypes < STV.ElTypes) return true;
- else if (ElTypes > STV.ElTypes) return false;
- else return (int)packed < (int)STV.packed;
- }
-};
+ return false;
}
-static ManagedStatic<TypeMap<StructValType, StructType> > StructTypes;
+//===----------------------------------------------------------------------===//
+// Struct Type Factory...
+//
-StructType *StructType::get(const std::vector<const Type*> &ETypes,
+StructType *StructType::get(LLVMContext &Context,
+ const std::vector<const Type*> &ETypes,
bool isPacked) {
StructValType STV(ETypes, isPacked);
- StructType *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);
-
+ StructType *ST = 0;
+
+ LLVMContextImpl *pImpl = Context.pImpl;
+
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ ST = pImpl->StructTypes.get(STV);
+
+ if (!ST) {
+ // Value not found. Derive a new type!
+ ST = (StructType*) operator new(sizeof(StructType) +
+ sizeof(PATypeHandle) * ETypes.size());
+ new (ST) StructType(ETypes, isPacked);
+ pImpl->StructTypes.add(STV, ST);
+ }
#ifdef DEBUG_MERGE_TYPES
DOUT << "Derived new type: " << *ST << "\n";
#endif
return ST;
}
-StructType *StructType::get(const Type *type, ...) {
+StructType *StructType::get(LLVMContext &Context, const Type *type, ...) {
va_list ap;
std::vector<const llvm::Type*> StructFields;
va_start(ap, type);
StructFields.push_back(type);
type = va_arg(ap, llvm::Type*);
}
- return llvm::StructType::get(StructFields);
+ return llvm::StructType::get(Context, 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<PointerType>(ElemTy))
+ if (PTy->getElementType() == Type::MetadataTy)
+ return false;
+
+ return true;
+}
//===----------------------------------------------------------------------===//
// Pointer Type Factory...
//
-// PointerValType - Define a class to hold the key that goes into the TypeMap
-//
-namespace llvm {
-class PointerValType {
- const Type *ValTy;
- unsigned AddressSpace;
-public:
- PointerValType(const Type *val, unsigned as) : ValTy(val), AddressSpace(as) {}
-
- static PointerValType get(const PointerType *PT) {
- return PointerValType(PT->getElementType(), PT->getAddressSpace());
- }
-
- static unsigned hashTypeStructure(const PointerType *PT) {
- return getSubElementHash(PT);
- }
-
- bool operator<(const PointerValType &MTV) const {
- if (AddressSpace < MTV.AddressSpace) return true;
- return AddressSpace == MTV.AddressSpace && ValTy < MTV.ValTy;
- }
-};
-}
-
-static ManagedStatic<TypeMap<PointerValType, PointerType> > PointerTypes;
-
PointerType *PointerType::get(const Type *ValueType, unsigned AddressSpace) {
assert(ValueType && "Can't get a pointer to <null> type!");
assert(ValueType != Type::VoidTy &&
- "Pointer to void is not valid, use sbyte* instead!");
- assert(ValueType != Type::LabelTy && "Pointer to label is not valid!");
+ "Pointer to void is not valid, use i8* instead!");
+ assert(isValidElementType(ValueType) && "Invalid type for pointer element!");
PointerValType PVT(ValueType, AddressSpace);
- PointerType *PT = PointerTypes->get(PVT);
- if (PT) return PT;
-
- // Value not found. Derive a new type!
- PointerTypes->add(PVT, PT = new PointerType(ValueType, AddressSpace));
-
+ PointerType *PT = 0;
+
+ LLVMContextImpl *pImpl = ValueType->getContext().pImpl;
+
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ PT = pImpl->PointerTypes.get(PVT);
+
+ if (!PT) {
+ // Value not found. Derive a new type!
+ pImpl->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<PointerType>(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!");
+ AbstractTypeUsersLock->acquire();
+ AbstractTypeUsers.push_back(U);
+ AbstractTypeUsersLock->release();
+}
+
+
// 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 {
+ 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.
DOUT << "DELETEing unused abstract type: <" << *this
<< ">[" << (void*)this << "]" << "\n";
#endif
- this->destroy();
+
+ this->destroy();
}
+
+ 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 << " "
// 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())
// will not cause users to drop off of the use list. If we resolve to ourself
// we succeed!
//
+ AbstractTypeUsersLock->acquire();
while (!AbstractTypeUsers.empty() && NewTy != this) {
AbstractTypeUser *User = AbstractTypeUsers.back();
assert(AbstractTypeUsers.size() != OldSize &&
"AbsTyUser did not remove self from user list!");
}
+ 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.
// 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) {
+ // All recursive calls will go through unlockedRefineAbstractTypeTo,
+ // to avoid deadlock problems.
+ sys::SmartScopedLock<true> L(*TypeMapLock);
+ unlockedRefineAbstractTypeTo(NewType);
+}
+
// notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type that
// the current type has transitioned from being abstract to being concrete.
//
DOUT << "typeIsREFINED type: " << (void*)this << " " << *this << "\n";
#endif
+ AbstractTypeUsersLock->acquire();
unsigned OldSize = AbstractTypeUsers.size(); OldSize=OldSize;
while (!AbstractTypeUsers.empty()) {
AbstractTypeUser *ATU = AbstractTypeUsers.back();
assert(AbstractTypeUsers.size() < OldSize-- &&
"AbstractTypeUser did not remove itself from the use list!");
}
+ AbstractTypeUsersLock->release();
}
// refineAbstractType - Called when a contained type is found to be more
//
void FunctionType::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
- FunctionTypes->RefineAbstractType(this, OldType, NewType);
+ LLVMContextImpl *pImpl = OldType->getContext().pImpl;
+ pImpl->FunctionTypes.RefineAbstractType(this, OldType, NewType);
}
void FunctionType::typeBecameConcrete(const DerivedType *AbsTy) {
- FunctionTypes->TypeBecameConcrete(this, AbsTy);
+ LLVMContextImpl *pImpl = AbsTy->getContext().pImpl;
+ pImpl->FunctionTypes.TypeBecameConcrete(this, AbsTy);
}
//
void ArrayType::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
- ArrayTypes->RefineAbstractType(this, OldType, NewType);
+ LLVMContextImpl *pImpl = OldType->getContext().pImpl;
+ pImpl->ArrayTypes.RefineAbstractType(this, OldType, NewType);
}
void ArrayType::typeBecameConcrete(const DerivedType *AbsTy) {
- ArrayTypes->TypeBecameConcrete(this, AbsTy);
+ LLVMContextImpl *pImpl = AbsTy->getContext().pImpl;
+ pImpl->ArrayTypes.TypeBecameConcrete(this, AbsTy);
}
// refineAbstractType - Called when a contained type is found to be more
//
void VectorType::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
- VectorTypes->RefineAbstractType(this, OldType, NewType);
+ LLVMContextImpl *pImpl = OldType->getContext().pImpl;
+ pImpl->VectorTypes.RefineAbstractType(this, OldType, NewType);
}
void VectorType::typeBecameConcrete(const DerivedType *AbsTy) {
- VectorTypes->TypeBecameConcrete(this, AbsTy);
+ LLVMContextImpl *pImpl = AbsTy->getContext().pImpl;
+ pImpl->VectorTypes.TypeBecameConcrete(this, AbsTy);
}
// refineAbstractType - Called when a contained type is found to be more
//
void StructType::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
- StructTypes->RefineAbstractType(this, OldType, NewType);
+ LLVMContextImpl *pImpl = OldType->getContext().pImpl;
+ pImpl->StructTypes.RefineAbstractType(this, OldType, NewType);
}
void StructType::typeBecameConcrete(const DerivedType *AbsTy) {
- StructTypes->TypeBecameConcrete(this, AbsTy);
+ LLVMContextImpl *pImpl = AbsTy->getContext().pImpl;
+ pImpl->StructTypes.TypeBecameConcrete(this, AbsTy);
}
// refineAbstractType - Called when a contained type is found to be more
//
void PointerType::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
- PointerTypes->RefineAbstractType(this, OldType, NewType);
+ LLVMContextImpl *pImpl = OldType->getContext().pImpl;
+ pImpl->PointerTypes.RefineAbstractType(this, OldType, NewType);
}
void PointerType::typeBecameConcrete(const DerivedType *AbsTy) {
- PointerTypes->TypeBecameConcrete(this, AbsTy);
+ LLVMContextImpl *pImpl = AbsTy->getContext().pImpl;
+ pImpl->PointerTypes.TypeBecameConcrete(this, AbsTy);
}
bool SequentialType::indexValid(const Value *V) const {
- if (const IntegerType *IT = dyn_cast<IntegerType>(V->getType()))
- return IT->getBitWidth() == 32 || IT->getBitWidth() == 64;
+ if (isa<IntegerType>(V->getType()))
+ return true;
return false;
}
T.print(OS);
return OS;
}
+
+raw_ostream &operator<<(raw_ostream &OS, const Type &T) {
+ T.print(OS);
+ return OS;
+}
}