Unfortunately the fix for the previous bug introduced the previous

exponential behavior (bork!).  This patch processes stuff with an
explicit SCC finder, allowing the algorithm to be more clear,
efficient, and also (as a bonus) correct!  This gets us back to taking
0.6s to disassemble my horrible .bc file that previously took something
> 30 mins.

llvm-svn: 16811
This commit is contained in:
Chris Lattner 2004-10-07 19:20:48 +00:00
parent d299ffee01
commit 251093ca5d
1 changed files with 64 additions and 38 deletions

View File

@ -17,6 +17,7 @@
#include "llvm/Constants.h" #include "llvm/Constants.h"
#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
@ -443,44 +444,76 @@ void DerivedType::dropAllTypeUses() {
} }
} }
/// TypePromotionGraph and graph traits - this is designed to allow us to do
/// efficient SCC processing of type graphs. This is the exact same as
/// GraphTraits<Type*>, except that we pretend that concrete types have no
/// children to avoid processing them.
struct TypePromotionGraph {
Type *Ty;
TypePromotionGraph(Type *T) : Ty(T) {}
};
namespace llvm {
template <> struct GraphTraits<TypePromotionGraph> {
typedef Type NodeType;
typedef Type::subtype_iterator ChildIteratorType;
static inline NodeType *getEntryNode(TypePromotionGraph G) { return G.Ty; }
static inline ChildIteratorType child_begin(NodeType *N) {
if (N->isAbstract())
return N->subtype_begin();
else // No need to process children of concrete types.
return N->subtype_end();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->subtype_end();
}
};
}
// PromoteAbstractToConcrete - This is a recursive function that walks a type // PromoteAbstractToConcrete - This is a recursive function that walks a type
// graph calculating whether or not a type is abstract. // graph calculating whether or not a type is abstract.
// //
// This method returns true if the type is found to still be abstract. // This method returns true if the type is found to still be abstract.
// //
bool Type::PromoteAbstractToConcrete(void *Ptr) { void Type::PromoteAbstractToConcrete() {
if (!isAbstract()) // Base case for the recursion if (!isAbstract()) return;
return false; // Primitive = leaf type
if (isa<OpaqueType>(this)) // Base case for the recursion
return true; // This whole type is abstract!
/// KnownAbstractTypes - This set contains all of the types that we know for scc_iterator<TypePromotionGraph> SI = scc_begin(TypePromotionGraph(this));
/// sure are abstract. Once we discover that a type really is abstract, we scc_iterator<TypePromotionGraph> SE = scc_end (TypePromotionGraph(this));
/// remember this so we don't have to do potentially exponential amounts of
/// checking in some cases.
std::set<Type*> &KnownAbstractTypes = *(std::set<Type*>*)Ptr;
if (KnownAbstractTypes.count(this))
return true; // We already know this type is abstract!
// We have to guard against recursion. To do this, we temporarily mark this for (; SI != SE; ++SI) {
// type as concrete, so that if we get back to here recursively we will think std::vector<Type*> &SCC = *SI;
// it's not abstract, and thus not scan it again.
setAbstract(false);
// Scan all of the sub-types. If any of them are abstract, than so is this // Concrete types are leaves in the tree. Since an SCC will either be all
// one! // abstract or all concrete, we only need to check one type.
for (Type::subtype_iterator I = subtype_begin(), E = subtype_end(); if (SCC[0]->isAbstract()) {
I != E; ++I) if (isa<OpaqueType>(SCC[0]))
if (const_cast<Type*>(I->get())->PromoteAbstractToConcrete(Ptr)) { return; // Not going to be concrete, sorry.
KnownAbstractTypes.insert(this);
setAbstract(true); // Restore the abstract bit. // If all of the children of all of the types in this SCC are concrete,
return true; // This type is abstract if subtype is abstract! // then this SCC is now concrete as well. If not, neither this SCC, nor
// any parent SCCs will be concrete, so we might as well just exit.
for (unsigned i = 0, e = SCC.size(); i != e; ++i)
for (Type::subtype_iterator CI = SCC[i]->subtype_begin(),
E = SCC[i]->subtype_end(); CI != E; ++CI)
if ((*CI)->isAbstract())
return; // Not going to be concrete, sorry.
// Okay, we just discovered this whole SCC is now concrete, mark it as
// such!
for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
assert(SCC[i]->isAbstract() && "Why are we processing concrete types?");
SCC[i]->setAbstract(false);
// The type just became concrete, notify all users!
cast<DerivedType>(SCC[i])->notifyUsesThatTypeBecameConcrete();
}
} }
}
// Nothing looks abstract here. Restore the abstract flag.
setAbstract(true);
return false;
} }
@ -730,15 +763,8 @@ public:
// If the type is currently thought to be abstract, rescan all of our // If the type is currently thought to be abstract, rescan all of our
// subtypes to see if the type has just become concrete! // subtypes to see if the type has just become concrete!
if (Ty->isAbstract()) { if (Ty->isAbstract())
std::set<Type*> KnownAbstractTypes; Ty->PromoteAbstractToConcrete();
if (!Ty->PromoteAbstractToConcrete(&KnownAbstractTypes))
Ty->setAbstract(false);
// If the type just became concrete, notify all users!
if (!Ty->isAbstract())
Ty->notifyUsesThatTypeBecameConcrete();
}
} }
void print(const char *Arg) const { void print(const char *Arg) const {