llvm-6502/lib/VMCore/SymbolTable.cpp
Chris Lattner 7685ac8d35 This checkin basically amounts to a complete rewrite of the type-resolution
machinery.  This dramatically simplifies how things works, removes irritating
little corner cases, and overall improves speed and reliability.

Highlights of this change are:

1. The exponential algorithm built into the code is now gone.  For example
   the time to disassemble one bytecode file from the mesa benchmark went
   from taking 12.5s to taking 0.16s.
2. The linker bugs should be dramatically reduced.  The one remaining bug
   has to do with constant handling, which I actually introduced in
   "union-find" checkins.
3. The code is much easier to follow, as a result of fewer special cases.
   It's probably also smaller.  yaay.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8842 91177308-0d34-0410-b5e6-96231b3b80d8
2003-10-03 18:46:24 +00:00

351 lines
12 KiB
C++

//===-- SymbolTable.cpp - Implement the SymbolTable class -------------------=//
//
// This file implements the SymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//
#include "llvm/SymbolTable.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "Support/StringExtras.h"
#include <algorithm>
#define DEBUG_SYMBOL_TABLE 0
#define DEBUG_ABSTYPE 0
SymbolTable::~SymbolTable() {
// Drop all abstract type references in the type plane...
iterator TyPlane = find(Type::TypeTy);
if (TyPlane != end()) {
VarMap &TyP = TyPlane->second;
for (VarMap::iterator I = TyP.begin(), E = TyP.end(); I != E; ++I) {
const Type *Ty = cast<Type>(I->second);
if (Ty->isAbstract()) // If abstract, drop the reference...
cast<DerivedType>(Ty)->removeAbstractTypeUser(this);
}
}
// TODO: FIXME: BIG ONE: This doesn't unreference abstract types for the planes
// that could still have entries!
#ifndef NDEBUG // Only do this in -g mode...
bool LeftoverValues = true;
for (iterator i = begin(); i != end(); ++i) {
for (type_iterator I = i->second.begin(); I != i->second.end(); ++I)
if (!isa<Constant>(I->second) && !isa<Type>(I->second)) {
std::cerr << "Value still in symbol table! Type = '"
<< i->first->getDescription() << "' Name = '"
<< I->first << "'\n";
LeftoverValues = false;
}
}
assert(LeftoverValues && "Values remain in symbol table!");
#endif
}
// getUniqueName - Given a base name, return a string that is either equal to
// it (or derived from it) that does not already occur in the symbol table for
// the specified type.
//
std::string SymbolTable::getUniqueName(const Type *Ty,
const std::string &BaseName) {
iterator I = find(Ty);
if (I == end()) return BaseName;
std::string TryName = BaseName;
unsigned Counter = 0;
type_iterator End = I->second.end();
while (I->second.find(TryName) != End) // Loop until we find unoccupied
TryName = BaseName + utostr(++Counter); // Name in the symbol table
return TryName;
}
// lookup - Returns null on failure...
Value *SymbolTable::lookup(const Type *Ty, const std::string &Name) {
iterator I = find(Ty);
if (I != end()) { // We have symbols in that plane...
type_iterator J = I->second.find(Name);
if (J != I->second.end()) // and the name is in our hash table...
return J->second;
}
return 0;
}
void SymbolTable::remove(Value *N) {
assert(N->hasName() && "Value doesn't have name!");
if (InternallyInconsistent) return;
iterator I = find(N->getType());
assert(I != end() &&
"Trying to remove a type that doesn't have a plane yet!");
removeEntry(I, I->second.find(N->getName()));
}
// removeEntry - Remove a value from the symbol table...
//
Value *SymbolTable::removeEntry(iterator Plane, type_iterator Entry) {
if (InternallyInconsistent) return 0;
assert(Plane != super::end() &&
Entry != Plane->second.end() && "Invalid entry to remove!");
Value *Result = Entry->second;
const Type *Ty = Result->getType();
#if DEBUG_SYMBOL_TABLE
dump();
std::cerr << " Removing Value: " << Result->getName() << "\n";
#endif
// Remove the value from the plane...
Plane->second.erase(Entry);
// If the plane is empty, remove it now!
if (Plane->second.empty()) {
// If the plane represented an abstract type that we were interested in,
// unlink ourselves from this plane.
//
if (Plane->first->isAbstract()) {
#if DEBUG_ABSTYPE
std::cerr << "Plane Empty: Removing type: "
<< Plane->first->getDescription() << "\n";
#endif
cast<DerivedType>(Plane->first)->removeAbstractTypeUser(this);
}
erase(Plane);
}
// If we are removing an abstract type, remove the symbol table from it's use
// list...
if (Ty == Type::TypeTy) {
const Type *T = cast<Type>(Result);
if (T->isAbstract()) {
#if DEBUG_ABSTYPE
std::cerr << "Removing abs type from symtab" << T->getDescription()<<"\n";
#endif
cast<DerivedType>(T)->removeAbstractTypeUser(this);
}
}
return Result;
}
// insertEntry - Insert a value into the symbol table with the specified
// name...
//
void SymbolTable::insertEntry(const std::string &Name, const Type *VTy,
Value *V) {
// Check to see if there is a naming conflict. If so, rename this value!
if (lookup(VTy, Name)) {
std::string UniqueName = getUniqueName(VTy, Name);
assert(InternallyInconsistent == false && "Infinite loop inserting entry!");
InternallyInconsistent = true;
V->setName(UniqueName, this);
InternallyInconsistent = false;
return;
}
#if DEBUG_SYMBOL_TABLE
dump();
std::cerr << " Inserting definition: " << Name << ": "
<< VTy->getDescription() << "\n";
#endif
iterator I = find(VTy);
if (I == end()) { // Not in collection yet... insert dummy entry
// Insert a new empty element. I points to the new elements.
I = super::insert(make_pair(VTy, VarMap())).first;
assert(I != end() && "How did insert fail?");
// Check to see if the type is abstract. If so, it might be refined in the
// future, which would cause the plane of the old type to get merged into
// a new type plane.
//
if (VTy->isAbstract()) {
cast<DerivedType>(VTy)->addAbstractTypeUser(this);
#if DEBUG_ABSTYPE
std::cerr << "Added abstract type value: " << VTy->getDescription()
<< "\n";
#endif
}
}
I->second.insert(make_pair(Name, V));
// If we are adding an abstract type, add the symbol table to it's use list.
if (VTy == Type::TypeTy) {
const Type *T = cast<Type>(V);
if (T->isAbstract()) {
cast<DerivedType>(T)->addAbstractTypeUser(this);
#if DEBUG_ABSTYPE
std::cerr << "Added abstract type to ST: " << T->getDescription() << "\n";
#endif
}
}
}
// This function is called when one of the types in the type plane are refined
void SymbolTable::refineAbstractType(const DerivedType *OldType,
const Type *NewType) {
// Search to see if we have any values of the type oldtype. If so, we need to
// move them into the newtype plane...
iterator TPI = find(OldType);
if (TPI != end()) {
// Get a handle to the new type plane...
iterator NewTypeIt = find(NewType);
if (NewTypeIt == super::end()) { // If no plane exists, add one
NewTypeIt = super::insert(make_pair(NewType, VarMap())).first;
if (NewType->isAbstract()) {
cast<DerivedType>(NewType)->addAbstractTypeUser(this);
#if DEBUG_ABSTYPE
std::cerr << "[Added] refined to abstype: " << NewType->getDescription()
<< "\n";
#endif
}
}
VarMap &NewPlane = NewTypeIt->second;
VarMap &OldPlane = TPI->second;
while (!OldPlane.empty()) {
std::pair<const std::string, Value*> V = *OldPlane.begin();
// Check to see if there is already a value in the symbol table that this
// would collide with.
type_iterator TI = NewPlane.find(V.first);
if (TI != NewPlane.end() && TI->second == V.second) {
// No action
} else if (TI != NewPlane.end()) {
// The only thing we are allowing for now is two external global values
// folded into one.
//
GlobalValue *ExistGV = dyn_cast<GlobalValue>(TI->second);
GlobalValue *NewGV = dyn_cast<GlobalValue>(V.second);
if (ExistGV && NewGV) {
assert((ExistGV->isExternal() || NewGV->isExternal()) &&
"Two planes folded together with overlapping value names!");
// Make sure that ExistGV is the one we want to keep!
if (!NewGV->isExternal())
std::swap(NewGV, ExistGV);
// Ok we have two external global values. Make all uses of the new
// one use the old one...
NewGV->uncheckedReplaceAllUsesWith(ExistGV);
// Now we just convert it to an unnamed method... which won't get
// added to our symbol table. The problem is that if we call
// setName on the method that it will try to remove itself from
// the symbol table and die... because it's not in the symtab
// right now. To fix this, we have an internally consistent flag
// that turns remove into a noop. Thus the name will get null'd
// out, but the symbol table won't get upset.
//
assert(InternallyInconsistent == false &&
"Symbol table already inconsistent!");
InternallyInconsistent = true;
// Remove newM from the symtab
NewGV->setName("");
InternallyInconsistent = false;
// Now we can remove this global from the module entirely...
Module *M = NewGV->getParent();
if (Function *F = dyn_cast<Function>(NewGV))
M->getFunctionList().remove(F);
else
M->getGlobalList().remove(cast<GlobalVariable>(NewGV));
delete NewGV;
}
} else {
insertEntry(V.first, NewType, V.second);
}
// Remove the item from the old type plane
OldPlane.erase(OldPlane.begin());
}
// Ok, now we are not referencing the type anymore... take me off your user
// list please!
#if DEBUG_ABSTYPE
std::cerr << "Removing type " << OldType->getDescription() << "\n";
#endif
OldType->removeAbstractTypeUser(this);
// Remove the plane that is no longer used
erase(TPI);
}
TPI = find(Type::TypeTy);
if (TPI != end()) {
// Loop over all of the types in the symbol table, replacing any references
// to OldType with references to NewType. Note that there may be multiple
// occurrences, and although we only need to remove one at a time, it's
// faster to remove them all in one pass.
//
VarMap &TyPlane = TPI->second;
for (VarMap::iterator I = TyPlane.begin(), E = TyPlane.end(); I != E; ++I)
if (I->second == (Value*)OldType) { // FIXME when Types aren't const.
#if DEBUG_ABSTYPE
std::cerr << "Removing type " << OldType->getDescription() << "\n";
#endif
OldType->removeAbstractTypeUser(this);
I->second = (Value*)NewType; // TODO FIXME when types aren't const
if (NewType->isAbstract()) {
#if DEBUG_ABSTYPE
std::cerr << "Added type " << NewType->getDescription() << "\n";
#endif
cast<DerivedType>(NewType)->addAbstractTypeUser(this);
}
}
}
}
void SymbolTable::typeBecameConcrete(const DerivedType *AbsTy) {
iterator TPI = find(AbsTy);
// If there are any values in the symbol table of this type, then the type
// plan is a use of the abstract type which must be dropped.
if (TPI != end())
AbsTy->removeAbstractTypeUser(this);
TPI = find(Type::TypeTy);
if (TPI != end()) {
// Loop over all of the types in the symbol table, dropping any abstract
// type user entries for AbsTy which occur because there are names for the
// type.
//
VarMap &TyPlane = TPI->second;
for (VarMap::iterator I = TyPlane.begin(), E = TyPlane.end(); I != E; ++I)
if (I->second == (Value*)AbsTy) // FIXME when Types aren't const.
AbsTy->removeAbstractTypeUser(this);
}
}
static void DumpVal(const std::pair<const std::string, Value *> &V) {
std::cout << " '" << V.first << "' = ";
V.second->dump();
std::cout << "\n";
}
static void DumpPlane(const std::pair<const Type *,
std::map<const std::string, Value *> >&P){
std::cout << " Plane: ";
P.first->dump();
std::cout << "\n";
for_each(P.second.begin(), P.second.end(), DumpVal);
}
void SymbolTable::dump() const {
std::cout << "Symbol table dump:\n";
for_each(begin(), end(), DumpPlane);
}