#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");
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.
//
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
}
CallSiteIterator(std::vector<DSCallSite> &CS) : FCs(&CS) {
CallSite = 0; CallSiteEntry = 0;
- advanceToNextValid();
+ advanceToValidCallee();
}
// End iterator ctor...
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:
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
//
bool BUDataStructures::run(Module &M) {
GlobalsGraph = new DSGraph();
+ GlobalsGraph->setPrintAuxCalls();
Function *MainFunc = M.getMainFunction();
if (MainFunc)
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);
}
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;
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.
} 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();
// 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;
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_" +
// 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()
// 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");
// 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);
}
}
// 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!
// 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),
// 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))
// 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;
}