Make the PATypeHolder use a simple union-find implementation to handle
authorChris Lattner <sabre@nondot.org>
Thu, 2 Oct 2003 23:35:57 +0000 (23:35 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 2 Oct 2003 23:35:57 +0000 (23:35 +0000)
merging of types.  This makes it MUCH more efficient than before, also
making things simpler.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8833 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/AbstractTypeUser.h
include/llvm/DerivedTypes.h
include/llvm/Type.h
lib/VMCore/Type.cpp

index 64fcd33a78a01add4d64e99670801e7d2f307418..b9e5f1c6593a2cef25334e3a32d33110ffcb7524 100644 (file)
@@ -61,9 +61,9 @@ public:
 };
 
 
-// PATypeHandle - Handle to a Type subclass.  This class is used to keep the use
-// list of abstract types up-to-date.
-//
+/// PATypeHandle - Handle to a Type subclass.  This class is used to keep the
+/// use list of abstract types up-to-date.
+///
 class PATypeHandle {
   const Type *Ty;
   AbstractTypeUser * const User;
@@ -123,50 +123,43 @@ public:
 };
 
 
-// PATypeHolder - Holder class for a potentially abstract type.  This functions
-// as both a handle (as above) and an AbstractTypeUser.  It uses the callback to
-// keep its pointer member updated to the current version of the type.
-//
-class PATypeHolder : public AbstractTypeUser {
-  PATypeHandle Handle;
+/// PATypeHolder - Holder class for a potentially abstract type.  This uses
+/// efficient union-find techniques to handle dynamic type resolution.  Unless
+/// you need to do custom processing when types are resolved, you should always
+/// use PATypeHolders in preference to PATypeHandles.
+///
+class PATypeHolder {
+  mutable const Type *Ty;
 public:
-  PATypeHolder(const Type *ty) : Handle(ty, this) {}
-  PATypeHolder(const PATypeHolder &T) : AbstractTypeUser(), Handle(T, this) {}
+  PATypeHolder(const Type *ty) : Ty(ty) {
+    addRef();
+  }
+  PATypeHolder(const PATypeHolder &T) : Ty(T.Ty) {
+    addRef();
+  }
 
-  operator const Type *() const { return Handle; }
-  const Type *get() const { return Handle; }
+  operator const Type *() const { return get(); }
+  const Type *get() const;
 
   // operator-> - Allow user to dereference handle naturally...
-  inline const Type *operator->() const { return Handle; }
-
-  // refineAbstractType - All we do is update our PATypeHandle member to point
-  // to the new type.
-  //
-  virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
-    assert(get() == (const Type*)OldTy && "Can't refine to unknown value!");
-
-    // Check to see if the type just became concrete.  If so, we have to
-    // removeUser to get off its AbstractTypeUser list
-    Handle.removeUserFromConcrete();
-
-    if ((const Type*)OldTy != NewTy)
-      Handle.operator=(NewTy);
-  }
+  const Type *operator->() const { return get(); }
 
   // operator= - Allow assignment to handle
   const Type *operator=(const Type *ty) {
-    return Handle = ty;
-  }
-
-  // operator= - Allow assignment to handle
-  const Type *operator=(const PATypeHandle &T) {
-    return Handle = T;
+    if (Ty != ty) {   // Don't accidentally drop last ref to Ty.
+      dropRef();
+      Ty = ty;
+      addRef();
+    }
+    return get();
   }
   const Type *operator=(const PATypeHolder &H) {
-    return Handle = H;
+    return operator=(H.Ty);
   }
 
-  void dump() const;
+private:
+  void addRef();
+  void dropRef();
 };
 
 #endif
