Add peak memory usage measurement stuff
[oota-llvm.git] / lib / Analysis / DataStructure / DataStructure.cpp
index 8d798e3dc2844c26257413619e8159a1e7c12902..94c1f8537e4d3d01f36bbe347bdcd3c682a461bf 100644 (file)
@@ -11,6 +11,7 @@
 #include "llvm/Target/TargetData.h"
 #include "Support/STLExtras.h"
 #include "Support/Statistic.h"
+#include "Support/Timer.h"
 #include <algorithm>
 #include <set>
 
@@ -77,7 +78,8 @@ void DSNode::foldNodeCompletely() {
   ++NumFolds;
 
   // We are no longer typed at all...
-  Ty = DSTypeRec(Type::VoidTy, true);
+  Ty = Type::VoidTy;
+  NodeType |= Array;
   Size = 1;
 
   // Loop over all of our referrers, making them point to our zero bytes of
@@ -97,7 +99,7 @@ void DSNode::foldNodeCompletely() {
 /// all of the field sensitivity that may be present in the node.
 ///
 bool DSNode::isNodeCompletelyFolded() const {
-  return getSize() == 1 && Ty.Ty == Type::VoidTy && Ty.isArray;
+  return getSize() == 1 && Ty == Type::VoidTy && isArray();
 }
 
 
@@ -117,20 +119,32 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
   //  Size = 1, Ty = Void, Array = 1: The node is collapsed
   //  Otherwise, sizeof(Ty) = Size
   //
-  assert(((Size == 0 && Ty.Ty == Type::VoidTy && !Ty.isArray) ||
-          (Size == 0 && !Ty.Ty->isSized() && !Ty.isArray) ||
-          (Size == 1 && Ty.Ty == Type::VoidTy && Ty.isArray) ||
-          (Size == 0 && !Ty.Ty->isSized() && !Ty.isArray) ||
-          (TD.getTypeSize(Ty.Ty) == Size)) &&
+  assert(((Size == 0 && Ty == Type::VoidTy && !isArray()) ||
+          (Size == 0 && !Ty->isSized() && !isArray()) ||
+          (Size == 1 && Ty == Type::VoidTy && isArray()) ||
+          (Size == 0 && !Ty->isSized() && !isArray()) ||
+          (TD.getTypeSize(Ty) == Size)) &&
          "Size member of DSNode doesn't match the type structure!");
   assert(NewTy != Type::VoidTy && "Cannot merge void type into DSNode!");
 
-  if (Offset == 0 && NewTy == Ty.Ty)
+  if (Offset == 0 && NewTy == Ty)
     return false;  // This should be a common case, handle it efficiently
 
   // Return true immediately if the node is completely folded.
   if (isNodeCompletelyFolded()) return true;
 
+  // If this is an array type, eliminate the outside arrays because they won't
+  // be used anyway.  This greatly reduces the size of large static arrays used
+  // as global variables, for example.
+  //
+  bool WillBeArray = false;
+  while (const ArrayType *AT = dyn_cast<ArrayType>(NewTy)) {
+    // FIXME: we might want to keep small arrays, but must be careful about
+    // things like: [2 x [10000 x int*]]
+    NewTy = AT->getElementType();
+    WillBeArray = true;
+  }
+
   // Figure out how big the new type we're merging in is...
   unsigned NewTySize = NewTy->isSized() ? TD.getTypeSize(NewTy) : 0;
 
@@ -138,12 +152,14 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
   // we can't, we fold the node completely, if we can, we potentially update our
   // internal state.
   //
-  if (Ty.Ty == Type::VoidTy) {
+  if (Ty == Type::VoidTy) {
     // If this is the first type that this node has seen, just accept it without
     // question....
     assert(Offset == 0 && "Cannot have an offset into a void node!");
-    assert(Ty.isArray == false && "This shouldn't happen!");
-    Ty.Ty = NewTy;
+    assert(!isArray() && "This shouldn't happen!");
+    Ty = NewTy;
+    NodeType &= ~Array;
+    if (WillBeArray) NodeType |= Array;
     Size = NewTySize;
 
     // Calculate the number of outgoing links from this node.
@@ -155,7 +171,7 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
   if (Offset+NewTySize > Size) {
     // It is illegal to grow this node if we have treated it as an array of
     // objects...
-    if (Ty.isArray) {
+    if (isArray()) {
       foldNodeCompletely();
       return true;
     }
@@ -173,8 +189,10 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
     // hit the other code path here.  If the other code path decides it's not
     // ok, it will collapse the node as appropriate.
     //
-    const Type *OldTy = Ty.Ty;
-    Ty.Ty = NewTy;
+    const Type *OldTy = Ty;
+    Ty = NewTy;
+    NodeType &= ~Array;
+    if (WillBeArray) NodeType |= Array;
     Size = NewTySize;
 
     // Must grow links to be the appropriate size...
@@ -188,11 +206,11 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
   assert(Offset <= Size &&
          "Cannot merge something into a part of our type that doesn't exist!");
 
-  // Find the section of Ty.Ty that NewTy overlaps with... first we find the
+  // Find the section of Ty that NewTy overlaps with... first we find the
   // type that starts at offset Offset.
   //
   unsigned O = 0;
-  const Type *SubType = Ty.Ty;
+  const Type *SubType = Ty;
   while (O < Offset) {
     assert(Offset-O < TD.getTypeSize(SubType) && "Offset out of range!");
 
@@ -233,17 +251,27 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
   // composite type...
   //
   unsigned SubTypeSize = SubType->isSized() ? TD.getTypeSize(SubType) : 0;
+  unsigned PadSize = SubTypeSize; // Size, including pad memory which is ignored
   while (SubType != NewTy) {
     const Type *NextSubType = 0;
-    unsigned NextSubTypeSize;
+    unsigned NextSubTypeSize = 0;
+    unsigned NextPadSize = 0;
     switch (SubType->getPrimitiveID()) {
-    case Type::StructTyID:
-      NextSubType = cast<StructType>(SubType)->getElementTypes()[0];
-      NextSubTypeSize = TD.getTypeSize(SubType);
+    case Type::StructTyID: {
+      const StructType *STy = cast<StructType>(SubType);
+      const StructLayout &SL = *TD.getStructLayout(STy);
+      if (SL.MemberOffsets.size() > 1)
+        NextPadSize = SL.MemberOffsets[1];
+      else
+        NextPadSize = SubTypeSize;
+      NextSubType = STy->getElementTypes()[0];
+      NextSubTypeSize = TD.getTypeSize(NextSubType);
       break;
+    }
     case Type::ArrayTyID:
       NextSubType = cast<ArrayType>(SubType)->getElementType();
-      NextSubTypeSize = TD.getTypeSize(SubType);
+      NextSubTypeSize = TD.getTypeSize(NextSubType);
+      NextPadSize = NextSubTypeSize;
       break;
     default: ;
       // fall out 
@@ -252,10 +280,11 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
     if (NextSubType == 0)
       break;   // In the default case, break out of the loop
 
-    if (NextSubTypeSize < NewTySize)
+    if (NextPadSize < NewTySize)
       break;   // Don't allow shrinking to a smaller type than NewTySize
     SubType = NextSubType;
     SubTypeSize = NextSubTypeSize;
+    PadSize = NextPadSize;
   }
 
   // If we found the type exactly, return it...
@@ -274,11 +303,14 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset) {
     if (SubType->isInteger() && isa<PointerType>(NewTy) ||
         NewTy->isInteger() && isa<PointerType>(SubType))
       return false;
-
+  } else if (NewTySize > SubTypeSize && NewTySize <= PadSize) {
+    // We are accessing the field, plus some structure padding.  Ignore the
+    // structure padding.
+    return false;
   }
 
 
-  DEBUG(std::cerr << "MergeTypeInfo Folding OrigTy: " << Ty.Ty
+  DEBUG(std::cerr << "MergeTypeInfo Folding OrigTy: " << Ty
                   << "\n due to:" << NewTy << " @ " << Offset << "!\n"
                   << "SubType: " << SubType << "\n\n");
 
@@ -308,8 +340,8 @@ void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) {
 // duplicates are not allowed and both are sorted.  This assumes that 'T's are
 // efficiently copyable and have sane comparison semantics.
 //
-template<typename T>
-void MergeSortedVectors(vector<T> &Dest, const vector<T> &Src) {
+static void MergeSortedVectors(vector<GlobalValue*> &Dest,
+                               const vector<GlobalValue*> &Src) {
   // By far, the most common cases will be the simple ones.  In these cases,
   // avoid having to allocate a temporary vector...
   //
@@ -318,22 +350,22 @@ void MergeSortedVectors(vector<T> &Dest, const vector<T> &Src) {
   } else if (Dest.empty()) {     // Just copy the result in...
     Dest = Src;
   } else if (Src.size() == 1) {  // Insert a single element...
-    const T &V = Src[0];
-    typename vector<T>::iterator I =
+    const GlobalValue *V = Src[0];
+    vector<GlobalValue*>::iterator I =
       std::lower_bound(Dest.begin(), Dest.end(), V);
     if (I == Dest.end() || *I != Src[0])  // If not already contained...
       Dest.insert(I, Src[0]);
   } else if (Dest.size() == 1) {
-    T Tmp = Dest[0];                      // Save value in temporary...
+    GlobalValue *Tmp = Dest[0];           // Save value in temporary...
     Dest = Src;                           // Copy over list...
-    typename vector<T>::iterator I =
-      std::lower_bound(Dest.begin(), Dest.end(),Tmp);
-    if (I == Dest.end() || *I != Src[0])  // If not already contained...
-      Dest.insert(I, Src[0]);
+    vector<GlobalValue*>::iterator I =
+      std::lower_bound(Dest.begin(), Dest.end(), Tmp);
+    if (I == Dest.end() || *I != Tmp)     // If not already contained...
+      Dest.insert(I, Tmp);
 
   } else {
     // Make a copy to the side of Dest...
-    vector<T> Old(Dest);
+    vector<GlobalValue*> Old(Dest);
     
     // Make space for all of the type entries now...
     Dest.resize(Dest.size()+Src.size());
@@ -360,6 +392,10 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
   if (N == 0 || (N == this && NH.getOffset() == Offset))
     return;  // Noop
 
+  assert((N->NodeType & DSNode::DEAD) == 0);
+  assert((NodeType & DSNode::DEAD) == 0);
+  assert(!hasNoReferrers() && "Should not try to fold a useless node!");
+
   if (N == this) {
     // We cannot merge two pieces of the same node together, collapse the node
     // completely.
@@ -369,35 +405,54 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
     return;
   }
 
+  // If both nodes are not at offset 0, make sure that we are merging the node
+  // at an later offset into the node with the zero offset.
+  //
+  if (Offset < NH.getOffset()) {
+    N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
+    return;
+  } else if (Offset == NH.getOffset() && getSize() < N->getSize()) {
+    // If the offsets are the same, merge the smaller node into the bigger node
+    N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
+    return;
+  }
+
+  // Now we know that Offset >= NH.Offset, so convert it so our "Offset" (with
+  // respect to NH.Offset) is now zero.  NOffset is the distance from the base
+  // of our object that N starts from.
+  //
+  unsigned NOffset = Offset-NH.getOffset();
+  unsigned NSize = N->getSize();
+
   // Merge the type entries of the two nodes together...
-  if (N->Ty.Ty != Type::VoidTy)
-    mergeTypeInfo(N->Ty.Ty, Offset);
+  if (N->Ty != Type::VoidTy) {
+    mergeTypeInfo(N->Ty, NOffset);
+
+    // mergeTypeInfo can cause collapsing, which can cause this node to become
+    // dead.
+    if (hasNoReferrers()) return;
+  }
+  assert((NodeType & DSNode::DEAD) == 0);
 
   // If we are merging a node with a completely folded node, then both nodes are
   // now completely folded.
   //
   if (isNodeCompletelyFolded()) {
-    if (!N->isNodeCompletelyFolded())
+    if (!N->isNodeCompletelyFolded()) {
       N->foldNodeCompletely();
+      if (hasNoReferrers()) return;
+      NSize = N->getSize();
+    }
   } else if (N->isNodeCompletelyFolded()) {
     foldNodeCompletely();
+    if (hasNoReferrers()) return;
     Offset = 0;
+    NOffset = NH.getOffset();
+    NSize = N->getSize();
   }
   N = NH.getNode();
-
   if (this == N || N == 0) return;
-
-  // If both nodes are not at offset 0, make sure that we are merging the node
-  // at an later offset into the node with the zero offset.
-  //
-  if (Offset > NH.getOffset()) {
-    N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
-    return;
-  } else if (Offset == NH.getOffset() && getSize() < N->getSize()) {
-    // If the offsets are the same, merge the smaller node into the bigger node
-    N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
-    return;
-  }
+  assert((NodeType & DSNode::DEAD) == 0);
 
 #if 0
   std::cerr << "\n\nMerging:\n";
@@ -406,12 +461,6 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
   print(std::cerr, 0);
 #endif
 
-  // Now we know that Offset <= NH.Offset, so convert it so our "Offset" (with
-  // respect to NH.Offset) is now zero.
-  //
-  unsigned NOffset = NH.getOffset()-Offset;
-  unsigned NSize = N->getSize();
-
   // Remove all edges pointing at N, causing them to point to 'this' instead.
   // Make sure to adjust their offset, not just the node pointer.
   //
@@ -419,6 +468,7 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
     DSNodeHandle &Ref = *N->Referrers.back();
     Ref = DSNodeHandle(this, NOffset+Ref.getOffset());
   }
+  assert((NodeType & DSNode::DEAD) == 0);
 
   // Make all of the outgoing links of N now be outgoing links of this.  This
   // can cause recursive merging!
@@ -432,15 +482,17 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
       // merging just occured, causing THIS node to get merged into oblivion.
       // If that happens, we must not try to merge any more edges into it!
       //
-      if (Size == 0) return;
+      if (Size == 0)
+        return;             // Node is now dead
+      if (Size == 1)
+        break;              // Node got collapsed
     }
   }
 
   // Now that there are no outgoing edges, all of the Links are dead.
   N->Links.clear();
   N->Size = 0;
-  N->Ty.Ty = Type::VoidTy;
-  N->Ty.isArray = false;
+  N->Ty = Type::VoidTy;
 
   // Merge the node types
   NodeType |= N->NodeType;
@@ -469,26 +521,28 @@ Function &DSCallSite::getCaller() const {
 // DSGraph Implementation
 //===----------------------------------------------------------------------===//
 
-DSGraph::DSGraph(const DSGraph &G) : Func(G.Func) {
-  std::map<const DSNode*, DSNode*> NodeMap;
+DSGraph::DSGraph(const DSGraph &G) : Func(G.Func), GlobalsGraph(0) {
+  PrintAuxCalls = false;
+  std::map<const DSNode*, DSNodeHandle> NodeMap;
   RetNode = cloneInto(G, ScalarMap, NodeMap);
 }
 
-DSGraph::DSGraph(const DSGraph &G, std::map<const DSNode*, DSNode*> &NodeMap)
-  : Func(G.Func) {
+DSGraph::DSGraph(const DSGraph &G,
+                 std::map<const DSNode*, DSNodeHandle> &NodeMap)
+  : Func(G.Func), GlobalsGraph(0) {
+  PrintAuxCalls = false;
   RetNode = cloneInto(G, ScalarMap, NodeMap);
 }
 
 DSGraph::~DSGraph() {
   FunctionCalls.clear();
+  AuxFunctionCalls.clear();
   ScalarMap.clear();
   RetNode.setNode(0);
 
-#ifndef NDEBUG
   // Drop all intra-node references, so that assertions don't fail...
   std::for_each(Nodes.begin(), Nodes.end(),
                 std::mem_fun(&DSNode::dropAllReferences));
-#endif
 
   // Delete all of the nodes themselves...
   std::for_each(Nodes.begin(), Nodes.end(), deleter<DSNode>);
@@ -501,9 +555,12 @@ void DSGraph::dump() const { print(std::cerr); }
 /// remapLinks - Change all of the Links in the current node according to the
 /// specified mapping.
 ///
-void DSNode::remapLinks(std::map<const DSNode*, DSNode*> &OldNodeMap) {
-  for (unsigned i = 0, e = Links.size(); i != e; ++i) 
-    Links[i].setNode(OldNodeMap[Links[i].getNode()]);
+void DSNode::remapLinks(std::map<const DSNode*, DSNodeHandle> &OldNodeMap) {
+  for (unsigned i = 0, e = Links.size(); i != e; ++i) {
+    DSNodeHandle &H = OldNodeMap[Links[i].getNode()];
+    Links[i].setNode(H.getNode());
+    Links[i].setOffset(Links[i].getOffset()+H.getOffset());
+  }
 }
 
 
@@ -515,8 +572,8 @@ void DSNode::remapLinks(std::map<const DSNode*, DSNode*> &OldNodeMap) {
 //
 DSNodeHandle DSGraph::cloneInto(const DSGraph &G, 
                                 std::map<Value*, DSNodeHandle> &OldValMap,
-                                std::map<const DSNode*, DSNode*> &OldNodeMap,
-                                AllocaBit StripAllocas) {
+                              std::map<const DSNode*, DSNodeHandle> &OldNodeMap,
+                                unsigned CloneFlags) {
   assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!");
   assert(&G != this && "Cannot clone graph into itself!");
 
@@ -527,16 +584,21 @@ DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
   for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) {
     DSNode *Old = G.Nodes[i];
     DSNode *New = new DSNode(*Old);
+    New->NodeType &= ~DSNode::DEAD;  // Clear dead flag...
     Nodes.push_back(New);
     OldNodeMap[Old] = New;
   }
 
+#ifndef NDEBUG
+  Timer::addPeakMemoryMeasurement();
+#endif
+
   // Rewrite the links in the new nodes to point into the current graph now.
   for (unsigned i = FN, e = Nodes.size(); i != e; ++i)
     Nodes[i]->remapLinks(OldNodeMap);
 
   // Remove alloca markers as specified
-  if (StripAllocas == StripAllocaBit)
+  if (CloneFlags & StripAllocaBit)
     for (unsigned i = FN, e = Nodes.size(); i != e; ++i)
       Nodes[i]->NodeType &= ~DSNode::AllocaNode;
 
@@ -544,28 +606,40 @@ DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
   for (std::map<Value*, DSNodeHandle>::const_iterator I = G.ScalarMap.begin(),
          E = G.ScalarMap.end(); I != E; ++I) {
     DSNodeHandle &H = OldValMap[I->first];
-    H.setNode(OldNodeMap[I->second.getNode()]);
-    H.setOffset(I->second.getOffset());
+    DSNodeHandle &MappedNode = OldNodeMap[I->second.getNode()];
+    H.setNode(MappedNode.getNode());
+    H.setOffset(I->second.getOffset()+MappedNode.getOffset());
 
     if (isa<GlobalValue>(I->first)) {  // Is this a global?
       std::map<Value*, DSNodeHandle>::iterator GVI = ScalarMap.find(I->first);
       if (GVI != ScalarMap.end()) {   // Is the global value in this fn already?
         GVI->second.mergeWith(H);
-        OldNodeMap[I->second.getNode()] = H.getNode();
       } else {
         ScalarMap[I->first] = H;      // Add global pointer to this graph
       }
     }
   }
 
-  // Copy the function calls list...
-  unsigned FC = FunctionCalls.size();  // FirstCall
-  FunctionCalls.reserve(FC+G.FunctionCalls.size());
-  for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i)
-    FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap));
+  if (!(CloneFlags & DontCloneCallNodes)) {
+    // Copy the function calls list...
+    unsigned FC = FunctionCalls.size();  // FirstCall
+    FunctionCalls.reserve(FC+G.FunctionCalls.size());
+    for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i)
+      FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap));
+  }
+
+  if (!(CloneFlags & DontCloneAuxCallNodes)) {
+    // Copy the auxillary function calls list...
+    unsigned FC = AuxFunctionCalls.size();  // FirstCall
+    AuxFunctionCalls.reserve(FC+G.AuxFunctionCalls.size());
+    for (unsigned i = 0, ei = G.AuxFunctionCalls.size(); i != ei; ++i)
+      AuxFunctionCalls.push_back(DSCallSite(G.AuxFunctionCalls[i], OldNodeMap));
+  }
 
   // Return the returned node pointer...
-  return DSNodeHandle(OldNodeMap[G.RetNode.getNode()], G.RetNode.getOffset());
+  DSNodeHandle &MappedRet = OldNodeMap[G.RetNode.getNode()];
+  return DSNodeHandle(MappedRet.getNode(),
+                      MappedRet.getOffset()+G.RetNode.getOffset());
 }
 
 /// mergeInGraph - The method is used for merging graphs together.  If the
@@ -574,7 +648,7 @@ DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
 /// graph.
 ///
 void DSGraph::mergeInGraph(DSCallSite &CS, const DSGraph &Graph,
-                           AllocaBit StripAllocas) {
+                           unsigned CloneFlags) {
   std::map<Value*, DSNodeHandle> OldValMap;
   DSNodeHandle RetVal;
   std::map<Value*, DSNodeHandle> *ScalarMap = &OldValMap;
@@ -584,11 +658,11 @@ void DSGraph::mergeInGraph(DSCallSite &CS, const DSGraph &Graph,
     // Clone the callee's graph into the current graph, keeping
     // track of where scalars in the old graph _used_ to point,
     // and of the new nodes matching nodes of the old graph.
-    std::map<const DSNode*, DSNode*> OldNodeMap;
+    std::map<const DSNode*, DSNodeHandle> OldNodeMap;
     
     // The clone call may invalidate any of the vectors in the data
     // structure graph.  Strip locals and don't copy the list of callers
-    RetVal = cloneInto(Graph, OldValMap, OldNodeMap, StripAllocas);
+    RetVal = cloneInto(Graph, OldValMap, OldNodeMap, CloneFlags);
     ScalarMap = &OldValMap;
   } else {
     RetVal = getRetNode();
@@ -666,6 +740,14 @@ static void markIncompleteNode(DSNode *N) {
       markIncompleteNode(DSN);
 }
 
+static void markIncomplete(DSCallSite &Call) {
+  // Then the return value is certainly incomplete!
+  markIncompleteNode(Call.getRetVal().getNode());
+
+  // All objects pointed to by function arguments are incomplete!
+  for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i)
+    markIncompleteNode(Call.getPtrArg(i).getNode());
+}
 
 // markIncompleteNodes - Traverse the graph, identifying nodes that may be
 // modified by other functions that have not been resolved yet.  This marks
@@ -685,21 +767,18 @@ void DSGraph::markIncompleteNodes(bool markFormalArgs) {
         markIncompleteNode(ScalarMap[I].getNode());
 
   // Mark stuff passed into functions calls as being incomplete...
-  for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
-    DSCallSite &Call = FunctionCalls[i];
-    // Then the return value is certainly incomplete!
-    markIncompleteNode(Call.getRetVal().getNode());
-
-    // All objects pointed to by function arguments are incomplete though!
-    for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i)
-      markIncompleteNode(Call.getPtrArg(i).getNode());
-  }
+  if (!shouldPrintAuxCalls())
+    for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
+      markIncomplete(FunctionCalls[i]);
+  else
+    for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
+      markIncomplete(AuxFunctionCalls[i]);
+    
 
   // Mark all of the nodes pointed to by global nodes as incomplete...
   for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
     if (Nodes[i]->NodeType & DSNode::GlobalNode) {
       DSNode *N = Nodes[i];
-      // FIXME: Make more efficient by looking over Links directly
       for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
         if (DSNode *DSN = N->getLink(i).getNode())
           markIncompleteNode(DSN);
@@ -723,22 +802,23 @@ static void removeRefsToGlobal(DSNode* N,
 // dead.
 //
 bool DSGraph::isNodeDead(DSNode *N) {
-  // Is it a trivially dead shadow node...
-  if (N->getReferrers().empty() &&
-      (N->NodeType == 0 || N->NodeType == DSNode::DEAD))
-    return true;
-
-  // Is it a function node or some other trivially unused global?
-  if ((N->NodeType & ~DSNode::GlobalNode) == 0 && N->getSize() == 0 &&
-      N->getReferrers().size() == N->getGlobals().size()) {
+  // Is it a trivially dead shadow node?
+  return N->getReferrers().empty() && (N->NodeType & ~DSNode::DEAD) == 0;
+}
 
-    // Remove the globals from the ScalarMap, so that the referrer count will go
-    // down to zero.
-    removeRefsToGlobal(N, ScalarMap);
-    assert(N->getReferrers().empty() && "Referrers should all be gone now!");
-    return true;
-  }
+static inline void killIfUselessEdge(DSNodeHandle &Edge) {
+  if (DSNode *N = Edge.getNode())  // Is there an edge?
+    if (N->getReferrers().size() == 1)  // Does it point to a lonely node?
+      if ((N->NodeType & ~DSNode::Incomplete) == 0 && // No interesting info?
+          N->getType() == Type::VoidTy && !N->isNodeCompletelyFolded())
+        Edge.setNode(0);  // Kill the edge!
+}
 
+static inline bool nodeContainsExternalFunction(const DSNode *N) {
+  const std::vector<GlobalValue*> &Globals = N->getGlobals();
+  for (unsigned i = 0, e = Globals.size(); i != e; ++i)
+    if (Globals[i]->isExternal())
+      return true;
   return false;
 }
 
@@ -746,7 +826,63 @@ static void removeIdenticalCalls(vector<DSCallSite> &Calls,
                                  const std::string &where) {
   // Remove trivially identical function calls
   unsigned NumFns = Calls.size();
-  std::sort(Calls.begin(), Calls.end());
+  std::sort(Calls.begin(), Calls.end());  // Sort by callee as primary key!
+
+  // Scan the call list cleaning it up as necessary...
+  DSNode *LastCalleeNode = 0;
+  unsigned NumDuplicateCalls = 0;
+  bool LastCalleeContainsExternalFunction = false;
+  for (unsigned i = 0; i != Calls.size(); ++i) {
+    DSCallSite &CS = Calls[i];
+
+    // If the Callee is a useless edge, this must be an unreachable call site,
+    // eliminate it.
+    killIfUselessEdge(CS.getCallee());
+    if (CS.getCallee().getNode() == 0) {
+      CS.swap(Calls.back());
+      Calls.pop_back();
+      --i;
+    } else {
+      // If the return value or any arguments point to a void node with no
+      // information at all in it, and the call node is the only node to point
+      // to it, remove the edge to the node (killing the node).
+      //
+      killIfUselessEdge(CS.getRetVal());
+      for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
+        killIfUselessEdge(CS.getPtrArg(a));
+      
+      // If this call site calls the same function as the last call site, and if
+      // the function pointer contains an external function, this node will
+      // never be resolved.  Merge the arguments of the call node because no
+      // information will be lost.
+      //
+      if (CS.getCallee().getNode() == LastCalleeNode) {
+        ++NumDuplicateCalls;
+        if (NumDuplicateCalls == 1) {
+          LastCalleeContainsExternalFunction =
+            nodeContainsExternalFunction(LastCalleeNode);
+        }
+        
+        if (LastCalleeContainsExternalFunction ||
+            // This should be more than enough context sensitivity!
+            // FIXME: Evaluate how many times this is tripped!
+            NumDuplicateCalls > 20) {
+          DSCallSite &OCS = Calls[i-1];
+          OCS.mergeWith(CS);
+          
+          // The node will now be eliminated as a duplicate!
+          if (CS.getNumPtrArgs() < OCS.getNumPtrArgs())
+            CS = OCS;
+          else if (CS.getNumPtrArgs() > OCS.getNumPtrArgs())
+            OCS = CS;
+        }
+      } else {
+        LastCalleeNode = CS.getCallee().getNode();
+        NumDuplicateCalls = 0;
+      }
+    }
+  }
+
   Calls.erase(std::unique(Calls.begin(), Calls.end()),
               Calls.end());
 
@@ -758,20 +894,21 @@ static void removeIdenticalCalls(vector<DSCallSite> &Calls,
                     << " call nodes in " << where << "\n";);
 }
 
+
 // removeTriviallyDeadNodes - After the graph has been constructed, this method
 // removes all unreachable nodes that are created because they got merged with
 // other nodes in the graph.  These nodes will all be trivially unreachable, so
 // we don't have to perform any non-trivial analysis here.
 //
-void DSGraph::removeTriviallyDeadNodes(bool KeepAllGlobals) {
-  for (unsigned i = 0; i != Nodes.size(); ++i)
-    if (!KeepAllGlobals || !(Nodes[i]->NodeType & DSNode::GlobalNode))
-      if (isNodeDead(Nodes[i])) {               // This node is dead!
-        delete Nodes[i];                        // Free memory...
-        Nodes.erase(Nodes.begin()+i--);         // Remove from node list...
-      }
-
+void DSGraph::removeTriviallyDeadNodes() {
   removeIdenticalCalls(FunctionCalls, Func ? Func->getName() : "");
+  removeIdenticalCalls(AuxFunctionCalls, Func ? Func->getName() : "");
+
+  for (unsigned i = 0; i != Nodes.size(); ++i)
+    if (isNodeDead(Nodes[i])) {               // This node is dead!
+      delete Nodes[i];                        // Free memory...
+      Nodes.erase(Nodes.begin()+i--);         // Remove from node list...
+    }
 }
 
 
@@ -780,152 +917,65 @@ void DSGraph::removeTriviallyDeadNodes(bool KeepAllGlobals) {
 //
 static void markAlive(DSNode *N, std::set<DSNode*> &Alive) {
   if (N == 0) return;
+  std::set<DSNode*>::iterator I = Alive.lower_bound(N);
+  if (I != Alive.end() && *I == N) return;  // Already marked alive
+  Alive.insert(I, N);                       // Is alive now
 
-  Alive.insert(N);
   for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
-    if (DSNode *DSN = N->getLink(i).getNode())
-      if (!Alive.count(DSN))
-        markAlive(DSN, Alive);
+    markAlive(N->getLink(i).getNode(), Alive);
 }
 
-static bool checkGlobalAlive(DSNode *N, std::set<DSNode*> &Alive,
-                             std::set<DSNode*> &Visiting) {
+// markAliveIfCanReachAlive - Simple graph walker that recursively traverses the
+// graph looking for a node that is marked alive.  If the node is marked alive,
+// the recursive unwind marks node alive that can point to the alive node.  This
+// is basically just a post-order traversal.
+//
+// This function returns true if the specified node is alive.
+//
+static bool markAliveIfCanReachAlive(DSNode *N, std::set<DSNode*> &Alive,
+                                     std::set<DSNode*> &Visited) {
   if (N == 0) return false;
 
-  if (Visiting.count(N)) return false; // terminate recursion on a cycle
-  Visiting.insert(N);
+  // If we know that this node is alive, return so!
+  if (Alive.count(N)) return true;
 
-  // If any immediate successor is alive, N is alive
-  for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
-    if (DSNode *DSN = N->getLink(i).getNode())
-      if (Alive.count(DSN)) {
-        Visiting.erase(N);
-        return true;
-      }
+  // Otherwise, we don't think the node is alive yet, check for infinite
+  // recursion.
+  std::set<DSNode*>::iterator VI = Visited.lower_bound(N);
+  if (VI != Visited.end() && *VI == N) return false;  // Found a cycle
+  // No recursion, insert into Visited...
+  Visited.insert(VI, N);
 
-  // Else if any successor reaches a live node, N is alive
-  for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
-    if (DSNode *DSN = N->getLink(i).getNode())
-      if (checkGlobalAlive(DSN, Alive, Visiting)) {
-        Visiting.erase(N); return true;
-      }
+  if (N->NodeType & DSNode::GlobalNode)
+    return false; // Global nodes will be marked on their own
 
-  Visiting.erase(N);
-  return false;
-}
+  bool ChildrenAreAlive = false;
 
-
-// markGlobalsIteration - Recursive helper function for markGlobalsAlive().
-// This would be unnecessary if function calls were real nodes!  In that case,
-// the simple iterative loop in the first few lines below suffice.
-// 
-static void markGlobalsIteration(std::set<DSNode*>& GlobalNodes,
-                                 vector<DSCallSite> &Calls,
-                                 std::set<DSNode*> &Alive,
-                                 bool FilterCalls) {
-
-  // Iterate, marking globals or cast nodes alive until no new live nodes
-  // are added to Alive
-  std::set<DSNode*> Visiting;           // Used to identify cycles 
-  std::set<DSNode*>::iterator I = GlobalNodes.begin(), E = GlobalNodes.end();
-  for (size_t liveCount = 0; liveCount < Alive.size(); ) {
-    liveCount = Alive.size();
-    for ( ; I != E; ++I)
-      if (Alive.count(*I) == 0) {
-        Visiting.clear();
-        if (checkGlobalAlive(*I, Alive, Visiting))
-          markAlive(*I, Alive);
-      }
-  }
-
-  // Find function calls with some dead and some live nodes.
-  // Since all call nodes must be live if any one is live, we have to mark
-  // all nodes of the call as live and continue the iteration (via recursion).
-  if (FilterCalls) {
-    bool Recurse = false;
-    for (unsigned i = 0, ei = Calls.size(); i < ei; ++i) {
-      bool CallIsDead = true, CallHasDeadArg = false;
-      DSCallSite &CS = Calls[i];
-      for (unsigned j = 0, ej = CS.getNumPtrArgs(); j != ej; ++j)
-        if (DSNode *N = CS.getPtrArg(j).getNode()) {
-          bool ArgIsDead  = !Alive.count(N);
-          CallHasDeadArg |= ArgIsDead;
-          CallIsDead     &= ArgIsDead;
-        }
-
-      if (DSNode *N = CS.getRetVal().getNode()) {
-        bool RetIsDead  = !Alive.count(N);
-        CallHasDeadArg |= RetIsDead;
-        CallIsDead     &= RetIsDead;
-      }
-
-      DSNode *N = CS.getCallee().getNode();
-      bool FnIsDead  = !Alive.count(N);
-      CallHasDeadArg |= FnIsDead;
-      CallIsDead     &= FnIsDead;
-
-      if (!CallIsDead && CallHasDeadArg) {
-        // Some node in this call is live and another is dead.
-        // Mark all nodes of call as live and iterate once more.
-        Recurse = true;
-        for (unsigned j = 0, ej = CS.getNumPtrArgs(); j != ej; ++j)
-          markAlive(CS.getPtrArg(j).getNode(), Alive);
-        markAlive(CS.getRetVal().getNode(), Alive);
-        markAlive(CS.getCallee().getNode(), Alive);
-      }
-    }
-    if (Recurse)
-      markGlobalsIteration(GlobalNodes, Calls, Alive, FilterCalls);
-  }
+  for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
+    ChildrenAreAlive |= markAliveIfCanReachAlive(N->getLink(i).getNode(),
+                                                 Alive, Visited);
+  if (ChildrenAreAlive)
+    markAlive(N, Alive);
+  return ChildrenAreAlive;
 }
 
+static bool CallSiteUsesAliveArgs(DSCallSite &CS, std::set<DSNode*> &Alive,
+                                  std::set<DSNode*> &Visited) {
+  if (markAliveIfCanReachAlive(CS.getRetVal().getNode(), Alive, Visited) ||
+      markAliveIfCanReachAlive(CS.getCallee().getNode(), Alive, Visited))
+    return true;
+  for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j)
+    if (markAliveIfCanReachAlive(CS.getPtrArg(j).getNode(), Alive, Visited))
+      return true;
+  return false;
+}
 
-// markGlobalsAlive - Mark global nodes and cast nodes alive if they
-// can reach any other live node.  Since this can produce new live nodes,
-// we use a simple iterative algorithm.
-// 
-static void markGlobalsAlive(DSGraph &G, std::set<DSNode*> &Alive,
-                             bool FilterCalls) {
-  // Add global and cast nodes to a set so we don't walk all nodes every time
-  std::set<DSNode*> GlobalNodes;
-  for (unsigned i = 0, e = G.getNodes().size(); i != e; ++i)
-    if (G.getNodes()[i]->NodeType & DSNode::GlobalNode)
-      GlobalNodes.insert(G.getNodes()[i]);
-
-  // Add all call nodes to the same set
-  vector<DSCallSite> &Calls = G.getFunctionCalls();
-  if (FilterCalls) {
-    for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
-      for (unsigned j = 0, e = Calls[i].getNumPtrArgs(); j != e; ++j)
-        if (DSNode *N = Calls[i].getPtrArg(j).getNode())
-          GlobalNodes.insert(N);
-      if (DSNode *N = Calls[i].getRetVal().getNode())
-        GlobalNodes.insert(N);
-      if (DSNode *N = Calls[i].getCallee().getNode())
-        GlobalNodes.insert(N);
-    }
-  }
-
-  // Iterate and recurse until no new live node are discovered.
-  // This would be a simple iterative loop if function calls were real nodes!
-  markGlobalsIteration(GlobalNodes, Calls, Alive, FilterCalls);
-
-  // Free up references to dead globals from the ScalarMap
-  std::set<DSNode*>::iterator I = GlobalNodes.begin(), E = GlobalNodes.end();
-  for( ; I != E; ++I)
-    if (Alive.count(*I) == 0)
-      removeRefsToGlobal(*I, G.getScalarMap());
-
-  // Delete dead function calls
-  if (FilterCalls)
-    for (int ei = Calls.size(), i = ei-1; i >= 0; --i) {
-      bool CallIsDead = true;
-      for (unsigned j = 0, ej = Calls[i].getNumPtrArgs();
-           CallIsDead && j != ej; ++j)
-        CallIsDead = Alive.count(Calls[i].getPtrArg(j).getNode()) == 0;
-      if (CallIsDead)
-        Calls.erase(Calls.begin() + i); // remove the call entirely
-    }
+static void markAlive(DSCallSite &CS, std::set<DSNode*> &Alive) {
+  markAlive(CS.getRetVal().getNode(), Alive);
+  markAlive(CS.getCallee().getNode(), Alive);
+  
+  for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j)
+    markAlive(CS.getPtrArg(j).getNode(), Alive);
 }
 
 // removeDeadNodes - Use a more powerful reachability analysis to eliminate
@@ -934,41 +984,70 @@ static void markGlobalsAlive(DSGraph &G, std::set<DSNode*> &Alive,
 // from the caller's graph entirely.  This is only appropriate to use when
 // inlining graphs.
 //
-void DSGraph::removeDeadNodes(bool KeepAllGlobals, bool KeepCalls) {
-  assert((!KeepAllGlobals || KeepCalls) &&  // FIXME: This should be an enum!
-         "KeepAllGlobals without KeepCalls is meaningless");
-
+void DSGraph::removeDeadNodes() {
   // Reduce the amount of work we have to do...
-  removeTriviallyDeadNodes(KeepAllGlobals);
+  removeTriviallyDeadNodes();
 
   // FIXME: Merge nontrivially identical call nodes...
 
   // Alive - a set that holds all nodes found to be reachable/alive.
   std::set<DSNode*> Alive;
+  std::vector<std::pair<Value*, DSNode*> > GlobalNodes;
 
-  // If KeepCalls, mark all nodes reachable by call nodes as alive...
-  if (KeepCalls)
-    for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
-      for (unsigned j = 0, e = FunctionCalls[i].getNumPtrArgs(); j != e; ++j)
-        markAlive(FunctionCalls[i].getPtrArg(j).getNode(), Alive);
-      markAlive(FunctionCalls[i].getRetVal().getNode(), Alive);
-      markAlive(FunctionCalls[i].getCallee().getNode(), Alive);
-    }
-
-  // Mark all nodes reachable by scalar nodes as alive...
+  // Mark all nodes reachable by (non-global) scalar nodes as alive...
   for (std::map<Value*, DSNodeHandle>::iterator I = ScalarMap.begin(),
          E = ScalarMap.end(); I != E; ++I)
-    markAlive(I->second.getNode(), Alive);
+    if (!isa<GlobalValue>(I->first))              // Don't mark globals!
+      markAlive(I->second.getNode(), Alive);
+    else                    // Keep track of global nodes
+      GlobalNodes.push_back(std::make_pair(I->first, I->second.getNode()));
 
   // The return value is alive as well...
   markAlive(RetNode.getNode(), Alive);
 
-  // Mark all globals or cast nodes that can reach a live node as alive.
-  // This also marks all nodes reachable from such nodes as alive.
-  // Of course, if KeepAllGlobals is specified, they would be live already.
+  // If any global nodes points to a non-global that is "alive", the global is
+  // "alive" as well...
+  //
+  std::set<DSNode*> Visited;
+  for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i)
+    markAliveIfCanReachAlive(GlobalNodes[i].second, Alive, Visited);
+
+  std::vector<bool> FCallsAlive(FunctionCalls.size());
+  for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
+    if (CallSiteUsesAliveArgs(FunctionCalls[i], Alive, Visited)) {
+      markAlive(FunctionCalls[i], Alive);
+      FCallsAlive[i] = true;
+    }
 
-  if (!KeepAllGlobals)
-    markGlobalsAlive(*this, Alive, !KeepCalls);
+  std::vector<bool> AuxFCallsAlive(AuxFunctionCalls.size());
+  for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
+    if (CallSiteUsesAliveArgs(AuxFunctionCalls[i], Alive, Visited)) {
+      markAlive(AuxFunctionCalls[i], Alive);
+      AuxFCallsAlive[i] = true;
+    }
+
+  // Remove all dead function calls...
+  unsigned CurIdx = 0;
+  for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
+    if (FCallsAlive[i])
+      FunctionCalls[CurIdx++].swap(FunctionCalls[i]);
+  // Crop all the bad ones out...
+  FunctionCalls.erase(FunctionCalls.begin()+CurIdx, FunctionCalls.end());
+
+  // Remove all dead aux function calls...
+  CurIdx = 0;
+  for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
+    if (AuxFCallsAlive[i])
+      AuxFunctionCalls[CurIdx++].swap(AuxFunctionCalls[i]);
+  // Crop all the bad ones out...
+  AuxFunctionCalls.erase(AuxFunctionCalls.begin()+CurIdx,
+                         AuxFunctionCalls.end());
+
+
+  // Remove all unreachable globals from the ScalarMap
+  for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i)
+    if (!Alive.count(GlobalNodes[i].second))
+      ScalarMap.erase(GlobalNodes[i].first);
 
   // Loop over all unreachable nodes, dropping their references...
   vector<DSNode*> DeadNodes;
@@ -985,44 +1064,11 @@ void DSGraph::removeDeadNodes(bool KeepAllGlobals, bool KeepCalls) {
   std::for_each(DeadNodes.begin(), DeadNodes.end(), deleter<DSNode>);
 }
 
-
-
-// maskNodeTypes - Apply a mask to all of the node types in the graph.  This
-// is useful for clearing out markers like Scalar or Incomplete.
-//
-void DSGraph::maskNodeTypes(unsigned char Mask) {
-  for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
-    Nodes[i]->NodeType &= Mask;
-}
-
-
 #if 0
 //===----------------------------------------------------------------------===//
 // GlobalDSGraph Implementation
 //===----------------------------------------------------------------------===//
 
-GlobalDSGraph::GlobalDSGraph() : DSGraph(*(Function*)0, this) {
-}
-
-GlobalDSGraph::~GlobalDSGraph() {
-  assert(Referrers.size() == 0 &&
-         "Deleting global graph while references from other graphs exist");
-}
-
-void GlobalDSGraph::addReference(const DSGraph* referrer) {
-  if (referrer != this)
-    Referrers.insert(referrer);
-}
-
-void GlobalDSGraph::removeReference(const DSGraph* referrer) {
-  if (referrer != this) {
-    assert(Referrers.find(referrer) != Referrers.end() && "This is very bad!");
-    Referrers.erase(referrer);
-    if (Referrers.size() == 0)
-      delete this;
-  }
-}
-
 #if 0
 // Bits used in the next function
 static const char ExternalTypeBits = DSNode::GlobalNode | DSNode::HeapNode;
@@ -1113,23 +1159,6 @@ DSNode* GlobalDSGraph::cloneNodeInto(DSNode *OldNode,
 }
 
 
-// GlobalDSGraph::cloneGlobals - Clone global nodes and all their externally
-// visible target links (and recursively their such links) into this graph.
-// 
-void GlobalDSGraph::cloneGlobals(DSGraph& Graph, bool CloneCalls) {
-  std::map<const DSNode*, DSNode*> NodeCache;
-#if 0
-  for (unsigned i = 0, N = Graph.Nodes.size(); i < N; ++i)
-    if (Graph.Nodes[i]->NodeType & DSNode::GlobalNode)
-      GlobalsGraph->cloneNodeInto(Graph.Nodes[i], NodeCache, false);
-  if (CloneCalls)
-    GlobalsGraph->cloneCalls(Graph);
-
-  GlobalsGraph->removeDeadNodes(/*KeepAllGlobals*/ true, /*KeepCalls*/ true);
-#endif
-}
-
-
 // GlobalDSGraph::cloneCalls - Clone function calls and their visible target
 // links (and recursively their such links) into this graph.
 //