mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
Change the code to no longer compute the "type description" immediately when
the type is analyzed. Instead, only compute it when requested (with getDescription), and cached for reuse later. This dramatically speeds up LLVM in general because these descriptions almost _never_ need to be constructed. The only time they are used is when a type is <<'d. Printing of modules by themselves uses other code to print symbolic types when possible, so these descriptions are really only used for debugging. Also, this fixes the particularly bad case when lots of types get resolved to each other, such as during linking of large programs. In these cases, the type descriptions would be repeatedly recomputed and discarded even though: A. noone reads the description before it gets resolved, and B. many many resolutions happen at intermediate steps, causing a HUGE waste of time. Overall, this makes the getTypeDesc function much more light-weight, and fixes bug: Assembler/2002-07-08-HugePerformanceProblem.llx, which went from taking 1048.770u/19.150s (which is 17.5 MINUTES, on apoc), to taking 0.020u/0.000s, which is a nice little speedup. :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8320 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b44cacb647
commit
dd4b421516
@ -25,6 +25,13 @@
|
||||
static unsigned CurUID = 0;
|
||||
static std::vector<const Type *> UIDMappings;
|
||||
|
||||
// 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 std::map<const Type*, std::string> ConcreteTypeDescriptions;
|
||||
static std::map<const Type*, std::string> AbstractTypeDescriptions;
|
||||
|
||||
void PATypeHolder::dump() const {
|
||||
std::cerr << "PATypeHolder(" << (void*)this << ")\n";
|
||||
}
|
||||
@ -32,7 +39,7 @@ void PATypeHolder::dump() const {
|
||||
|
||||
Type::Type(const std::string &name, PrimitiveID id)
|
||||
: Value(Type::TypeTy, Value::TypeVal) {
|
||||
setDescription(name);
|
||||
ConcreteTypeDescriptions[this] = name;
|
||||
ID = id;
|
||||
Abstract = Recursive = false;
|
||||
UID = CurUID++; // Assign types UID's as they are created
|
||||
@ -114,6 +121,125 @@ unsigned Type::getPrimitiveSize() const {
|
||||
}
|
||||
|
||||
|
||||
// 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.lower_bound(Ty);
|
||||
if (I != AbstractTypeDescriptions.end() && I->first == Ty)
|
||||
return I->second;
|
||||
std::string Desc = "opaque"+utostr(Ty->getUniqueID());
|
||||
AbstractTypeDescriptions.insert(std::make_pair(Ty, Desc));
|
||||
return Desc;
|
||||
}
|
||||
|
||||
if (!Ty->isAbstract() && !Ty->isRecursive()) { // Base case for the recursion
|
||||
std::map<const Type*, std::string>::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->getPrimitiveID()) {
|
||||
case Type::FunctionTyID: {
|
||||
const FunctionType *FTy = cast<FunctionType>(Ty);
|
||||
Result = getTypeDescription(FTy->getReturnType(), TypeStack) + " (";
|
||||
for (FunctionType::ParamTypes::const_iterator
|
||||
I = FTy->getParamTypes().begin(),
|
||||
E = FTy->getParamTypes().end(); I != E; ++I) {
|
||||
if (I != FTy->getParamTypes().begin())
|
||||
Result += ", ";
|
||||
Result += getTypeDescription(*I, TypeStack);
|
||||
}
|
||||
if (FTy->isVarArg()) {
|
||||
if (!FTy->getParamTypes().empty()) Result += ", ";
|
||||
Result += "...";
|
||||
}
|
||||
Result += ")";
|
||||
break;
|
||||
}
|
||||
case Type::StructTyID: {
|
||||
const StructType *STy = cast<StructType>(Ty);
|
||||
Result = "{ ";
|
||||
for (StructType::ElementTypes::const_iterator
|
||||
I = STy->getElementTypes().begin(),
|
||||
E = STy->getElementTypes().end(); I != E; ++I) {
|
||||
if (I != STy->getElementTypes().begin())
|
||||
Result += ", ";
|
||||
Result += getTypeDescription(*I, TypeStack);
|
||||
}
|
||||
Result += " }";
|
||||
break;
|
||||
}
|
||||
case Type::PointerTyID: {
|
||||
const PointerType *PTy = cast<PointerType>(Ty);
|
||||
Result = getTypeDescription(PTy->getElementType(), TypeStack) + " *";
|
||||
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;
|
||||
}
|
||||
default:
|
||||
assert(0 && "Unhandled type in getTypeDescription!");
|
||||
Result = "<error>";
|
||||
}
|
||||
|
||||
TypeStack.pop_back(); // Remove self from stack...
|
||||
|
||||
// In order to reduce the amount of repeated computation, we cache the computd
|
||||
// value for later.
|
||||
if (Ty->isAbstract())
|
||||
AbstractTypeDescriptions[Ty] = Result;
|
||||
else
|
||||
ConcreteTypeDescriptions[Ty] = Result;
|
||||
|
||||
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;
|
||||
getTypeDescription(Ty, TypeStack);
|
||||
assert(Map.count(Ty) && "Type didn't get inserted!!");
|
||||
return Map[Ty];
|
||||
}
|
||||
|
||||
|
||||
const std::string &Type::getDescription() const {
|
||||
if (isAbstract())
|
||||
return getOrCreateDesc(AbstractTypeDescriptions, this);
|
||||
else
|
||||
return getOrCreateDesc(ConcreteTypeDescriptions, this);
|
||||
}
|
||||
|
||||
|
||||
bool StructType::indexValid(const Value *V) const {
|
||||
if (!isa<Constant>(V)) return false;
|
||||
if (V->getType() != Type::UByteTy) return false;
|
||||
@ -247,7 +373,6 @@ PointerType::PointerType(const Type *E) : SequentialType(PointerTyID, E) {
|
||||
|
||||
OpaqueType::OpaqueType() : DerivedType(OpaqueTyID) {
|
||||
setAbstract(true);
|
||||
setDescription("opaque"+utostr(getUniqueID()));
|
||||
#ifdef DEBUG_MERGE_TYPES
|
||||
std::cerr << "Derived new type: " << getDescription() << "\n";
|
||||
#endif
|
||||
@ -266,87 +391,64 @@ OpaqueType::OpaqueType() : DerivedType(OpaqueTyID) {
|
||||
// some whacko opaque types, but in most cases, it will do some simple stuff
|
||||
// when it hits non-abstract types that aren't recursive.
|
||||
//
|
||||
static std::string getTypeProps(const Type *Ty,
|
||||
std::vector<const Type *> &TypeStack,
|
||||
bool &isAbstract, bool &isRecursive) {
|
||||
if (!Ty->isAbstract() && !Ty->isRecursive() && // Base case for the recursion
|
||||
Ty->getDescription().size()) {
|
||||
return Ty->getDescription(); // Primitive = leaf type
|
||||
} else if (isa<OpaqueType>(Ty)) { // Base case for the recursion
|
||||
isAbstract = true; // This whole type is abstract!
|
||||
return Ty->getDescription(); // Opaque = leaf type
|
||||
} else {
|
||||
// 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) {
|
||||
isRecursive = true; // We know we are recursive
|
||||
return "\\" + utostr(CurSize-Slot); // Here's the upreference
|
||||
} else { // Recursive case: abstract derived type...
|
||||
std::string Result;
|
||||
TypeStack.push_back(Ty); // Add us to the stack..
|
||||
|
||||
switch (Ty->getPrimitiveID()) {
|
||||
case Type::FunctionTyID: {
|
||||
const FunctionType *MTy = cast<FunctionType>(Ty);
|
||||
Result = getTypeProps(MTy->getReturnType(), TypeStack,
|
||||
isAbstract, isRecursive)+" (";
|
||||
for (FunctionType::ParamTypes::const_iterator
|
||||
I = MTy->getParamTypes().begin(),
|
||||
E = MTy->getParamTypes().end(); I != E; ++I) {
|
||||
if (I != MTy->getParamTypes().begin())
|
||||
Result += ", ";
|
||||
Result += getTypeProps(*I, TypeStack, isAbstract, isRecursive);
|
||||
}
|
||||
if (MTy->isVarArg()) {
|
||||
if (!MTy->getParamTypes().empty()) Result += ", ";
|
||||
Result += "...";
|
||||
}
|
||||
Result += ")";
|
||||
break;
|
||||
}
|
||||
case Type::StructTyID: {
|
||||
const StructType *STy = cast<StructType>(Ty);
|
||||
Result = "{ ";
|
||||
for (StructType::ElementTypes::const_iterator
|
||||
I = STy->getElementTypes().begin(),
|
||||
E = STy->getElementTypes().end(); I != E; ++I) {
|
||||
if (I != STy->getElementTypes().begin())
|
||||
Result += ", ";
|
||||
Result += getTypeProps(*I, TypeStack, isAbstract, isRecursive);
|
||||
}
|
||||
Result += " }";
|
||||
break;
|
||||
}
|
||||
case Type::PointerTyID: {
|
||||
const PointerType *PTy = cast<PointerType>(Ty);
|
||||
Result = getTypeProps(PTy->getElementType(), TypeStack,
|
||||
isAbstract, isRecursive) + " *";
|
||||
break;
|
||||
}
|
||||
case Type::ArrayTyID: {
|
||||
const ArrayType *ATy = cast<ArrayType>(Ty);
|
||||
unsigned NumElements = ATy->getNumElements();
|
||||
Result = "[";
|
||||
Result += utostr(NumElements) + " x ";
|
||||
Result += getTypeProps(ATy->getElementType(), TypeStack,
|
||||
isAbstract, isRecursive) + "]";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "Unhandled case in getTypeProps!");
|
||||
Result = "<error>";
|
||||
}
|
||||
|
||||
TypeStack.pop_back(); // Remove self from stack...
|
||||
return Result;
|
||||
}
|
||||
static void getTypeProps(const Type *Ty, std::vector<const Type *> &TypeStack,
|
||||
bool &isAbstract, bool &isRecursive) {
|
||||
if (!Ty->isAbstract() && !Ty->isRecursive()) // Base case for the recursion
|
||||
return; // Primitive = leaf type
|
||||
|
||||
if (isa<OpaqueType>(Ty)) { // Base case for the recursion
|
||||
isAbstract = true; // This whole type is abstract!
|
||||
return; // Opaque = leaf type
|
||||
}
|
||||
|
||||
// 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) {
|
||||
isRecursive = true; // We know we are recursive
|
||||
return;
|
||||
}
|
||||
|
||||
// Recursive case: derived type...
|
||||
TypeStack.push_back(Ty); // Add us to the stack..
|
||||
|
||||
switch (Ty->getPrimitiveID()) {
|
||||
case Type::FunctionTyID: {
|
||||
const FunctionType *FTy = cast<FunctionType>(Ty);
|
||||
getTypeProps(FTy->getReturnType(), TypeStack, isAbstract, isRecursive);
|
||||
for (FunctionType::ParamTypes::const_iterator
|
||||
I = FTy->getParamTypes().begin(),
|
||||
E = FTy->getParamTypes().end(); I != E; ++I)
|
||||
getTypeProps(*I, TypeStack, isAbstract, isRecursive);
|
||||
break;
|
||||
}
|
||||
case Type::StructTyID: {
|
||||
const StructType *STy = cast<StructType>(Ty);
|
||||
for (StructType::ElementTypes::const_iterator
|
||||
I = STy->getElementTypes().begin(),
|
||||
E = STy->getElementTypes().end(); I != E; ++I)
|
||||
getTypeProps(*I, TypeStack, isAbstract, isRecursive);
|
||||
break;
|
||||
}
|
||||
case Type::PointerTyID: {
|
||||
const PointerType *PTy = cast<PointerType>(Ty);
|
||||
getTypeProps(PTy->getElementType(), TypeStack, isAbstract, isRecursive);
|
||||
break;
|
||||
}
|
||||
case Type::ArrayTyID:
|
||||
getTypeProps(cast<ArrayType>(Ty)->getElementType(), TypeStack,
|
||||
isAbstract, isRecursive);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unhandled type in getTypeProps!");
|
||||
}
|
||||
|
||||
TypeStack.pop_back(); // Remove self from stack...
|
||||
}
|
||||
|
||||
|
||||
@ -358,7 +460,7 @@ void DerivedType::setDerivedTypeProperties() {
|
||||
std::vector<const Type *> TypeStack;
|
||||
bool isAbstract = false, isRecursive = false;
|
||||
|
||||
setDescription(getTypeProps(this, TypeStack, isAbstract, isRecursive));
|
||||
getTypeProps(this, TypeStack, isAbstract, isRecursive);
|
||||
setAbstract(isAbstract);
|
||||
setRecursive(isRecursive);
|
||||
}
|
||||
@ -402,8 +504,8 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2,
|
||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
|
||||
if (ATy->getNumElements() != cast<ArrayType>(Ty2)->getNumElements())
|
||||
return false;
|
||||
} else if (const FunctionType *MTy = dyn_cast<FunctionType>(Ty)) {
|
||||
if (MTy->isVarArg() != cast<FunctionType>(Ty2)->isVarArg())
|
||||
} else if (const FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
|
||||
if (FTy->isVarArg() != cast<FunctionType>(Ty2)->isVarArg())
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -846,6 +948,9 @@ void DerivedType::removeAbstractTypeUser(AbstractTypeUser *U) const {
|
||||
void DerivedType::refineAbstractTypeTo(const Type *NewType) {
|
||||
assert(isAbstract() && "refineAbstractTypeTo: Current type is not abstract!");
|
||||
assert(this != NewType && "Can't refine to myself!");
|
||||
|
||||
// The descriptions may be out of date. Conservatively clear them all!
|
||||
AbstractTypeDescriptions.clear();
|
||||
|
||||
#ifdef DEBUG_MERGE_TYPES
|
||||
std::cerr << "REFINING abstract type [" << (void*)this << " "
|
||||
|
Loading…
Reference in New Issue
Block a user