From eb7116bb08a99897c69570a3789af97343bff9f2 Mon Sep 17 00:00:00 2001 From: Reid Spencer Date: Tue, 10 Jan 2006 09:51:48 +0000 Subject: [PATCH] For PR411: First step in refactoring the SymbolTable is to split it into two classes, one for a symbol table of types and one for a symbol table of Values. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25175 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/TypeSymbolTable.h | 152 +++++++++++++++++++++++++ include/llvm/ValueSymbolTable.h | 138 +++++++++++++++++++++++ lib/VMCore/TypeSymbolTable.cpp | 193 ++++++++++++++++++++++++++++++++ lib/VMCore/ValueSymbolTable.cpp | 167 +++++++++++++++++++++++++++ 4 files changed, 650 insertions(+) create mode 100644 include/llvm/TypeSymbolTable.h create mode 100644 include/llvm/ValueSymbolTable.h create mode 100644 lib/VMCore/TypeSymbolTable.cpp create mode 100644 lib/VMCore/ValueSymbolTable.cpp diff --git a/include/llvm/TypeSymbolTable.h b/include/llvm/TypeSymbolTable.h new file mode 100644 index 00000000000..6511be03db0 --- /dev/null +++ b/include/llvm/TypeSymbolTable.h @@ -0,0 +1,152 @@ +//===-- llvm/TypeSymbolTable.h - Implement a Type Symtab --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer based on the original SymbolTable +// implemented by the LLVM Research Group and re-written by Reid Spencer. +// It is distributed under the University of Illinois Open Source License. +// See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the name/type symbol table for LLVM. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TYPE_SYMBOL_TABLE_H +#define LLVM_TYPE_SYMBOL_TABLE_H + +#include "llvm/Type.h" +#include + +namespace llvm { + +/// This class provides a symbol table of name/type pairs with operations to +/// support constructing, searching and iterating over the symbol table. The +/// class derives from AbstractTypeUser so that the contents of the symbol +/// table can be updated when abstract types become concrete. +class TypeSymbolTable : public AbstractTypeUser { + +/// @name Types +/// @{ +public: + + /// @brief A mapping of names to types. + typedef std::map TypeMap; + + /// @brief An iterator over the TypeMap. + typedef TypeMap::iterator iterator; + + /// @brief A const_iterator over the TypeMap. + typedef TypeMap::const_iterator const_iterator; + +/// @} +/// @name Constructors +/// @{ +public: + + TypeSymbolTable() {} + ~TypeSymbolTable(); + +/// @} +/// @name Accessors +/// @{ +public: + + /// Generates a unique name for a type based on the \p BaseName by + /// incrementing an integer and appending it to the name, if necessary + /// @returns the unique name + /// @brief Get a unique name for a type + std::string getUniqueName(const std::string &BaseName) const; + + /// This method finds the type with the given \p name in the type map + /// and returns it. + /// @returns null if the name is not found, otherwise the Type + /// associated with the \p name. + /// @brief Lookup a type by name. + Type* lookup(const std::string& name) const; + + /// @returns true iff the symbol table is empty. + /// @brief Determine if the symbol table is empty + inline bool empty() const { return tmap.empty(); } + + /// @returns the size of the symbol table + /// @brief The number of name/type pairs is returned. + inline unsigned size() const { return unsigned(tmap.size()); } + + /// This function can be used from the debugger to display the + /// content of the symbol table while debugging. + /// @brief Print out symbol table on stderr + void dump() const; + +/// @} +/// @name Iteration +/// @{ +public: + /// Get an iterator to the start of the symbol table + inline iterator begin() { return tmap.begin(); } + + /// @brief Get a const_iterator to the start of the symbol table + inline const_iterator begin() const { return tmap.begin(); } + + /// Get an iterator to the end of the symbol talbe. + inline iterator end() { return tmap.end(); } + + /// Get a const_iterator to the end of the symbol table. + inline const_iterator end() const { return tmap.end(); } + +/// @} +/// @name Mutators +/// @{ +public: + + /// This method will strip the symbol table of its names + /// @brief Strip the symbol table. + bool strip(); + + /// Inserts a type into the symbol table with the specified name. There can be + /// a many-to-one mapping between names and types. This method allows a type + /// with an existing entry in the symbol table to get a new name. + /// @brief Insert a type under a new name. + void insert(const std::string &Name, const Type *Typ); + + /// Remove a type at the specified position in the symbol table. + /// @returns the removed Type. + /// @returns the Type that was erased from the symbol table. + Type* erase(iterator TI); + + /// Remove a specific Type from the symbol table. This isn't fast, linear + /// search, O(n), algorithm. + /// @returns true if the erase was successful (TI was found) + bool erase(Type* TI); + + /// Rename a type. This ain't fast, we have to linearly search for it first. + /// @returns true if the rename was successful (type was found) + bool rename(Type* T, const std::string& new_name); + +/// @} +/// @name AbstractTypeUser Methods +/// @{ +private: + /// This function is called when one of the types in the type plane + /// is refined. + virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy); + + /// This function markes a type as being concrete (defined). + virtual void typeBecameConcrete(const DerivedType *AbsTy); + +/// @} +/// @name Internal Data +/// @{ +private: + TypeMap tmap; ///< This is the mapping of names to types. + mutable unsigned long LastUnique; ///< Counter for tracking unique names + +/// @} + +}; + +} // End llvm namespace + +#endif + diff --git a/include/llvm/ValueSymbolTable.h b/include/llvm/ValueSymbolTable.h new file mode 100644 index 00000000000..df3fe181971 --- /dev/null +++ b/include/llvm/ValueSymbolTable.h @@ -0,0 +1,138 @@ +//===-- llvm/ValueSymbolTable.h - Implement a Value Symtab ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer based on the original SymbolTable.h +// written by the LLVM research group and re-written by Reid Spencer. +// It is distributed under the University of Illinois Open Source License. +// See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the name/Value symbol table for LLVM. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_VALUE_SYMBOL_TABLE_H +#define LLVM_VALUE_SYMBOL_TABLE_H + +#include "llvm/Value.h" +#include + +namespace llvm { + +/// This class provides a symbol table of name/value pairs. It is essentially +/// a std::map but has a controlled interface provided by +/// LLVM as well as ensuring uniqueness of names. +/// +class ValueSymbolTable { + +/// @name Types +/// @{ +public: + + /// @brief A mapping of names to values. + typedef std::map ValueMap; + + /// @brief An iterator over a ValueMap. + typedef ValueMap::iterator iterator; + + /// @brief A const_iterator over a ValueMap. + typedef ValueMap::const_iterator const_iterator; + +/// @} +/// @name Constructors +/// @{ +public: + + ValueSymbolTable() : LastUnique(0) {} + ~ValueSymbolTable(); + +/// @} +/// @name Accessors +/// @{ +public: + + /// This method finds the value with the given \p name in the + /// the symbol table. + /// @returns the value associated with the \p name + /// @brief Lookup a named Value. + Value *lookup(const std::string &name) const; + + /// @returns true iff the symbol table is empty + /// @brief Determine if the symbol table is empty + inline bool empty() const { return vmap.empty(); } + + /// @brief The number of name/type pairs is returned. + inline unsigned size() const { return unsigned(vmap.size()); } + + /// 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. + /// @brief Get a name unique to this symbol table + std::string getUniqueName(const std::string &BaseName) const; + + /// This function can be used from the debugger to display the + /// content of the symbol table while debugging. + /// @brief Print out symbol table on stderr + void dump() const; + +/// @} +/// @name Iteration +/// @{ +public: + + /// @brief Get an iterator that from the beginning of the symbol table. + inline iterator begin() { return vmap.begin(); } + + /// @brief Get a const_iterator that from the beginning of the symbol table. + inline const_iterator begin() const { return vmap.begin(); } + + /// @brief Get an iterator to the end of the symbol table. + inline iterator end() { return vmap.end(); } + + /// @brief Get a const_iterator to the end of the symbol table. + inline const_iterator end() const { return vmap.end(); } + +/// @} +/// @name Mutators +/// @{ +public: + + /// This method will strip the symbol table of its names. + /// @brief Strip the symbol table. + bool strip(); + + /// This method adds the provided value \p N to the symbol table. The Value + /// must have a name which is used to place the value in the symbol table. + /// @brief Add a named value to the symbol table + void insert(Value *Val); + + /// This method removes a value from the symbol table. The name of the + /// Value is extracted from \p Val and used to lookup the Value in the + /// symbol table. If the Value is not in the symbol table, this method + /// returns false. + /// @returns true if \p Val was successfully erased, false otherwise + /// @brief Remove a value from the symbol table. + bool erase(Value* Val); + + /// Given a value with a non-empty name, remove its existing + /// entry from the symbol table and insert a new one for Name. This is + /// equivalent to doing "remove(V), V->Name = Name, insert(V)". + /// @brief Rename a value in the symbol table + bool rename(Value *V, const std::string &Name); + +/// @} +/// @name Internal Data +/// @{ +private: + ValueMap vmap; ///< The map that holds the symbol table. + mutable unsigned long LastUnique; ///< Counter for tracking unique names + +/// @} + +}; + +} // End llvm namespace + +#endif diff --git a/lib/VMCore/TypeSymbolTable.cpp b/lib/VMCore/TypeSymbolTable.cpp new file mode 100644 index 00000000000..e2712d0de6c --- /dev/null +++ b/lib/VMCore/TypeSymbolTable.cpp @@ -0,0 +1,193 @@ +//===-- TypeSymbolTable.cpp - Implement the TypeSymbolTable class ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and revised by Reid +// Spencer. It is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TypeSymbolTable class for the VMCore library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TypeSymbolTable.h" +#include "llvm/DerivedTypes.h" +#include "llvm/ADT/StringExtras.h" +#include + +using namespace llvm; + +#define DEBUG_SYMBOL_TABLE 0 +#define DEBUG_ABSTYPE 0 + +TypeSymbolTable::~TypeSymbolTable() { + // Drop all abstract type references in the type plane... + for (iterator TI = tmap.begin(), TE = tmap.end(); TI != TE; ++TI) { + if (TI->second->isAbstract()) // If abstract, drop the reference... + cast(TI->second)->removeAbstractTypeUser(this); + } +} + +std::string TypeSymbolTable::getUniqueName(const std::string &BaseName) const { + std::string TryName = BaseName; + const_iterator End = tmap.end(); + + // See if the name exists + while (tmap.find(TryName) != End) // Loop until we find a free + TryName = BaseName + utostr(++LastUnique); // name in the symbol table + return TryName; +} + +// lookup a type by name - returns null on failure +Type* TypeSymbolTable::lookup(const std::string& Name) const { + const_iterator TI = tmap.find(Name); + if (TI != tmap.end()) + return const_cast(TI->second); + return 0; +} + +// Erase a specific type from the symbol table +bool TypeSymbolTable::erase(Type *N) { + for (iterator TI = tmap.begin(), TE = tmap.end(); TI != TE; ++TI) { + if (TI->second == N) { + this->erase(TI); + return true; + } + } + return false; +} + +// remove - Remove a type from the symbol table... +Type* TypeSymbolTable::erase(iterator Entry) { + assert(Entry != tmap.end() && "Invalid entry to remove!"); + + const Type* Result = Entry->second; + +#if DEBUG_SYMBOL_TABLE + dump(); + std::cerr << " Removing Value: " << Result->getName() << "\n"; +#endif + + tmap.erase(Entry); + + // If we are removing an abstract type, remove the symbol table from it's use + // list... + if (Result->isAbstract()) { +#if DEBUG_ABSTYPE + std::cerr << "Removing abstract type from symtab" << Result->getDescription()<<"\n"; +#endif + cast(Result)->removeAbstractTypeUser(this); + } + + return const_cast(Result); +} + + +// insert - Insert a type into the symbol table with the specified name... +void TypeSymbolTable::insert(const std::string& Name, const Type* T) { + assert(T && "Can't insert null type into symbol table!"); + + // Check to see if there is a naming conflict. If so, rename this type! + std::string UniqueName = Name; + if (lookup(Name)) + UniqueName = getUniqueName(Name); + +#if DEBUG_SYMBOL_TABLE + dump(); + std::cerr << " Inserting type: " << UniqueName << ": " + << T->getDescription() << "\n"; +#endif + + // Insert the tmap entry + tmap.insert(make_pair(UniqueName, T)); + + // If we are adding an abstract type, add the symbol table to it's use list. + if (T->isAbstract()) { + cast(T)->addAbstractTypeUser(this); +#if DEBUG_ABSTYPE + std::cerr << "Added abstract type to ST: " << T->getDescription() << "\n"; +#endif + } +} + +// Strip the symbol table of its names. +bool TypeSymbolTable::strip() { + bool RemovedSymbol = false; + for (iterator TI = tmap.begin(); TI != tmap.end(); ) { + erase(TI++); + RemovedSymbol = true; + } + + return RemovedSymbol; +} + +/// rename - Given a value with a non-empty name, remove its existing entry +/// from the symbol table and insert a new one for Name. This is equivalent to +/// doing "remove(V), V->Name = Name, insert(V)", but is faster, and will not +/// temporarily remove the symbol table plane if V is the last value in the +/// symtab with that name (which could invalidate iterators to that plane). +bool TypeSymbolTable::rename(Type *T, const std::string &name) { + for (iterator TI = tmap.begin(), TE = tmap.end(); TI != TE; ++TI) { + if (TI->second == T) { + // Remove the old entry. + tmap.erase(TI); + // Add the new entry. + this->insert(name,T); + return true; + } + } + return false; +} + +// This function is called when one of the types in the type plane are refined +void TypeSymbolTable::refineAbstractType(const DerivedType *OldType, + const Type *NewType) { + + // 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. + // + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->second == (Type*)OldType) { // FIXME when Types aren't const. +#if DEBUG_ABSTYPE + std::cerr << "Removing type " << OldType->getDescription() << "\n"; +#endif + OldType->removeAbstractTypeUser(this); + + I->second = (Type*)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); + } + } + } +} + + +// Handle situation where type becomes Concreate from Abstract +void TypeSymbolTable::typeBecameConcrete(const DerivedType *AbsTy) { + // 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. + for (iterator TI = begin(), TE = end(); TI != TE; ++TI) + if (TI->second == const_cast(static_cast(AbsTy))) + AbsTy->removeAbstractTypeUser(this); +} + +static void DumpTypes(const std::pair& T ) { + std::cerr << " '" << T.first << "' = "; + T.second->dump(); + std::cerr << "\n"; +} + +void TypeSymbolTable::dump() const { + std::cerr << "TypeSymbolPlane: "; + for_each(tmap.begin(), tmap.end(), DumpTypes); +} + +// vim: sw=2 ai diff --git a/lib/VMCore/ValueSymbolTable.cpp b/lib/VMCore/ValueSymbolTable.cpp new file mode 100644 index 00000000000..a355bbdd606 --- /dev/null +++ b/lib/VMCore/ValueSymbolTable.cpp @@ -0,0 +1,167 @@ +//===-- ValueSymbolTable.cpp - Implement the ValueSymbolTable class -------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and revised by Reid +// Spencer. It is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ValueSymbolTable class for the VMCore library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/GlobalValue.h" +#include "llvm/Type.h" +#include "llvm/ValueSymbolTable.h" +#include "llvm/ADT/StringExtras.h" +#include +#include + +using namespace llvm; + +#define DEBUG_SYMBOL_TABLE 0 +#define DEBUG_ABSTYPE 0 + +// Class destructor +ValueSymbolTable::~ValueSymbolTable() { +#ifndef NDEBUG // Only do this in -g mode... + bool LeftoverValues = true; + for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ++VI) + if (!isa(VI->second) ) { + std::cerr << "Value still in symbol table! Type = '" + << VI->second->getType()->getDescription() << "' Name = '" + << VI->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 ValueSymbolTable::getUniqueName(const std::string &BaseName) const { + std::string TryName = BaseName; + const_iterator End = vmap.end(); + + // See if the name exists + while (vmap.find(TryName) != End) // Loop until we find a free + TryName = BaseName + utostr(++LastUnique); // name in the symbol table + return TryName; +} + + +// lookup a value - Returns null on failure... +// +Value *ValueSymbolTable::lookup(const std::string &Name) const { + const_iterator VI = vmap.find(Name); + if (VI != vmap.end()) // We found the symbol + return const_cast(VI->second); + return 0; +} + +// Strip the symbol table of its names. +// +bool ValueSymbolTable::strip() { + bool RemovedSymbol = false; + for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ) { + Value *V = VI->second; + ++VI; + if (!isa(V) || cast(V)->hasInternalLinkage()) { + // Set name to "", removing from symbol table! + V->setName(""); + RemovedSymbol = true; + } + } + return RemovedSymbol; +} + +// Insert a value into the symbol table with the specified name... +// +void ValueSymbolTable::insert(Value* V) { + assert(V && "Can't insert null Value into symbol table!"); + assert(V->hasName() && "Can't insert nameless Value into symbol table"); + + // Check to see if there is a naming conflict. If so, rename this type! + std::string UniqueName = getUniqueName(V->getName()); + +#if DEBUG_SYMBOL_TABLE + dump(); + std::cerr << " Inserting value: " << UniqueName << ": " << V->dump() << "\n"; +#endif + + // Insert the vmap entry + vmap.insert(make_pair(UniqueName, V)); +} + +// Remove a value +bool ValueSymbolTable::erase(Value *V) { + assert(V->hasName() && "Value doesn't have name!"); + iterator Entry = vmap.find(V->getName()); + if (Entry == vmap.end()) + return false; + +#if DEBUG_SYMBOL_TABLE + dump(); + std::cerr << " Removing Value: " << Entry->second->getName() << "\n"; +#endif + + // Remove the value from the plane... + vmap.erase(Entry); + return true; +} + + +// rename - Given a value with a non-empty name, remove its existing entry +// from the symbol table and insert a new one for Name. This is equivalent to +// doing "remove(V), V->Name = Name, insert(V)", +// +bool ValueSymbolTable::rename(Value *V, const std::string &name) { + assert(V && "Can't rename a null Value"); + assert(V->hasName() && "Can't rename a nameless Value"); + assert(!V->getName().empty() && "Can't rename an Value with null name"); + assert(V->getName() != name && "Can't rename a Value with same name"); + assert(!name.empty() && "Can't rename a named Value with a null name"); + + // Find the name + iterator VI = vmap.find(V->getName()); + + // If we didn't find it, we're done + if (VI == vmap.end()) + return false; + + // Remove the old entry. + vmap.erase(VI); + + // See if we can insert the new name. + VI = vmap.lower_bound(name); + + // Is there a naming conflict? + if (VI != vmap.end() && VI->first == name) { + V->Name = getUniqueName( name); + vmap.insert(make_pair(V->Name, V)); + } else { + V->Name = name; + vmap.insert(VI, make_pair(name, V)); + } + + return true; +} + +// DumpVal - a std::for_each function for dumping a value +// +static void DumpVal(const std::pair &V) { + std::cerr << " '" << V.first << "' = "; + V.second->dump(); + std::cerr << "\n"; +} + +// dump - print out the symbol table +// +void ValueSymbolTable::dump() const { + std::cerr << "ValueSymbolTable:\n"; + for_each(vmap.begin(), vmap.end(), DumpVal); +} -- 2.34.1