Make error messages more useful than jsut an abort
[oota-llvm.git] / lib / Analysis / DataStructure / BottomUpClosure.cpp
index d8ae1de7be0f76ab471af96eb8833d176187172e..0833a029129095c78b86978ee2150c5325635ef5 100644 (file)
@@ -11,7 +11,7 @@
 #include "llvm/Analysis/DSGraph.h"
 #include "llvm/Module.h"
 #include "Support/Statistic.h"
-using std::map;
+#include "Support/hash_map"
 
 namespace {
   Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
@@ -22,6 +22,13 @@ namespace {
 
 using namespace DS;
 
+static bool isVAHackFn(const Function *F) {
+  return F->getName() == "printf"  || F->getName() == "sscanf" ||
+         F->getName() == "fprintf" || F->getName() == "open" ||
+         F->getName() == "sprintf" || F->getName() == "fputs" ||
+         F->getName() == "fscanf";
+}
+
 // isCompleteNode - Return true if we know all of the targets of this node, and
 // if the call sites are not external.
 //
@@ -29,13 +36,9 @@ static inline bool isCompleteNode(DSNode *N) {
   if (N->NodeType & DSNode::Incomplete) return false;
   const std::vector<GlobalValue*> &Callees = N->getGlobals();
   for (unsigned i = 0, e = Callees.size(); i != e; ++i)
-    if (Callees[i]->isExternal()) {
-      GlobalValue &FI = cast<Function>(*Callees[i]);
-      if (FI.getName() != "printf"  && FI.getName() != "sscanf" &&
-          FI.getName() != "fprintf" && FI.getName() != "open" &&
-          FI.getName() != "sprintf" && FI.getName() != "fputs")
+    if (Callees[i]->isExternal())
+      if (!isVAHackFn(cast<Function>(Callees[i])))
         return false;  // External function found...
-    }
   return true;  // otherwise ok
 }
 
@@ -47,7 +50,7 @@ struct CallSiteIterator {
 
   CallSiteIterator(std::vector<DSCallSite> &CS) : FCs(&CS) {
     CallSite = 0; CallSiteEntry = 0;
-    advanceToNextValid();
+    advanceToValidCallee();
   }
 
   // End iterator ctor...
@@ -55,18 +58,24 @@ struct CallSiteIterator {
     CallSite = FCs->size(); CallSiteEntry = 0;
   }
 
-  void advanceToNextValid() {
+  void advanceToValidCallee() {
     while (CallSite < FCs->size()) {
-      if (DSNode *CalleeNode = (*FCs)[CallSite].getCallee().getNode()) {
+      if ((*FCs)[CallSite].isDirectCall()) {
+        if (CallSiteEntry == 0 &&        // direct call only has one target...
+            (!(*FCs)[CallSite].getCalleeFunc()->isExternal() ||
+             isVAHackFn((*FCs)[CallSite].getCalleeFunc()))) // If not external
+          return;
+      } else {
+        DSNode *CalleeNode = (*FCs)[CallSite].getCalleeNode();
         if (CallSiteEntry || isCompleteNode(CalleeNode)) {
           const std::vector<GlobalValue*> &Callees = CalleeNode->getGlobals();
           
           if (CallSiteEntry < Callees.size())
             return;
         }
-        CallSiteEntry = 0;
-        ++CallSite;
       }
+      CallSiteEntry = 0;
+      ++CallSite;
     }
   }
 public:
@@ -86,14 +95,18 @@ public:
   unsigned getCallSiteIdx() const { return CallSite; }
   DSCallSite &getCallSite() const { return (*FCs)[CallSite]; }
 
-  Function* operator*() const {
-    DSNode *Node = (*FCs)[CallSite].getCallee().getNode();
-    return cast<Function>(Node->getGlobals()[CallSiteEntry]);
+  Function *operator*() const {
+    if ((*FCs)[CallSite].isDirectCall()) {
+      return (*FCs)[CallSite].getCalleeFunc();
+    } else {
+      DSNode *Node = (*FCs)[CallSite].getCalleeNode();
+      return cast<Function>(Node->getGlobals()[CallSiteEntry]);
+    }
   }
 
   CallSiteIterator& operator++() {                // Preincrement
     ++CallSiteEntry;
-    advanceToNextValid();
+    advanceToValidCallee();
     return *this;
   }
   CallSiteIterator operator++(int) { // Postincrement
@@ -108,6 +121,7 @@ public:
 //
 bool BUDataStructures::run(Module &M) {
   GlobalsGraph = new DSGraph();
+  GlobalsGraph->setPrintAuxCalls();
 
   Function *MainFunc = M.getMainFunction();
   if (MainFunc)
@@ -128,7 +142,7 @@ bool BUDataStructures::run(Module &M) {
 
 void BUDataStructures::calculateReachableGraphs(Function *F) {
   std::vector<Function*> Stack;
-  std::map<Function*, unsigned> ValMap;
+  hash_map<Function*, unsigned> ValMap;
   unsigned NextID = 1;
   calculateGraphs(F, Stack, NextID, ValMap);
 }
@@ -152,7 +166,7 @@ DSGraph &BUDataStructures::getOrCreateGraph(Function *F) {
 unsigned BUDataStructures::calculateGraphs(Function *F,
                                            std::vector<Function*> &Stack,
                                            unsigned &NextID, 
-                                     std::map<Function*, unsigned> &ValMap) {
+                                     hash_map<Function*, unsigned> &ValMap) {
   assert(ValMap.find(F) == ValMap.end() && "Shouldn't revisit functions!");
   unsigned Min = NextID++, MyID = Min;
   ValMap[F] = Min;
@@ -173,7 +187,7 @@ unsigned BUDataStructures::calculateGraphs(Function *F,
     Function *Callee = *I;
     unsigned M;
     // Have we visited the destination function yet?
-    std::map<Function*, unsigned>::iterator It = ValMap.find(Callee);
+    hash_map<Function*, unsigned>::iterator It = ValMap.find(Callee);
     if (It == ValMap.end())  // No, visit it now.
       M = calculateGraphs(Callee, Stack, NextID, ValMap);
     else                    // Yes, get it's number.
@@ -206,7 +220,7 @@ unsigned BUDataStructures::calculateGraphs(Function *F,
   } else {
     // SCCFunctions - Keep track of the functions in the current SCC
     //
-    std::set<Function*> SCCFunctions;
+    hash_set<Function*> SCCFunctions;
 
     Function *NF;
     std::vector<Function*>::iterator FirstInSCC = Stack.end();
@@ -283,7 +297,7 @@ unsigned BUDataStructures::calculateGraphs(Function *F,
 // our memory... here...
 //
 void BUDataStructures::releaseMemory() {
-  for (map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
+  for (hash_map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
          E = DSInfo.end(); I != E; ++I)
     delete I->second;
 
@@ -335,17 +349,19 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
       DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
       
       DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
-            << " in: " << F.getName() << "[" << GI.getGraphSize() << "+"
-            << GI.getAuxFunctionCalls().size() << "]\n");
-
+            << "[" << GI.getGraphSize() << "+"
+            << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+            << "[" << Graph.getGraphSize() << "+"
+            << Graph.getAuxFunctionCalls().size() << "]\n");
 #if 0
       Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_before_" +
                              Callee->getName());
 #endif
       
       // Handle self recursion by resolving the arguments and return value
-      Graph.mergeInGraph(CS, GI, DSGraph::StripAllocaBit |
-                         DSGraph::DontCloneCallNodes);
+      Graph.mergeInGraph(CS, GI,
+                         DSGraph::KeepModRefBits | 
+                         DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes);
 
 #if 0
       Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_after_" +
@@ -363,8 +379,9 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
   // Recompute the Incomplete markers.  If there are any function calls left
   // now that are complete, we must loop!
   Graph.maskIncompleteMarkers();
-  Graph.markIncompleteNodes();
-  Graph.removeDeadNodes();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+  // FIXME: materialize nodes from the globals graph as neccesary...
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
 
   DEBUG(std::cerr << "  [BU] Done inlining: " << F.getName() << " ["
         << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
@@ -382,7 +399,7 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
 // IN the SCC at all.
 //
 DSGraph &BUDataStructures::inlineNonSCCGraphs(Function &F,
-                                             std::set<Function*> &SCCFunctions){
+                                             hash_set<Function*> &SCCFunctions){
   DSGraph &Graph = getDSGraph(F);
   DEBUG(std::cerr << "  [BU] Inlining Non-SCC graphs for: "
                   << F.getName() << "\n");
@@ -418,13 +435,16 @@ DSGraph &BUDataStructures::inlineNonSCCGraphs(Function &F,
       // Get the data structure graph for the called function.
       //
       DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
-      
+
       DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
-            << " in: " << F.getName() << "[" << GI.getGraphSize() << "+"
-            << GI.getAuxFunctionCalls().size() << "]\n");
+            << "[" << GI.getGraphSize() << "+"
+            << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+            << "[" << Graph.getGraphSize() << "+"
+            << Graph.getAuxFunctionCalls().size() << "]\n");
 
       // Handle self recursion by resolving the arguments and return value
-      Graph.mergeInGraph(CS, GI, DSGraph::StripAllocaBit |
+      Graph.mergeInGraph(CS, GI,
+                         DSGraph::KeepModRefBits | DSGraph::StripAllocaBit |
                          DSGraph::DontCloneCallNodes);
     }
   }
@@ -438,24 +458,24 @@ DSGraph &BUDataStructures::inlineNonSCCGraphs(Function &F,
   // Recompute the Incomplete markers.  If there are any function calls left
   // now that are complete, we must loop!
   Graph.maskIncompleteMarkers();
-  Graph.markIncompleteNodes();
-  Graph.removeDeadNodes();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
 
   DEBUG(std::cerr << "  [BU] Done Non-SCC inlining: " << F.getName() << " ["
         << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
         << "]\n");
-
+  //Graph.writeGraphToFile(std::cerr, "nscc_" + F.getName());
   return Graph;
 }
 
 
 DSGraph &BUDataStructures::calculateSCCGraph(Function &F,
-                                             std::set<Function*> &SCCFunctions){
+                                             hash_set<Function*> &SCCFunctions){
   DSGraph &Graph = getDSGraph(F);
   DEBUG(std::cerr << "  [BU] Calculating SCC graph for: " << F.getName()<<"\n");
 
   std::vector<DSCallSite> UnresolvableCalls;
-  std::map<Function*, DSCallSite> SCCCallSiteMap;
+  hash_map<Function*, DSCallSite> SCCCallSiteMap;
   std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
 
   while (1) {  // Loop until we run out of resolvable call sites!
@@ -463,7 +483,7 @@ DSGraph &BUDataStructures::calculateSCCGraph(Function &F,
     // the new call site list and doesn't invalidate our iterators!
     std::vector<DSCallSite> TempFCs;
     TempFCs.swap(AuxCallsList);
-    
+
     // Loop over all of the resolvable call sites
     unsigned LastCallSiteIdx = ~0U;
     CallSiteIterator I = CallSiteIterator::begin(TempFCs),
@@ -502,13 +522,15 @@ DSGraph &BUDataStructures::calculateSCCGraph(Function &F,
         // Get the data structure graph for the called function.
         //
         DSGraph &GI = getDSGraph(*Callee);  // Graph to inline
-        
         DEBUG(std::cerr << "    Inlining graph for " << Callee->getName()
-              << " in: " << F.getName() << "[" << GI.getGraphSize() << "+"
-              << GI.getAuxFunctionCalls().size() << "]\n");
+              << "[" << GI.getGraphSize() << "+"
+              << GI.getAuxFunctionCalls().size() << "] into: " << F.getName()
+              << "[" << Graph.getGraphSize() << "+"
+              << Graph.getAuxFunctionCalls().size() << "]\n");
         
         // Handle self recursion by resolving the arguments and return value
-        Graph.mergeInGraph(CS, GI, DSGraph::StripAllocaBit |
+        Graph.mergeInGraph(CS, GI,
+                           DSGraph::KeepModRefBits | DSGraph::StripAllocaBit |
                            DSGraph::DontCloneCallNodes);
 
         if (SCCFunctions.count(Callee))
@@ -532,13 +554,15 @@ DSGraph &BUDataStructures::calculateSCCGraph(Function &F,
   // Recompute the Incomplete markers.  If there are any function calls left
   // now that are complete, we must loop!
   Graph.maskIncompleteMarkers();
-  Graph.markIncompleteNodes();
-  Graph.removeDeadNodes();
+  Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
+
+  // FIXME: materialize nodes from the globals graph as neccesary...
+
+  Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
 
   DEBUG(std::cerr << "  [BU] Done inlining: " << F.getName() << " ["
         << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
         << "]\n");
   //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
-
   return Graph;
 }