//===-- SymbolTable.cpp - Implement the SymbolTable class -----------------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // 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 #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(I->second); if (Ty->isAbstract()) // If abstract, drop the reference... cast(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(I->second) && !isa(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(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(Result); if (T->isAbstract()) { #if DEBUG_ABSTYPE std::cerr << "Removing abs type from symtab" << T->getDescription()<<"\n"; #endif cast(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(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(V); if (T->isAbstract()) { cast(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(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 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(TI->second); GlobalValue *NewGV = dyn_cast(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(NewGV)) M->getFunctionList().remove(F); else M->getGlobalList().remove(cast(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(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 &V) { std::cout << " '" << V.first << "' = "; V.second->dump(); std::cout << "\n"; } static void DumpPlane(const std::pair >&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); }