mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-29 14:40:39 +00:00
PR1210: make uniquing of struct and function types more efficient by
using a DenseMap and Talin's new GeneralHash, avoiding the need for a temporary std::vector on every lookup. Patch by Meador Inge! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
dac3d36584
commit
6b842e35dc
@ -29,6 +29,7 @@
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -89,6 +90,107 @@ struct DenseMapAPFloatKeyInfo {
|
||||
}
|
||||
};
|
||||
|
||||
struct AnonStructTypeKeyInfo {
|
||||
struct KeyTy {
|
||||
ArrayRef<Type*> ETypes;
|
||||
bool isPacked;
|
||||
KeyTy(const ArrayRef<Type*>& E, bool P) :
|
||||
ETypes(E), isPacked(P) {}
|
||||
KeyTy(const KeyTy& that) :
|
||||
ETypes(that.ETypes), isPacked(that.isPacked) {}
|
||||
KeyTy(const StructType* ST) :
|
||||
ETypes(ArrayRef<Type*>(ST->element_begin(), ST->element_end())),
|
||||
isPacked(ST->isPacked()) {}
|
||||
bool operator==(const KeyTy& that) const {
|
||||
if (isPacked != that.isPacked)
|
||||
return false;
|
||||
if (ETypes != that.ETypes)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const KeyTy& that) const {
|
||||
return !this->operator==(that);
|
||||
}
|
||||
};
|
||||
static inline StructType* getEmptyKey() {
|
||||
return DenseMapInfo<StructType*>::getEmptyKey();
|
||||
}
|
||||
static inline StructType* getTombstoneKey() {
|
||||
return DenseMapInfo<StructType*>::getTombstoneKey();
|
||||
}
|
||||
static unsigned getHashValue(const KeyTy& Key) {
|
||||
GeneralHash Hash;
|
||||
Hash.add(Key.ETypes);
|
||||
Hash.add(Key.isPacked);
|
||||
return Hash.finish();
|
||||
}
|
||||
static unsigned getHashValue(const StructType *ST) {
|
||||
return getHashValue(KeyTy(ST));
|
||||
}
|
||||
static bool isEqual(const KeyTy& LHS, const StructType *RHS) {
|
||||
if (RHS == getEmptyKey() || RHS == getTombstoneKey())
|
||||
return false;
|
||||
return LHS == KeyTy(RHS);
|
||||
}
|
||||
static bool isEqual(const StructType *LHS, const StructType *RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionTypeKeyInfo {
|
||||
struct KeyTy {
|
||||
const Type *ReturnType;
|
||||
ArrayRef<Type*> Params;
|
||||
bool isVarArg;
|
||||
KeyTy(const Type* R, const ArrayRef<Type*>& P, bool V) :
|
||||
ReturnType(R), Params(P), isVarArg(V) {}
|
||||
KeyTy(const KeyTy& that) :
|
||||
ReturnType(that.ReturnType),
|
||||
Params(that.Params),
|
||||
isVarArg(that.isVarArg) {}
|
||||
KeyTy(const FunctionType* FT) :
|
||||
ReturnType(FT->getReturnType()),
|
||||
Params(ArrayRef<Type*>(FT->param_begin(), FT->param_end())),
|
||||
isVarArg(FT->isVarArg()) {}
|
||||
bool operator==(const KeyTy& that) const {
|
||||
if (ReturnType != that.ReturnType)
|
||||
return false;
|
||||
if (isVarArg != that.isVarArg)
|
||||
return false;
|
||||
if (Params != that.Params)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const KeyTy& that) const {
|
||||
return !this->operator==(that);
|
||||
}
|
||||
};
|
||||
static inline FunctionType* getEmptyKey() {
|
||||
return DenseMapInfo<FunctionType*>::getEmptyKey();
|
||||
}
|
||||
static inline FunctionType* getTombstoneKey() {
|
||||
return DenseMapInfo<FunctionType*>::getTombstoneKey();
|
||||
}
|
||||
static unsigned getHashValue(const KeyTy& Key) {
|
||||
GeneralHash Hash;
|
||||
Hash.add(Key.ReturnType);
|
||||
Hash.add(Key.Params);
|
||||
Hash.add(Key.isVarArg);
|
||||
return Hash.finish();
|
||||
}
|
||||
static unsigned getHashValue(const FunctionType *FT) {
|
||||
return getHashValue(KeyTy(FT));
|
||||
}
|
||||
static bool isEqual(const KeyTy& LHS, const FunctionType *RHS) {
|
||||
if (RHS == getEmptyKey() || RHS == getTombstoneKey())
|
||||
return false;
|
||||
return LHS == KeyTy(RHS);
|
||||
}
|
||||
static bool isEqual(const FunctionType *LHS, const FunctionType *RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
/// DebugRecVH - This is a CallbackVH used to keep the Scope -> index maps
|
||||
/// up to date as MDNodes mutate. This class is implemented in DebugLoc.cpp.
|
||||
class DebugRecVH : public CallbackVH {
|
||||
@ -180,9 +282,10 @@ public:
|
||||
|
||||
DenseMap<unsigned, IntegerType*> IntegerTypes;
|
||||
|
||||
// TODO: Optimize FunctionTypes/AnonStructTypes!
|
||||
std::map<std::vector<Type*>, FunctionType*> FunctionTypes;
|
||||
std::map<std::vector<Type*>, StructType*> AnonStructTypes;
|
||||
typedef DenseMap<FunctionType*, bool, FunctionTypeKeyInfo> FunctionTypeMap;
|
||||
FunctionTypeMap FunctionTypes;
|
||||
typedef DenseMap<StructType*, bool, AnonStructTypeKeyInfo> StructTypeMap;
|
||||
StructTypeMap AnonStructTypes;
|
||||
StringMap<StructType*> NamedStructTypes;
|
||||
unsigned NamedStructTypesUniqueID;
|
||||
|
||||
|
@ -390,24 +390,20 @@ FunctionType::FunctionType(Type *Result, ArrayRef<Type*> Params,
|
||||
// FunctionType::get - The factory function for the FunctionType class.
|
||||
FunctionType *FunctionType::get(Type *ReturnType,
|
||||
ArrayRef<Type*> Params, bool isVarArg) {
|
||||
// TODO: This is brutally slow.
|
||||
unsigned ParamsSize = Params.size();
|
||||
std::vector<Type*> Key;
|
||||
Key.reserve(ParamsSize + 2);
|
||||
Key.push_back(const_cast<Type*>(ReturnType));
|
||||
for (unsigned i = 0, e = ParamsSize; i != e; ++i)
|
||||
Key.push_back(const_cast<Type*>(Params[i]));
|
||||
if (isVarArg)
|
||||
Key.push_back(0);
|
||||
|
||||
LLVMContextImpl *pImpl = ReturnType->getContext().pImpl;
|
||||
FunctionType *&FT = pImpl->FunctionTypes[Key];
|
||||
|
||||
if (FT == 0) {
|
||||
FunctionTypeKeyInfo::KeyTy Key(ReturnType, Params, isVarArg);
|
||||
LLVMContextImpl::FunctionTypeMap::iterator I =
|
||||
pImpl->FunctionTypes.find_as(Key);
|
||||
FunctionType *FT;
|
||||
|
||||
if (I == pImpl->FunctionTypes.end()) {
|
||||
FT = (FunctionType*) pImpl->TypeAllocator.
|
||||
Allocate(sizeof(FunctionType) + sizeof(Type*) * (ParamsSize + 1),
|
||||
Allocate(sizeof(FunctionType) + sizeof(Type*) * (Params.size() + 1),
|
||||
AlignOf<FunctionType>::Alignment);
|
||||
new (FT) FunctionType(ReturnType, Params, isVarArg);
|
||||
pImpl->FunctionTypes[FT] = true;
|
||||
} else {
|
||||
FT = I->first;
|
||||
}
|
||||
|
||||
return FT;
|
||||
@ -440,24 +436,22 @@ bool FunctionType::isValidArgumentType(Type *ArgTy) {
|
||||
|
||||
StructType *StructType::get(LLVMContext &Context, ArrayRef<Type*> ETypes,
|
||||
bool isPacked) {
|
||||
// FIXME: std::vector is horribly inefficient for this probe.
|
||||
unsigned ETypesSize = ETypes.size();
|
||||
std::vector<Type*> Key(ETypesSize);
|
||||
for (unsigned i = 0, e = ETypesSize; i != e; ++i) {
|
||||
assert(isValidElementType(ETypes[i]) &&
|
||||
"Invalid type for structure element!");
|
||||
Key[i] = ETypes[i];
|
||||
LLVMContextImpl *pImpl = Context.pImpl;
|
||||
AnonStructTypeKeyInfo::KeyTy Key(ETypes, isPacked);
|
||||
LLVMContextImpl::StructTypeMap::iterator I =
|
||||
pImpl->AnonStructTypes.find_as(Key);
|
||||
StructType *ST;
|
||||
|
||||
if (I == pImpl->AnonStructTypes.end()) {
|
||||
// Value not found. Create a new type!
|
||||
ST = new (Context.pImpl->TypeAllocator) StructType(Context);
|
||||
ST->setSubclassData(SCDB_IsLiteral); // Literal struct.
|
||||
ST->setBody(ETypes, isPacked);
|
||||
Context.pImpl->AnonStructTypes[ST] = true;
|
||||
} else {
|
||||
ST = I->first;
|
||||
}
|
||||
if (isPacked)
|
||||
Key.push_back(0);
|
||||
|
||||
StructType *&ST = Context.pImpl->AnonStructTypes[Key];
|
||||
if (ST) return ST;
|
||||
|
||||
// Value not found. Create a new type!
|
||||
ST = new (Context.pImpl->TypeAllocator) StructType(Context);
|
||||
ST->setSubclassData(SCDB_IsLiteral); // Literal struct.
|
||||
ST->setBody(ETypes, isPacked);
|
||||
|
||||
return ST;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user