[llvm-commits] CVS: llvm/lib/VMCore/Type.cpp

Chris Lattner lattner at cs.uiuc.edu
Tue Sep 2 11:36:02 PDT 2003


Changes in directory llvm/lib/VMCore:

Type.cpp updated: 1.50 -> 1.51

---
Log message:

Change the code to no longer compute the "type description" immediately when 
the type is analyzed.  Instead, only compute it when requested (with 
getDescription), and cached for reuse later.

This dramatically speeds up LLVM in general because these descriptions almost 
_never_ need to be constructed.  The only time they are used is when a type is
<<'d.  Printing of modules by themselves uses other code to print symbolic 
types when possible, so these descriptions are really only used for debugging.

Also, this fixes the particularly bad case when lots of types get resolved to 
each other, such as during linking of large programs.  In these cases, the type
descriptions would be repeatedly recomputed and discarded even though: A. noone
reads the description before it gets resolved, and B. many many resolutions 
happen at intermediate steps, causing a HUGE waste of time.

Overall, this makes the getTypeDesc function much more light-weight, and fixes
bug: Assembler/2002-07-08-HugePerformanceProblem.llx, which went from taking
1048.770u/19.150s (which is 17.5 MINUTES, on apoc), to taking 0.020u/0.000s,
which is a nice little speedup.  :)



---
Diffs of the changes:

Index: llvm/lib/VMCore/Type.cpp
diff -u llvm/lib/VMCore/Type.cpp:1.50 llvm/lib/VMCore/Type.cpp:1.51
--- llvm/lib/VMCore/Type.cpp:1.50	Thu Aug 21 17:12:47 2003
+++ llvm/lib/VMCore/Type.cpp	Tue Sep  2 11:35:17 2003
@@ -25,6 +25,13 @@
 static unsigned CurUID = 0;
 static std::vector<const Type *> UIDMappings;
 
+// Concrete/Abstract TypeDescriptions - We lazily calculate type descriptions
+// for types as they are needed.  Because resolution of types must invalidate
+// all of the abstract type descriptions, we keep them in a seperate map to make
+// this easy.
+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";
 }
@@ -32,7 +39,7 @@
 
 Type::Type(const std::string &name, PrimitiveID id)
   : Value(Type::TypeTy, Value::TypeVal) {
-  setDescription(name);
+  ConcreteTypeDescriptions[this] = name;
   ID = id;
   Abstract = Recursive = false;
   UID = CurUID++;       // Assign types UID's as they are created
@@ -114,6 +121,125 @@
 }
 
 
