#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>
AbstractTypeUser::~AbstractTypeUser() {}
+void AbstractTypeUser::setType(Value *V, const Type *NewTy) {
+ V->VTy = NewTy;
+}
//===----------------------------------------------------------------------===//
// Type Class Implementation
//===----------------------------------------------------------------------===//
-// 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<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.
/// Some type objects (FunctionTy, StructTy) allocate additional space after
operator delete(const_cast<Type *>(this));
return;
+ } else if (const OpaqueType *opaque_this = dyn_cast<OpaqueType>(this)) {
+ LLVMContextImpl *pImpl = this->getContext().pImpl;
+ pImpl->OpaqueTypes.erase(opaque_this);
}
// For all the other type subclasses, there is either no contained types or
std::string Type::getDescription() const {
+ LLVMContextImpl *pImpl = getContext().pImpl;
TypePrinting &Map =
- isAbstract() ? *AbstractTypeDescriptions : *ConcreteTypeDescriptions;
+ isAbstract() ?
+ pImpl->AbstractTypeDescriptions :
+ pImpl->ConcreteTypeDescriptions;
std::string DescStr;
raw_string_ostream DescOS(DescStr);
//===----------------------------------------------------------------------===//
const Type *Type::getVoidTy(LLVMContext &C) {
- return C.pImpl->VoidTy;
+ return &C.pImpl->VoidTy;
}
const Type *Type::getLabelTy(LLVMContext &C) {
- return C.pImpl->LabelTy;
+ return &C.pImpl->LabelTy;
}
const Type *Type::getFloatTy(LLVMContext &C) {
- return C.pImpl->FloatTy;
+ return &C.pImpl->FloatTy;
}
const Type *Type::getDoubleTy(LLVMContext &C) {
- return C.pImpl->DoubleTy;
+ return &C.pImpl->DoubleTy;
}
const Type *Type::getMetadataTy(LLVMContext &C) {
- return C.pImpl->MetadataTy;
+ return &C.pImpl->MetadataTy;
}
const Type *Type::getX86_FP80Ty(LLVMContext &C) {
- return C.pImpl->X86_FP80Ty;
+ return &C.pImpl->X86_FP80Ty;
}
const Type *Type::getFP128Ty(LLVMContext &C) {
- return C.pImpl->FP128Ty;
+ return &C.pImpl->FP128Ty;
}
const Type *Type::getPPC_FP128Ty(LLVMContext &C) {
- return C.pImpl->PPC_FP128Ty;
+ return &C.pImpl->PPC_FP128Ty;
}
const IntegerType *Type::getInt1Ty(LLVMContext &C) {
- return C.pImpl->Int1Ty;
+ return &C.pImpl->Int1Ty;
}
const IntegerType *Type::getInt8Ty(LLVMContext &C) {
- return C.pImpl->Int8Ty;
+ return &C.pImpl->Int8Ty;
}
const IntegerType *Type::getInt16Ty(LLVMContext &C) {
- return C.pImpl->Int16Ty;
+ return &C.pImpl->Int16Ty;
}
const IntegerType *Type::getInt32Ty(LLVMContext &C) {
- return C.pImpl->Int32Ty;
+ return &C.pImpl->Int32Ty;
}
const IntegerType *Type::getInt64Ty(LLVMContext &C) {
- return C.pImpl->Int64Ty;
+ return &C.pImpl->Int64Ty;
+}
+
+const PointerType *Type::getFloatPtrTy(LLVMContext &C, unsigned AS) {
+ return getFloatTy(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getDoublePtrTy(LLVMContext &C, unsigned AS) {
+ return getDoubleTy(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getX86_FP80PtrTy(LLVMContext &C, unsigned AS) {
+ return getX86_FP80Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getFP128PtrTy(LLVMContext &C, unsigned AS) {
+ return getFP128Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getPPC_FP128PtrTy(LLVMContext &C, unsigned AS) {
+ return getPPC_FP128Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getInt1PtrTy(LLVMContext &C, unsigned AS) {
+ return getInt1Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getInt8PtrTy(LLVMContext &C, unsigned AS) {
+ return getInt8Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getInt16PtrTy(LLVMContext &C, unsigned AS) {
+ return getInt16Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getInt32PtrTy(LLVMContext &C, unsigned AS) {
+ return getInt32Ty(C)->getPointerTo(AS);
+}
+
+const PointerType *Type::getInt64PtrTy(LLVMContext &C, unsigned AS) {
+ return getInt64Ty(C)->getPointerTo(AS);
}
//===----------------------------------------------------------------------===//
/// 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<PointerType>(RetTy))
- return PTy->getElementType() != Type::getMetadataTy(RetTy->getContext());
- return true;
- }
- if (RetTy == Type::getVoidTy(RetTy->getContext()) ||
- RetTy == Type::getMetadataTy(RetTy->getContext()) ||
- isa<OpaqueType>(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<StructType>(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;
+ return RetTy->getTypeID() != LabelTyID &&
+ RetTy->getTypeID() != MetadataTyID;
}
/// 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::getMetadataTy(ArgTy->getContext())))
- return false;
-
- return true;
+ return ArgTy->isFirstClassType() || isa<OpaqueType>(ArgTy);
}
FunctionType::FunctionType(const Type *Result,
OpaqueType::OpaqueType(LLVMContext &C) : DerivedType(C, OpaqueTyID) {
setAbstract(true);
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << *this << "\n";
+ DEBUG(errs() << "Derived new type: " << *this << "\n");
#endif
}
tmp = AlwaysOpaqueTy;
if (!tmp) {
tmp = OpaqueType::get(getContext());
- PATypeHolder* tmp2 = new PATypeHolder(AlwaysOpaqueTy);
+ PATypeHolder* tmp2 = new PATypeHolder(tmp);
sys::MemoryFence();
AlwaysOpaqueTy = tmp;
Holder = tmp2;
llvm_release_global_lock();
}
- } else {
+ } else if (!AlwaysOpaqueTy) {
AlwaysOpaqueTy = OpaqueType::get(getContext());
Holder = new PATypeHolder(AlwaysOpaqueTy);
}
// 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.
+ // concrete to avoid overhead for adding to AbstractTypeUser lists and
+ // stuff.
+ const Type *ConcreteTy = Type::getInt32Ty(getContext());
for (unsigned i = 1, e = NumContainedTys; i != e; ++i)
- ContainedTys[i] = Type::getInt32Ty(getContext());
+ ContainedTys[i] = ConcreteTy;
}
}
}
}
+namespace llvm { // in namespace llvm so findable by ADL
static bool TypesEqual(const Type *Ty, const Type *Ty2) {
std::map<const Type *, const Type *> EqTypes;
- return TypesEqual(Ty, Ty2, EqTypes);
+ return ::TypesEqual(Ty, Ty2, EqTypes);
+}
}
// AbstractTypeHasCycleThrough - Return true there is a path from CurTy to
return false;
}
-/// TypeHasCycleThroughItself - Return true if the specified type has a cycle
-/// back to itself.
+/// TypeHasCycleThroughItself - Return true if the specified type has
+/// a cycle back to itself.
+
+namespace llvm { // in namespace llvm so it's findable by ADL
static bool TypeHasCycleThroughItself(const Type *Ty) {
SmallPtrSet<const Type*, 128> VisitedTypes;
}
return false;
}
+}
//===----------------------------------------------------------------------===//
// Function Type Factory and Value Class...
// First, see if the type is already in the table, for which
// a reader lock suffices.
- sys::SmartScopedLock<true> L(pImpl->TypeMapLock);
ITy = pImpl->IntegerTypes.get(IVT);
if (!ITy) {
pImpl->IntegerTypes.add(IVT, ITy);
}
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << *ITy << "\n";
+ DEBUG(errs() << "Derived new type: " << *ITy << "\n");
#endif
return ITy;
}
LLVMContextImpl *pImpl = ReturnType->getContext().pImpl;
- sys::SmartScopedLock<true> L(pImpl->TypeMapLock);
FT = pImpl->FunctionTypes.get(VT);
if (!FT) {
}
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << FT << "\n";
+ DEBUG(errs() << "Derived new type: " << FT << "\n");
#endif
return FT;
}
LLVMContextImpl *pImpl = ElementType->getContext().pImpl;
- sys::SmartScopedLock<true> L(pImpl->TypeMapLock);
AT = pImpl->ArrayTypes.get(AVT);
if (!AT) {
pImpl->ArrayTypes.add(AVT, AT = new ArrayType(ElementType, NumElements));
}
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << *AT << "\n";
+ DEBUG(errs() << "Derived new type: " << *AT << "\n");
#endif
return AT;
}
bool ArrayType::isValidElementType(const Type *ElemTy) {
- if (ElemTy == Type::getVoidTy(ElemTy->getContext()) ||
- ElemTy == Type::getLabelTy(ElemTy->getContext()) ||
- ElemTy == Type::getMetadataTy(ElemTy->getContext()))
- return false;
-
- if (const PointerType *PTy = dyn_cast<PointerType>(ElemTy))
- if (PTy->getElementType() == Type::getMetadataTy(ElemTy->getContext()))
- return false;
-
- return true;
+ return ElemTy->getTypeID() != VoidTyID && ElemTy->getTypeID() != LabelTyID &&
+ ElemTy->getTypeID() != MetadataTyID && !isa<FunctionType>(ElemTy);
}
VectorType *VectorType::get(const Type *ElementType, unsigned NumElements) {
LLVMContextImpl *pImpl = ElementType->getContext().pImpl;
- sys::SmartScopedLock<true> L(pImpl->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";
+ DEBUG(errs() << "Derived new type: " << *PT << "\n");
#endif
return PT;
}
bool VectorType::isValidElementType(const Type *ElemTy) {
- if (ElemTy->isInteger() || ElemTy->isFloatingPoint() ||
- isa<OpaqueType>(ElemTy))
- return true;
-
- return false;
+ return ElemTy->isInteger() || ElemTy->isFloatingPoint() ||
+ isa<OpaqueType>(ElemTy);
}
//===----------------------------------------------------------------------===//
LLVMContextImpl *pImpl = Context.pImpl;
- sys::SmartScopedLock<true> L(pImpl->TypeMapLock);
ST = pImpl->StructTypes.get(STV);
if (!ST) {
pImpl->StructTypes.add(STV, ST);
}
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << *ST << "\n";
+ DEBUG(errs() << "Derived new type: " << *ST << "\n");
#endif
return ST;
}
}
bool StructType::isValidElementType(const Type *ElemTy) {
- if (ElemTy == Type::getVoidTy(ElemTy->getContext()) ||
- ElemTy == Type::getLabelTy(ElemTy->getContext()) ||
- ElemTy == Type::getMetadataTy(ElemTy->getContext()))
- return false;
-
- if (const PointerType *PTy = dyn_cast<PointerType>(ElemTy))
- if (PTy->getElementType() == Type::getMetadataTy(ElemTy->getContext()))
- return false;
-
- return true;
+ return ElemTy->getTypeID() != VoidTyID && ElemTy->getTypeID() != LabelTyID &&
+ ElemTy->getTypeID() != MetadataTyID && !isa<FunctionType>(ElemTy);
}
PointerType *PointerType::get(const Type *ValueType, unsigned AddressSpace) {
assert(ValueType && "Can't get a pointer to <null> type!");
- assert(ValueType != Type::getVoidTy(ValueType->getContext()) &&
+ assert(ValueType->getTypeID() != VoidTyID &&
"Pointer to void is not valid, use i8* instead!");
assert(isValidElementType(ValueType) && "Invalid type for pointer element!");
PointerValType PVT(ValueType, AddressSpace);
LLVMContextImpl *pImpl = ValueType->getContext().pImpl;
- sys::SmartScopedLock<true> L(pImpl->TypeMapLock);
PT = pImpl->PointerTypes.get(PVT);
if (!PT) {
pImpl->PointerTypes.add(PVT, PT = new PointerType(ValueType, AddressSpace));
}
#ifdef DEBUG_MERGE_TYPES
- DOUT << "Derived new type: " << *PT << "\n";
+ DEBUG(errs() << "Derived new type: " << *PT << "\n");
#endif
return PT;
}
-PointerType *Type::getPointerTo(unsigned addrs) const {
+const PointerType *Type::getPointerTo(unsigned addrs) const {
return PointerType::get(this, addrs);
}
bool PointerType::isValidElementType(const Type *ElemTy) {
- if (ElemTy == Type::getVoidTy(ElemTy->getContext()) ||
- ElemTy == Type::getLabelTy(ElemTy->getContext()))
- return false;
+ return ElemTy->getTypeID() != VoidTyID &&
+ ElemTy->getTypeID() != LabelTyID &&
+ ElemTy->getTypeID() != MetadataTyID;
+}
- if (const PointerType *PTy = dyn_cast<PointerType>(ElemTy))
- if (PTy->getElementType() == Type::getMetadataTy(ElemTy->getContext()))
- return false;
- return true;
+//===----------------------------------------------------------------------===//
+// Opaque Type Factory...
+//
+
+OpaqueType *OpaqueType::get(LLVMContext &C) {
+ OpaqueType *OT = new OpaqueType(C); // All opaque types are distinct
+
+ LLVMContextImpl *pImpl = C.pImpl;
+ pImpl->OpaqueTypes.insert(OT);
+ return OT;
}
+
//===----------------------------------------------------------------------===//
// Derived Type Refinement Functions
//===----------------------------------------------------------------------===//
// 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();
}
// 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
AbstractTypeUsers.erase(AbstractTypeUsers.begin()+i);
#ifdef DEBUG_MERGE_TYPES
- DOUT << " remAbstractTypeUser[" << (void*)this << ", "
- << *this << "][" << i << "] User = " << U << "\n";
+ DEBUG(errs() << " remAbstractTypeUser[" << (void*)this << ", "
+ << *this << "][" << i << "] User = " << U << "\n");
#endif
if (AbstractTypeUsers.empty() && getRefCount() == 0 && isAbstract()) {
#ifdef DEBUG_MERGE_TYPES
- DOUT << "DELETEing unused abstract type: <" << *this
- << ">[" << (void*)this << "]" << "\n";
+ DEBUG(errs() << "DELETEing unused abstract type: <" << *this
+ << ">[" << (void*)this << "]" << "\n");
#endif
this->destroy();
}
- AbstractTypeUsersLock->release();
}
// unlockedRefineAbstractTypeTo - This function is used when it is discovered
assert(this != NewType && "Can't refine to myself!");
assert(ForwardType == 0 && "This type has already been refined!");
+ LLVMContextImpl *pImpl = getContext().pImpl;
+
// The descriptions may be out of date. Conservatively clear them all!
- if (AbstractTypeDescriptions.isConstructed())
- AbstractTypeDescriptions->clear();
+ pImpl->AbstractTypeDescriptions.clear();
#ifdef DEBUG_MERGE_TYPES
- DOUT << "REFINING abstract type [" << (void*)this << " "
- << *this << "] to [" << (void*)NewType << " "
- << *NewType << "]!\n";
+ DEBUG(errs() << "REFINING abstract type [" << (void*)this << " "
+ << *this << "] to [" << (void*)NewType << " "
+ << *NewType << "]!\n");
#endif
// Make sure to put the type to be refined to into a holder so that if IT gets
// refined, that we will not continue using a dead reference...
//
PATypeHolder NewTy(NewType);
- // Any PATypeHolders referring to this type will now automatically forward o
+ // Any PATypeHolders referring to this type will now automatically forward to
// 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();
unsigned OldSize = AbstractTypeUsers.size(); OldSize=OldSize;
#ifdef DEBUG_MERGE_TYPES
- DOUT << " REFINING user " << OldSize-1 << "[" << (void*)User
- << "] of abstract type [" << (void*)this << " "
- << *this << "] to [" << (void*)NewTy.get() << " "
- << *NewTy << "]!\n";
+ DEBUG(errs() << " REFINING user " << OldSize-1 << "[" << (void*)User
+ << "] of abstract type [" << (void*)this << " "
+ << *this << "] to [" << (void*)NewTy.get() << " "
+ << *NewTy << "]!\n");
#endif
User->refineAbstractType(this, NewTy);
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.
void DerivedType::refineAbstractTypeTo(const Type *NewType) {
// All recursive calls will go through unlockedRefineAbstractTypeTo,
// to avoid deadlock problems.
- sys::SmartScopedLock<true> L(NewType->getContext().pImpl->TypeMapLock);
unlockedRefineAbstractTypeTo(NewType);
}
//
void DerivedType::notifyUsesThatTypeBecameConcrete() {
#ifdef DEBUG_MERGE_TYPES
- DOUT << "typeIsREFINED type: " << (void*)this << " " << *this << "\n";
+ DEBUG(errs() << "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
}
namespace llvm {
-std::ostream &operator<<(std::ostream &OS, const Type *T) {
- if (T == 0)
- OS << "<null> value!\n";
- else
- T->print(OS);
- return OS;
-}
-
-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;