index 73587b4824df095ca98f1c5e20e8390e22e64e02..5ed30458fb8f12f566d4f715a5869397ac8c7fbb 100644 (file)
@@ -20,7 +20,14 @@ class StructValType;
 class PointerValType;
 
 class DerivedType : public Type, public AbstractTypeUser {
-  char isRefining;                                   // Used for recursive types
+  /// RefCount - This counts the number of PATypeHolders that are pointing to
+  /// this type.  When this number falls to zero, if the type is abstract and
+  /// has no AbstractTypeUsers, the type is deleted.
+  ///
+  mutable unsigned RefCount;
+  
+  // isRefining - Used for recursive types
+  char isRefining;
 
   // AbstractTypeUsers - Implement a list of the users that need to be notified
   // if I am a type, and I get resolved into a more concrete type.
@@ -29,8 +36,7 @@ class DerivedType : public Type, public AbstractTypeUser {
   mutable std::vector<AbstractTypeUser *> AbstractTypeUsers;
 
 protected:
-  inline DerivedType(PrimitiveID id) : Type("", id) {
-    isRefining = 0;
+  DerivedType(PrimitiveID id) : Type("", id), RefCount(0), isRefining(0) {
   }
   ~DerivedType() {
     assert(AbstractTypeUsers.empty());
@@ -61,7 +67,10 @@ public:
   // addAbstractTypeUser - Notify an abstract type that there is a new user of
   // it.  This function is called primarily by the PATypeHandle class.
   //
-  void addAbstractTypeUser(AbstractTypeUser *U) const;
+  void addAbstractTypeUser(AbstractTypeUser *U) const {
+    assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!");
+    AbstractTypeUsers.push_back(U);
+  }
 
   // removeAbstractTypeUser - Notify an abstract type that a user of the class
   // no longer has a handle to the type.  This function is called primarily by
@@ -80,6 +89,22 @@ public:
     refineAbstractTypeToInternal(NewType, true);
   }
 
+  void addRef() const {
+    assert(isAbstract() && "Cannot add a reference to a non-abstract type!");
+    ++RefCount;
+  }
+
+  void dropRef() const {
+    assert(isAbstract() && "Cannot drop a refernce to a non-abstract type!");
+    assert(RefCount && "No objects are currently referencing this object!");
+
+    // If this is the last PATypeHolder using this object, and there are no
+    // PATypeHandles using it, the type is dead, delete it now.
+    if (--RefCount == 0 && AbstractTypeUsers.empty())
+      delete this;
+  }
+
+
   void dump() const { Value::dump(); }
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
@@ -453,4 +478,26 @@ inline void PATypeHandle::removeUserFromConcrete() {
     cast<DerivedType>(Ty)->removeAbstractTypeUser(User);
 }
 
+// Define inline methods for PATypeHolder...
+
+inline void PATypeHolder::addRef() {
+  if (Ty->isAbstract())
+    cast<DerivedType>(Ty)->addRef();
+}
+
+inline void PATypeHolder::dropRef() {
+  if (Ty->isAbstract())
+    cast<DerivedType>(Ty)->dropRef();
+}
+
+/// get - This implements the forwarding part of the union-find algorithm for
+/// abstract types.  Before every access to the Type*, we check to see if the
+/// type we are pointing to is forwarding to a new type.  If so, we drop our
+/// reference to the type.
+inline const Type* PATypeHolder::get() const {
+  const Type *NewTy = Ty->getForwardedType();
+  if (!NewTy) return Ty;
+  return *const_cast<PATypeHolder*>(this) = NewTy;
+}
+
 #endif
index 30949a6457776282acbde1070d50a906f560895a..5900b402dcc4931e278388d21bfd679a4fb4badf 100644 (file)
@@ -73,6 +73,7 @@ private:
   unsigned    UID;       // The unique ID number for this class
   bool        Abstract;  // True if type contains an OpaqueType
 
+  const Type *getForwardedTypeInternal() const;
 protected:
   /// ctor is protected, so only subclasses can create Type objects...
   Type(const std::string &Name, PrimitiveID id);
@@ -90,6 +91,12 @@ protected:
   /// isTypeAbstract - This method is used to calculate the Abstract bit.
   ///
   bool isTypeAbstract();
+
+  /// ForwardType - This field is used to implement the union find scheme for
+  /// abstract types.  When types are refined to other types, this field is set
+  /// to the more refined type.  Only abstract types can be forwarded.
+  mutable const Type *ForwardType;
+
 public:
   virtual void print(std::ostream &O) const;
 
@@ -177,6 +184,13 @@ public:
   ///
   unsigned getPrimitiveSize() const;
 
+  /// getForwaredType - Return the type that this type has been resolved to if
+  /// it has been resolved to anything.  This is used to implement the
+  /// union-find algorithm for type resolution.
+  const Type *getForwardedType() const {
+    if (!ForwardType) return 0;
+    return getForwardedTypeInternal();
+  }
 
   //===--------------------------------------------------------------------===//
   // Type Iteration support
index eb1c99e9f4146068874c4efc27a076977ef768e4..f5c91b13755bba003b4cac7b78cb771beda82da2 100644 (file)
@@ -32,13 +32,8 @@ static std::vector<const Type *> UIDMappings;
 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";
-}
-
-
 Type::Type(const std::string &name, PrimitiveID id)
-  : Value(Type::TypeTy, Value::TypeVal) {
+  : Value(Type::TypeTy, Value::TypeVal), ForwardType(0) {
   if (!name.empty())
     ConcreteTypeDescriptions[this] = name;
   ID = id;
@@ -122,6 +117,30 @@ unsigned Type::getPrimitiveSize() const {
 }
 
 
+/// getForwardedTypeInternal - This method is used to implement the union-find
+/// algorithm for when a type is being forwarded to another type.
+const Type *Type::getForwardedTypeInternal() const {
+  assert(ForwardType && "This type is not being forwarded to another type!");
+  
+  // Check to see if the forwarded type has been forwarded on.  If so, collapse
+  // the forwarding links.
+  const Type *RealForwardedType = ForwardType->getForwardedType();
+  if (!RealForwardedType)
+    return ForwardType;  // No it's not forwarded again
+
+  // Yes, it is forwarded again.  First thing, add the reference to the new
+  // forward type.
+  if (RealForwardedType->isAbstract())
+    cast<DerivedType>(RealForwardedType)->addRef();
+
+  // Now drop the old reference.  This could cause ForwardType to get deleted.
+  cast<DerivedType>(ForwardType)->dropRef();
+  
+  // Return the updated type.
+  ForwardType = RealForwardedType;
+  return ForwardType;
+}
+
 // getTypeDescription - This is a recursive function that walks a type hierarchy
 // calculating the description for a type.
 //
@@ -950,21 +969,6 @@ void debug_type_tables() {
 //                     Derived Type Refinement Functions
 //===----------------------------------------------------------------------===//
 
-// addAbstractTypeUser - Notify an abstract type that there is a new user of
-// it.  This function is called primarily by the PATypeHandle class.
-//
-void DerivedType::addAbstractTypeUser(AbstractTypeUser *U) const {
-  assert(isAbstract() && "addAbstractTypeUser: Current type not abstract!");
-
-#if DEBUG_MERGE_TYPES
-  std::cerr << "  addAbstractTypeUser[" << (void*)this << ", "
-            << *this << "][" << AbstractTypeUsers.size()
-            << "] User = " << U << "\n";
-#endif
-  AbstractTypeUsers.push_back(U);
-}
-
-
 // removeAbstractTypeUser - Notify an abstract type that a user of the class
 // no longer has a handle to the type.  This function is called primarily by
 // the PATypeHandle class.  When there are no users of the abstract type, it
@@ -989,7 +993,7 @@ void DerivedType::removeAbstractTypeUser(AbstractTypeUser *U) const {
             << *this << "][" << i << "] User = " << U << "\n";
 #endif
     
-  if (AbstractTypeUsers.empty() && isAbstract()) {
+  if (AbstractTypeUsers.empty() && RefCount == 0 && isAbstract()) {
 #ifdef DEBUG_MERGE_TYPES
     std::cerr << "DELETEing unused abstract type: <" << *this
               << ">[" << (void*)this << "]" << "\n";
@@ -1023,6 +1027,10 @@ void DerivedType::refineAbstractTypeToInternal(const Type *NewType, bool inMap){
   //
   PATypeHolder NewTy(NewType);
 
+  ForwardType = NewType;
+  if (NewType->isAbstract())
+    cast<DerivedType>(NewType)->addRef();
+
   // Add a self use of the current type so that we don't delete ourself until
   // after this while loop.  We are careful to never invoke refine on ourself,
   // so this extra reference shouldn't be a problem.  Note that we must only