+// getTypeDescription - This is a recursive function that walks a type hierarchy
+// calculating the description for a type.
+//
+static std::string getTypeDescription(const Type *Ty,
+                                      std::vector<const Type *> &TypeStack) {
+  if (isa<OpaqueType>(Ty)) {                     // Base case for the recursion
+    std::map<const Type*, std::string>::iterator I =
+      AbstractTypeDescriptions.lower_bound(Ty);
+    if (I != AbstractTypeDescriptions.end() && I->first == Ty)
+      return I->second;
+    std::string Desc = "opaque"+utostr(Ty->getUniqueID());
+    AbstractTypeDescriptions.insert(std::make_pair(Ty, Desc));
+    return Desc;
+  }
+  
+  if (!Ty->isAbstract() && !Ty->isRecursive()) {  // Base case for the recursion
+    std::map<const Type*, std::string>::iterator I =
+      ConcreteTypeDescriptions.find(Ty);
+    if (I != ConcreteTypeDescriptions.end()) return I->second;
+  }
+      
+  // Check to see if the Type is already on the stack...
+  unsigned Slot = 0, CurSize = TypeStack.size();
+  while (Slot < CurSize && TypeStack[Slot] != Ty) ++Slot; // Scan for type
+  
+  // This is another base case for the recursion.  In this case, we know 
+  // that we have looped back to a type that we have previously visited.
+  // Generate the appropriate upreference to handle this.
+  // 
+  if (Slot < CurSize)
+    return "\\" + utostr(CurSize-Slot);         // Here's the upreference
+
+  // Recursive case: derived types...
+  std::string Result;
+  TypeStack.push_back(Ty);    // Add us to the stack..
+      
+  switch (Ty->getPrimitiveID()) {
+  case Type::FunctionTyID: {
+    const FunctionType *FTy = cast<FunctionType>(Ty);
+    Result = getTypeDescription(FTy->getReturnType(), TypeStack) + " (";
+    for (FunctionType::ParamTypes::const_iterator
+           I = FTy->getParamTypes().begin(),
+           E = FTy->getParamTypes().end(); I != E; ++I) {
+      if (I != FTy->getParamTypes().begin())
+        Result += ", ";
+      Result += getTypeDescription(*I, TypeStack);
+    }
+    if (FTy->isVarArg()) {
+      if (!FTy->getParamTypes().empty()) Result += ", ";
+      Result += "...";
+    }
+    Result += ")";
+    break;
+  }
+  case Type::StructTyID: {
+    const StructType *STy = cast<StructType>(Ty);
+    Result = "{ ";
+    for (StructType::ElementTypes::const_iterator
+           I = STy->getElementTypes().begin(),
+           E = STy->getElementTypes().end(); I != E; ++I) {
+      if (I != STy->getElementTypes().begin())
+        Result += ", ";
+      Result += getTypeDescription(*I, TypeStack);
+    }
+    Result += " }";
+    break;
+  }
+  case Type::PointerTyID: {
+    const PointerType *PTy = cast<PointerType>(Ty);
+    Result = getTypeDescription(PTy->getElementType(), TypeStack) + " *";
+    break;
+  }
+  case Type::ArrayTyID: {
+    const ArrayType *ATy = cast<ArrayType>(Ty);
+    unsigned NumElements = ATy->getNumElements();
+    Result = "[";
+    Result += utostr(NumElements) + " x ";
+    Result += getTypeDescription(ATy->getElementType(), TypeStack) + "]";
+    break;
+  }
+  default:
+    assert(0 && "Unhandled type in getTypeDescription!");
+    Result = "<error>";
+  }
+
+  TypeStack.pop_back();       // Remove self from stack...
+
+  // In order to reduce the amount of repeated computation, we cache the computd
+  // value for later.
+  if (Ty->isAbstract())
+    AbstractTypeDescriptions[Ty] = Result;
+  else
+    ConcreteTypeDescriptions[Ty] = Result;
+
+  return Result;
+}
+
+
+
+static const std::string &getOrCreateDesc(std::map<const Type*,std::string>&Map,
+                                          const Type *Ty) {
+  std::map<const Type*, std::string>::iterator I = Map.find(Ty);
+  if (I != Map.end()) return I->second;
+    
+  std::vector<const Type *> TypeStack;
+  getTypeDescription(Ty, TypeStack);
+  assert(Map.count(Ty) && "Type didn't get inserted!!");
+  return Map[Ty];
+}
+
+
+const std::string &Type::getDescription() const {
+  if (isAbstract())
+    return getOrCreateDesc(AbstractTypeDescriptions, this);
+  else
+    return getOrCreateDesc(ConcreteTypeDescriptions, this);
+}
+
+
 bool StructType::indexValid(const Value *V) const {
   if (!isa<Constant>(V)) return false;
   if (V->getType() != Type::UByteTy) return false;
@@ -247,7 +373,6 @@
 
 OpaqueType::OpaqueType() : DerivedType(OpaqueTyID) {
   setAbstract(true);
-  setDescription("opaque"+utostr(getUniqueID()));
 #ifdef DEBUG_MERGE_TYPES
   std::cerr << "Derived new type: " << getDescription() << "\n";
 #endif
@@ -266,87 +391,64 @@
 // some whacko opaque types, but in most cases, it will do some simple stuff
 // when it hits non-abstract types that aren't recursive.
 //
-static std::string getTypeProps(const Type *Ty,
-                                std::vector<const Type *> &TypeStack,
-                                bool &isAbstract, bool &isRecursive) {
-  if (!Ty->isAbstract() && !Ty->isRecursive() && // Base case for the recursion
-      Ty->getDescription().size()) {
-    return Ty->getDescription();                 // Primitive = leaf type
-  } else if (isa<OpaqueType>(Ty)) {              // Base case for the recursion
-    isAbstract = true;                           // This whole type is abstract!
-    return Ty->getDescription();                 // Opaque = leaf type
-  } else {
-    // Check to see if the Type is already on the stack...
-    unsigned Slot = 0, CurSize = TypeStack.size();
-    while (Slot < CurSize && TypeStack[Slot] != Ty) ++Slot; // Scan for type
+static void getTypeProps(const Type *Ty, std::vector<const Type *> &TypeStack,
+                         bool &isAbstract, bool &isRecursive) {
+  if (!Ty->isAbstract() && !Ty->isRecursive()) // Base case for the recursion
+    return;                                    // Primitive = leaf type
+  
+  if (isa<OpaqueType>(Ty)) {                   // Base case for the recursion
+    isAbstract = true;                         // This whole type is abstract!
+    return;                                    // Opaque = leaf type
+  }
+
+  // Check to see if the Type is already on the stack...
+  unsigned Slot = 0, CurSize = TypeStack.size();
+  while (Slot < CurSize && TypeStack[Slot] != Ty) ++Slot; // Scan for type
     
-    // This is another base case for the recursion.  In this case, we know 
-    // that we have looped back to a type that we have previously visited.
-    // Generate the appropriate upreference to handle this.
-    // 
-    if (Slot < CurSize) {
-      isRecursive = true;                         // We know we are recursive
-      return "\\" + utostr(CurSize-Slot);         // Here's the upreference
-    } else {                      // Recursive case: abstract derived type...
-      std::string Result;
-      TypeStack.push_back(Ty);    // Add us to the stack..
-      
-      switch (Ty->getPrimitiveID()) {
-      case Type::FunctionTyID: {
-	const FunctionType *MTy = cast<FunctionType>(Ty);
-	Result = getTypeProps(MTy->getReturnType(), TypeStack,
-			      isAbstract, isRecursive)+" (";
-	for (FunctionType::ParamTypes::const_iterator
-	       I = MTy->getParamTypes().begin(),
-	       E = MTy->getParamTypes().end(); I != E; ++I) {
-	  if (I != MTy->getParamTypes().begin())
-	    Result += ", ";
-	  Result += getTypeProps(*I, TypeStack, isAbstract, isRecursive);
-	}
-	if (MTy->isVarArg()) {
-	  if (!MTy->getParamTypes().empty()) Result += ", ";
-	  Result += "...";
-	}
-	Result += ")";
-	break;
-      }
-      case Type::StructTyID: {
-	const StructType *STy = cast<StructType>(Ty);
-	Result = "{ ";
-	for (StructType::ElementTypes::const_iterator
-	       I = STy->getElementTypes().begin(),
-	       E = STy->getElementTypes().end(); I != E; ++I) {
-	  if (I != STy->getElementTypes().begin())
-	    Result += ", ";
-	  Result += getTypeProps(*I, TypeStack, isAbstract, isRecursive);
-	}
-	Result += " }";
-	break;
-      }
-      case Type::PointerTyID: {
-	const PointerType *PTy = cast<PointerType>(Ty);
-	Result = getTypeProps(PTy->getElementType(), TypeStack,
-			      isAbstract, isRecursive) + " *";
-	break;
-      }
-      case Type::ArrayTyID: {
-	const ArrayType *ATy = cast<ArrayType>(Ty);
-	unsigned NumElements = ATy->getNumElements();
-	Result = "[";
-	Result += utostr(NumElements) + " x ";
-	Result += getTypeProps(ATy->getElementType(), TypeStack,
-			       isAbstract, isRecursive) + "]";
-	break;
-      }
-      default:
-	assert(0 && "Unhandled case in getTypeProps!");
-	Result = "<error>";
-      }
+  // This is another base case for the recursion.  In this case, we know 
+  // that we have looped back to a type that we have previously visited.
+  // Generate the appropriate upreference to handle this.
+  // 
+  if (Slot < CurSize) {
+    isRecursive = true;                         // We know we are recursive
+    return;
+  }
 
-      TypeStack.pop_back();       // Remove self from stack...
-      return Result;
-    }
+  // Recursive case: derived type...
+  TypeStack.push_back(Ty);    // Add us to the stack..
+      
+  switch (Ty->getPrimitiveID()) {
+  case Type::FunctionTyID: {
+    const FunctionType *FTy = cast<FunctionType>(Ty);
+    getTypeProps(FTy->getReturnType(), TypeStack, isAbstract, isRecursive);
+    for (FunctionType::ParamTypes::const_iterator
+           I = FTy->getParamTypes().begin(),
+           E = FTy->getParamTypes().end(); I != E; ++I)
+      getTypeProps(*I, TypeStack, isAbstract, isRecursive);
+    break;
+  }
+  case Type::StructTyID: {
+    const StructType *STy = cast<StructType>(Ty);
+    for (StructType::ElementTypes::const_iterator
+           I = STy->getElementTypes().begin(),
+           E = STy->getElementTypes().end(); I != E; ++I)
+      getTypeProps(*I, TypeStack, isAbstract, isRecursive);
+    break;
+  }
+  case Type::PointerTyID: {
+    const PointerType *PTy = cast<PointerType>(Ty);
+    getTypeProps(PTy->getElementType(), TypeStack, isAbstract, isRecursive);
+    break;
+  }
+  case Type::ArrayTyID:
+    getTypeProps(cast<ArrayType>(Ty)->getElementType(), TypeStack,
+                 isAbstract, isRecursive);
+    break;
+  default:
+    assert(0 && "Unhandled type in getTypeProps!");
   }
+
+  TypeStack.pop_back();       // Remove self from stack...
 }
 
 
@@ -358,7 +460,7 @@
   std::vector<const Type *> TypeStack;
   bool isAbstract = false, isRecursive = false;
   
-  setDescription(getTypeProps(this, TypeStack, isAbstract, isRecursive));
+  getTypeProps(this, TypeStack, isAbstract, isRecursive);
   setAbstract(isAbstract);
   setRecursive(isRecursive);
 }
@@ -402,8 +504,8 @@
   if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
     if (ATy->getNumElements() != cast<ArrayType>(Ty2)->getNumElements())
       return false;
-  } else if (const FunctionType *MTy = dyn_cast<FunctionType>(Ty)) {
-    if (MTy->isVarArg() != cast<FunctionType>(Ty2)->isVarArg())
+  } else if (const FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
+    if (FTy->isVarArg() != cast<FunctionType>(Ty2)->isVarArg())
       return false;
   }
 
@@ -846,6 +948,9 @@
 void DerivedType::refineAbstractTypeTo(const Type *NewType) {
   assert(isAbstract() && "refineAbstractTypeTo: Current type is not abstract!");
   assert(this != NewType && "Can't refine to myself!");
+  
+  // The descriptions may be out of date.  Conservatively clear them all!
+  AbstractTypeDescriptions.clear();
 
 #ifdef DEBUG_MERGE_TYPES
   std::cerr << "REFINING abstract type [" << (void*)this << " "





More information about the llvm-commits mailing list