//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
//
// This file implements the BUDataStructures class, which represents the
// Bottom-Up Interprocedural closure of the data structure graph over the
//
//===----------------------------------------------------------------------===//
-#include "llvm/Analysis/DataStructure.h"
+#include "llvm/Analysis/DataStructure/DataStructure.h"
#include "llvm/Module.h"
#include "Support/Statistic.h"
+#include "Support/Debug.h"
#include "DSCallSiteIterator.h"
+using namespace llvm;
namespace {
Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
Statistic<> NumBUInlines("budatastructures", "Number of graphs inlined");
+ Statistic<> NumCallEdges("budatastructures", "Number of 'actual' call edges");
RegisterAnalysis<BUDataStructures>
X("budatastructure", "Bottom-up Data Structure Analysis");
#endif
calculateReachableGraphs(I); // Calculate all graphs...
}
+
+ NumCallEdges += ActualCallees.size();
+
+ // At the end of the bottom-up pass, the globals graph becomes complete.
+ // FIXME: This is not the right way to do this, but it is sorta better than
+ // nothing! In particular, externally visible globals and unresolvable call
+ // nodes at the end of the BU phase should make things that they point to
+ // incomplete in the globals graph.
+ //
+ GlobalsGraph->removeTriviallyDeadNodes();
+ GlobalsGraph->maskIncompleteMarkers();
return false;
}
std::vector<Function*> &Stack,
unsigned &NextID,
hash_map<Function*, unsigned> &ValMap) {
- assert(ValMap.find(F) == ValMap.end() && "Shouldn't revisit functions!");
+ assert(!ValMap.count(F) && "Shouldn't revisit functions!");
unsigned Min = NextID++, MyID = Min;
ValMap[F] = Min;
Stack.push_back(F);
+ // FIXME! This test should be generalized to be any function that we have
+ // already processed, in the case when there isn't a main or there are
+ // unreachable functions!
if (F->isExternal()) { // sprintf, fprintf, sscanf, etc...
// No callees!
Stack.pop_back();
} else {
// SCCFunctions - Keep track of the functions in the current SCC
//
- hash_set<Function*> SCCFunctions;
+ hash_set<DSGraph*> SCCGraphs;
Function *NF;
std::vector<Function*>::iterator FirstInSCC = Stack.end();
do {
NF = *--FirstInSCC;
ValMap[NF] = ~0U;
- SCCFunctions.insert(NF);
// Figure out which graph is the largest one, in order to speed things up
// a bit in situations where functions in the SCC have widely different
// graph sizes.
DSGraph &NFGraph = getDSGraph(*NF);
+ SCCGraphs.insert(&NFGraph);
+ // FIXME: If we used a better way of cloning graphs (ie, just splice all
+ // of the nodes into the new graph), this would be completely unneeded!
if (!SCCGraph || SCCGraph->getGraphSize() < NFGraph.getGraphSize())
SCCGraph = &NFGraph;
} while (NF != F);
std::cerr << "Calculating graph for SCC #: " << MyID << " of size: "
- << SCCFunctions.size() << "\n";
+ << SCCGraphs.size() << "\n";
// Compute the Max SCC Size...
- if (MaxSCC < SCCFunctions.size())
- MaxSCC = SCCFunctions.size();
+ if (MaxSCC < SCCGraphs.size())
+ MaxSCC = SCCGraphs.size();
// First thing first, collapse all of the DSGraphs into a single graph for
// the entire SCC. We computed the largest graph, so clone all of the other
// (smaller) graphs into it. Discard all of the old graphs.
//
- for (hash_set<Function*>::iterator I = SCCFunctions.begin(),
- E = SCCFunctions.end(); I != E; ++I) {
- DSGraph &G = getDSGraph(**I);
+ for (hash_set<DSGraph*>::iterator I = SCCGraphs.begin(),
+ E = SCCGraphs.end(); I != E; ++I) {
+ DSGraph &G = **I;
if (&G != SCCGraph) {
- DSGraph::NodeMapTy NodeMap;
- SCCGraph->cloneInto(G, SCCGraph->getScalarMap(),
- SCCGraph->getReturnNodes(), NodeMap, 0);
+ {
+ DSGraph::NodeMapTy NodeMap;
+ SCCGraph->cloneInto(G, SCCGraph->getScalarMap(),
+ SCCGraph->getReturnNodes(), NodeMap);
+ }
// Update the DSInfo map and delete the old graph...
- DSInfo[*I] = SCCGraph;
+ for (DSGraph::ReturnNodesTy::iterator I = G.getReturnNodes().begin(),
+ E = G.getReturnNodes().end(); I != E; ++I)
+ DSInfo[I->first] = SCCGraph;
delete &G;
}
}
// Clean up the graph before we start inlining a bunch again...
- SCCGraph->removeTriviallyDeadNodes();
+ SCCGraph->removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
// Now that we have one big happy family, resolve all of the call sites in
// the graph...
if (Callee->isExternal()) {
// Ignore this case, simple varargs functions we cannot stub out!
- } else if (ReturnNodes.find(Callee) != ReturnNodes.end()) {
+ } else if (ReturnNodes.count(Callee)) {
// Self recursion... simply link up the formal arguments with the
// actual arguments...
DEBUG(std::cerr << " Self Inlining: " << Callee->getName() << "\n");
Graph.mergeInGraph(CS, *Callee, Graph, 0);
} else {
- ActualCallees.insert(std::make_pair(&CS.getCallInst(), Callee));
+ ActualCallees.insert(std::make_pair(CS.getCallSite().getInstruction(),
+ Callee));
// Get the data structure graph for the called function.
//
DSGraph &GI = getDSGraph(*Callee); // Graph to inline
-
+
DEBUG(std::cerr << " Inlining graph for " << Callee->getName()
<< "[" << GI.getGraphSize() << "+"
<< GI.getAuxFunctionCalls().size() << "] into '"
<< Graph.getFunctionNames() << "' [" << Graph.getGraphSize() << "+"
<< Graph.getAuxFunctionCalls().size() << "]\n");
-
- // Handle self recursion by resolving the arguments and return value
Graph.mergeInGraph(CS, *Callee, GI,
DSGraph::KeepModRefBits |
DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes);
TempFCs.clear();
- // Recompute the Incomplete markers. If there are any function calls left
- // now that are complete, we must loop!
+ // Recompute the Incomplete markers
+ assert(Graph.getInlinedGlobals().empty());
Graph.maskIncompleteMarkers();
Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
- // FIXME: materialize nodes from the globals graph as neccesary...
+
+ // Delete dead nodes. Treat globals that are unreachable but that can
+ // reach live nodes as live.
Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
+ // When this graph is finalized, clone the globals in the graph into the
+ // globals graph to make sure it has everything, from all graphs.
+ DSScalarMap &MainSM = Graph.getScalarMap();
+ ReachabilityCloner RC(*GlobalsGraph, Graph, DSGraph::StripAllocaBit);
+
+ // Clone everything reachable from globals in the "main" graph into the
+ // globals graph.
+ for (DSScalarMap::global_iterator I = MainSM.global_begin(),
+ E = MainSM.global_end(); I != E; ++I)
+ RC.getClonedNH(MainSM[*I]);
+
//Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
}
-