OSDN Git Service

Unfortunately the fix for the previous bug introduced the previous
authorChris Lattner <sabre@nondot.org>
Thu, 7 Oct 2004 19:20:48 +0000 (19:20 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 7 Oct 2004 19:20:48 +0000 (19:20 +0000)
exponential behavior (bork!).  This patch processes stuff with an
explicit SCC finder, allowing the algorithm to be more clear,
efficient, and also (as a bonus) correct!  This gets us back to taking
0.6s to disassemble my horrible .bc file that previously took something
> 30 mins.

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

lib/VMCore/Type.cpp

index 6a9da3a..02b723f 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/Constants.h"
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SCCIterator.h"
 #include "llvm/ADT/STLExtras.h"
 #include <algorithm>
 #include <iostream>
@@ -443,44 +444,76 @@ void DerivedType::dropAllTypeUses() {
   }
 }
 
+
+
+/// TypePromotionGraph and graph traits - this is designed to allow us to do
+/// efficient SCC processing of type graphs.  This is the exact same as
+/// GraphTraits<Type*>, except that we pretend that concrete types have no
+/// children to avoid processing them.
+struct TypePromotionGraph {
+  Type *Ty;
+  TypePromotionGraph(Type *T) : Ty(T) {}
+};
+
+namespace llvm {
+  template <> struct GraphTraits<TypePromotionGraph> {
+    typedef Type NodeType;
+    typedef Type::subtype_iterator ChildIteratorType;
+    
+    static inline NodeType *getEntryNode(TypePromotionGraph G) { return G.Ty; }
+    static inline ChildIteratorType child_begin(NodeType *N) { 
+      if (N->isAbstract())
+        return N->subtype_begin(); 
+      else           // No need to process children of concrete types.
+        return N->subtype_end(); 
+    }
+    static inline ChildIteratorType child_end(NodeType *N) { 
+      return N->subtype_end();
+    }
+  };
+}
+
+
 // PromoteAbstractToConcrete - This is a recursive function that walks a type
 // graph calculating whether or not a type is abstract.
 //
 // This method returns true if the type is found to still be abstract.
 //
-bool Type::PromoteAbstractToConcrete(void *Ptr) {
-  if (!isAbstract())                           // Base case for the recursion
-    return false;                              // Primitive = leaf type
-  
-  if (isa<OpaqueType>(this))                   // Base case for the recursion
-    return true;                               // This whole type is abstract!
-
-  /// KnownAbstractTypes - This set contains all of the types that we know for
-  /// sure are abstract.  Once we discover that a type really is abstract, we
-  /// remember this so we don't have to do potentially exponential amounts of
-  /// checking in some cases.
-  std::set<Type*> &KnownAbstractTypes = *(std::set<Type*>*)Ptr;
-  if (KnownAbstractTypes.count(this))
-    return true;    // We already know this type is abstract!
-
-  // We have to guard against recursion.  To do this, we temporarily mark this
-  // type as concrete, so that if we get back to here recursively we will think
-  // it's not abstract, and thus not scan it again.
-  setAbstract(false);
-
-  // Scan all of the sub-types.  If any of them are abstract, than so is this
-  // one!
-  for (Type::subtype_iterator I = subtype_begin(), E = subtype_end(); 
-       I != E; ++I)
-    if (const_cast<Type*>(I->get())->PromoteAbstractToConcrete(Ptr)) {
-      KnownAbstractTypes.insert(this);
-      setAbstract(true);        // Restore the abstract bit.
-      return true;              // This type is abstract if subtype is abstract!
+void Type::PromoteAbstractToConcrete() {
+  if (!isAbstract()) return;
+
+  scc_iterator<TypePromotionGraph> SI = scc_begin(TypePromotionGraph(this));
+  scc_iterator<TypePromotionGraph> SE = scc_end  (TypePromotionGraph(this));
+
+  for (; SI != SE; ++SI) {
+    std::vector<Type*> &SCC = *SI;
+
+    // Concrete types are leaves in the tree.  Since an SCC will either be all
+    // abstract or all concrete, we only need to check one type.
+    if (SCC[0]->isAbstract()) {
+      if (isa<OpaqueType>(SCC[0]))
+        return;     // Not going to be concrete, sorry.
+
+      // If all of the children of all of the types in this SCC are concrete,
+      // then this SCC is now concrete as well.  If not, neither this SCC, nor
+      // any parent SCCs will be concrete, so we might as well just exit.
+      for (unsigned i = 0, e = SCC.size(); i != e; ++i)
+        for (Type::subtype_iterator CI = SCC[i]->subtype_begin(),
+               E = SCC[i]->subtype_end(); CI != E; ++CI)
+          if ((*CI)->isAbstract())
+            return;               // Not going to be concrete, sorry.
+      
+      // Okay, we just discovered this whole SCC is now concrete, mark it as
+      // such!
+      for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
+        assert(SCC[i]->isAbstract() && "Why are we processing concrete types?");
+        
+        SCC[i]->setAbstract(false);
+        // The type just became concrete, notify all users!
+        cast<DerivedType>(SCC[i])->notifyUsesThatTypeBecameConcrete();
+      }
     }
-  
-  // Nothing looks abstract here.  Restore the abstract flag.
-  setAbstract(true);
-  return false;
+  }
 }
 
 
@@ -730,15 +763,8 @@ public:
 
     // If the type is currently thought to be abstract, rescan all of our
     // subtypes to see if the type has just become concrete!
-    if (Ty->isAbstract()) {
-      std::set<Type*> KnownAbstractTypes;
-      if (!Ty->PromoteAbstractToConcrete(&KnownAbstractTypes))
-        Ty->setAbstract(false);
-
-      // If the type just became concrete, notify all users!
-      if (!Ty->isAbstract())
-        Ty->notifyUsesThatTypeBecameConcrete();
-    }
+    if (Ty->isAbstract())
+      Ty->PromoteAbstractToConcrete();
   }
   
   void print(const char *Arg) const {