Make getContainedType more efficient by not returning null if out of range!
[oota-llvm.git] / include / llvm / DerivedTypes.h
index f827753a6c9af096caa7f190aa8f283cbbee9e32..e0ccffd5fb7e9371e01d48b437a86e5a0b3bab8b 100644 (file)
@@ -1,4 +1,4 @@
-//===-- llvm/DerivedTypes.h - Classes for handling data types ----*- C++ -*--=//
+//===-- llvm/DerivedTypes.h - Classes for handling data types ---*- C++ -*-===//
 //
 // This file contains the declarations of classes that represent "derived 
 // types".  These are things like "arrays of x" or "structure of x, y, z" or
 
 #include "llvm/Type.h"
 
-class DerivedType : public Type {
-  char isRefining;                                   // Used for recursive types
-
+template<class ValType, class TypeClass> class TypeMap;
+class FunctionValType;
+class ArrayValType;
+class StructValType;
+class PointerValType;
+
+class DerivedType : public Type, public AbstractTypeUser {
+  /// 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;
+  
   // 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.
   //
@@ -23,28 +33,23 @@ class DerivedType : public Type {
   mutable std::vector<AbstractTypeUser *> AbstractTypeUsers;
 
 protected:
-  inline DerivedType(PrimitiveID id) : Type("", id) {
-    isRefining = 0;
+  DerivedType(PrimitiveID id) : Type("", id), RefCount(0) {
   }
   ~DerivedType() {
     assert(AbstractTypeUsers.empty());
   }
 
-  // typeIsRefined - Notify AbstractTypeUsers of this type that the current type
-  // has been refined a bit.  The pointer is still valid and still should be
-  // used, but the subtypes have changed.
-  //
-  void typeIsRefined();
+  /// notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type
+  /// that the current type has transitioned from being abstract to being
+  /// concrete.
+  ///
+  void notifyUsesThatTypeBecameConcrete();
 
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
-  // types, to avoid some circular reference problems.  This also removes the
-  // type from the internal tables of available types.
-  virtual void dropAllTypeUses(bool inMap) = 0;
+  // types, to avoid some circular reference problems.
+  virtual void dropAllTypeUses() = 0;
   
-
-  void refineAbstractTypeToInternal(const Type *NewType, bool inMap);
-
 public:
 
   //===--------------------------------------------------------------------===//
@@ -55,7 +60,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
@@ -70,10 +78,26 @@ public:
   // This causes all users of 'this' to switch to reference the more concrete
   // type NewType and for 'this' to be deleted.
   //
-  void refineAbstractTypeTo(const Type *NewType) {
-    refineAbstractTypeToInternal(NewType, true);
+  void refineAbstractTypeTo(const Type *NewType);
+
+  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:
   static inline bool classof(const DerivedType *T) { return true; }
   static inline bool classof(const Type *T) {
@@ -89,6 +113,7 @@ public:
 
 struct FunctionType : public DerivedType {
   typedef std::vector<PATypeHandle> ParamTypes;
+  friend class TypeMap<FunctionValType, FunctionType>;
 private:
   PATypeHandle ResultType;
   ParamTypes ParamTys;
@@ -107,11 +132,15 @@ protected:
 
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
-  // types, to avoid some circular reference problems.  This also removes the
-  // type from the internal tables of available types.
-  virtual void dropAllTypeUses(bool inMap);
+  // types, to avoid some circular reference problems.
+  virtual void dropAllTypeUses();
 
 public:
+  /// FunctionType::get - This static method is the primary way of constructing
+  /// a FunctionType
+  static FunctionType *get(const Type *Result,
+                           const std::vector<const Type*> &Params,
+                           bool isVarArg);
 
   inline bool isVarArg() const { return isVarArgs; }
   inline const Type *getReturnType() const { return ResultType; }
@@ -127,22 +156,14 @@ public:
 
 
   virtual const Type *getContainedType(unsigned i) const {
-    return i == 0 ? ResultType : 
-                    (i <= ParamTys.size() ? ParamTys[i-1].get() : 0);
+    return i == 0 ? ResultType.get() : ParamTys[i-1].get();
   }
   virtual unsigned getNumContainedTypes() const { return ParamTys.size()+1; }
 
-  // refineAbstractType - Called when a contained type is found to be more
-  // concrete - this could potentially change us from an abstract type to a
-  // concrete type.
-  //
+  // Implement the AbstractTypeUser interface.
   virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
-
-  static FunctionType *get(const Type *Result,
-                           const std::vector<const Type*> &Params,
-                           bool isVarArg);
-
-
+  virtual void typeBecameConcrete(const DerivedType *AbsTy);
+  
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const FunctionType *T) { return true; }
   static inline bool classof(const Type *T) {
@@ -186,8 +207,8 @@ public:
 };
 
 
-class StructType : public CompositeType {
-public:
+struct StructType : public CompositeType {
+  friend class TypeMap<StructValType, StructType>;
   typedef std::vector<PATypeHandle> ElementTypes;
 
 private:
@@ -206,15 +227,18 @@ protected:
 
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
-  // types, to avoid some circular reference problems.  This also removes the
-  // type from the internal tables of available types.
-  virtual void dropAllTypeUses(bool inMap);
+  // types, to avoid some circular reference problems.
+  virtual void dropAllTypeUses();
   
 public:
+  /// StructType::get - This static method is the primary way to create a
+  /// StructType.
+  static StructType *get(const std::vector<const Type*> &Params);
+
   inline const ElementTypes &getElementTypes() const { return ETypes; }
 
   virtual const Type *getContainedType(unsigned i) const { 
-    return i < ETypes.size() ? ETypes[i].get() : 0;
+    return ETypes[i].get();
   }
   virtual unsigned getNumContainedTypes() const { return ETypes.size(); }
 
@@ -229,13 +253,9 @@ public:
   //
   virtual const Type *getIndexType() const { return Type::UByteTy; }
 
-  // refineAbstractType - Called when a contained type is found to be more
-  // concrete - this could potentially change us from an abstract type to a
-  // concrete type.
-  //
+  // Implement the AbstractTypeUser interface.
   virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
-
-  static StructType *get(const std::vector<const Type*> &Params);
+  virtual void typeBecameConcrete(const DerivedType *AbsTy);
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const StructType *T) { return true; }
@@ -268,7 +288,7 @@ public:
   inline const Type *getElementType() const { return ElementType; }
 
   virtual const Type *getContainedType(unsigned i) const { 
-    return i == 0 ? ElementType.get() : 0;
+    return ElementType.get();
   }
   virtual unsigned getNumContainedTypes() const { return 1; }
 
@@ -300,6 +320,7 @@ public:
 
 
 class ArrayType : public SequentialType {
+  friend class TypeMap<ArrayValType, ArrayType>;
   unsigned NumElements;
 
   ArrayType(const ArrayType &);                   // Do not implement
@@ -314,20 +335,19 @@ protected:
 
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
-  // types, to avoid some circular reference problems.  This also removes the
-  // type from the internal tables of available types.
-  virtual void dropAllTypeUses(bool inMap);
+  // types, to avoid some circular reference problems.
+  virtual void dropAllTypeUses();
 
 public:
+  /// ArrayType::get - This static method is the primary way to construct an
+  /// ArrayType
+  static ArrayType *get(const Type *ElementType, unsigned NumElements);
+
   inline unsigned    getNumElements() const { return NumElements; }
 
-  // refineAbstractType - Called when a contained type is found to be more
-  // concrete - this could potentially change us from an abstract type to a
-  // concrete type.
-  //
+  // Implement the AbstractTypeUser interface.
   virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
-
-  static ArrayType *get(const Type *ElementType, unsigned NumElements);
+  virtual void typeBecameConcrete(const DerivedType *AbsTy);
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const ArrayType *T) { return true; }
@@ -342,6 +362,7 @@ public:
 
 
 class PointerType : public SequentialType {
+  friend class TypeMap<PointerValType, PointerType>;
   PointerType(const PointerType &);                   // Do not implement
   const PointerType &operator=(const PointerType &);  // Do not implement
 protected:
@@ -354,20 +375,17 @@ protected:
 
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
-  // types, to avoid some circular reference problems.  This also removes the
-  // type from the internal tables of available types.
-  virtual void dropAllTypeUses(bool inMap);
+  // types, to avoid some circular reference problems.
+  virtual void dropAllTypeUses();
 public:
-  // PointerType::get - Named constructor for pointer types...
+  /// PointerType::get - This is the only way to construct a new pointer type.
   static PointerType *get(const Type *ElementType);
 
-  // refineAbstractType - Called when a contained type is found to be more
-  // concrete - this could potentially change us from an abstract type to a
-  // concrete type.
-  //
+  // Implement the AbstractTypeUser interface.
   virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
+  virtual void typeBecameConcrete(const DerivedType *AbsTy);
 
-  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  // Implement support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const PointerType *T) { return true; }
   static inline bool classof(const Type *T) {
     return T->getPrimitiveID() == PointerTyID;
@@ -392,16 +410,25 @@ protected:
   // dropAllTypeUses - When this (abstract) type is resolved to be equal to
   // another (more concrete) type, we must eliminate all references to other
   // types, to avoid some circular reference problems.
-  virtual void dropAllTypeUses(bool inMap) {}  // No type uses
+  virtual void dropAllTypeUses() {
+    // FIXME: THIS IS NOT AN ABSTRACT TYPE USER!
+  }  // No type uses
 
 public:
-
-  // get - Static factory method for the OpaqueType class...
+  // OpaqueType::get - Static factory method for the OpaqueType class...
   static OpaqueType *get() {
     return new OpaqueType();           // All opaque types are distinct
   }
 
-  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  // Implement the AbstractTypeUser interface.
+  virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy) {
+    abort();   // FIXME: this is not really an AbstractTypeUser!
+  }
+  virtual void typeBecameConcrete(const DerivedType *AbsTy) {
+    abort();   // FIXME: this is not really an AbstractTypeUser!
+  }
+
+  // Implement support for type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const OpaqueType *T) { return true; }
   static inline bool classof(const Type *T) {
     return T->getPrimitiveID() == OpaqueTyID;
@@ -433,4 +460,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