mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-25 00:24:26 +00:00
* Make some methods more const correct.
* Change the FunctionCalls and AuxFunctionCalls vectors into std::lists. This makes many operations on these lists much more natural, and avoids *exteremely* expensive copying of DSCallSites (e.g. moving nodes around between lists, erasing a node from not the end of the vector, etc). With a profile build of analyze, this speeds up BU DS from 25.14s to 12.59s on 176.gcc. I expect that it would help TD even more, but I don't have data for it. This effectively eliminates removeIdenticalCalls and children from the profile, going from 6.53 to 0.27s. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19939 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "llvm/Analysis/DataStructure/DSNode.h"
|
#include "llvm/Analysis/DataStructure/DSNode.h"
|
||||||
#include "llvm/ADT/hash_map"
|
#include "llvm/ADT/hash_map"
|
||||||
|
#include <list>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -136,19 +137,19 @@ private:
|
|||||||
//
|
//
|
||||||
ReturnNodesTy ReturnNodes;
|
ReturnNodesTy ReturnNodes;
|
||||||
|
|
||||||
// FunctionCalls - This vector maintains a single entry for each call
|
// FunctionCalls - This list maintains a single entry for each call
|
||||||
// instruction in the current graph. The first entry in the vector is the
|
// instruction in the current graph. The first entry in the vector is the
|
||||||
// scalar that holds the return value for the call, the second is the function
|
// scalar that holds the return value for the call, the second is the function
|
||||||
// scalar being invoked, and the rest are pointer arguments to the function.
|
// scalar being invoked, and the rest are pointer arguments to the function.
|
||||||
// This vector is built by the Local graph and is never modified after that.
|
// This vector is built by the Local graph and is never modified after that.
|
||||||
//
|
//
|
||||||
std::vector<DSCallSite> FunctionCalls;
|
std::list<DSCallSite> FunctionCalls;
|
||||||
|
|
||||||
// AuxFunctionCalls - This vector contains call sites that have been processed
|
// AuxFunctionCalls - This vector contains call sites that have been processed
|
||||||
// by some mechanism. In pratice, the BU Analysis uses this vector to hold
|
// by some mechanism. In pratice, the BU Analysis uses this vector to hold
|
||||||
// the _unresolved_ call sites, because it cannot modify FunctionCalls.
|
// the _unresolved_ call sites, because it cannot modify FunctionCalls.
|
||||||
//
|
//
|
||||||
std::vector<DSCallSite> AuxFunctionCalls;
|
std::list<DSCallSite> AuxFunctionCalls;
|
||||||
|
|
||||||
// InlinedGlobals - This set records which globals have been inlined from
|
// InlinedGlobals - This set records which globals have been inlined from
|
||||||
// other graphs (callers or callees, depending on the pass) into this one.
|
// other graphs (callers or callees, depending on the pass) into this one.
|
||||||
@ -222,20 +223,30 @@ public:
|
|||||||
/// getFunctionCalls - Return the list of call sites in the original local
|
/// getFunctionCalls - Return the list of call sites in the original local
|
||||||
/// graph...
|
/// graph...
|
||||||
///
|
///
|
||||||
const std::vector<DSCallSite> &getFunctionCalls() const {
|
const std::list<DSCallSite> &getFunctionCalls() const { return FunctionCalls;}
|
||||||
return FunctionCalls;
|
std::list<DSCallSite> &getFunctionCalls() { return FunctionCalls;}
|
||||||
}
|
|
||||||
|
|
||||||
/// getAuxFunctionCalls - Get the call sites as modified by whatever passes
|
/// getAuxFunctionCalls - Get the call sites as modified by whatever passes
|
||||||
/// have been run.
|
/// have been run.
|
||||||
///
|
///
|
||||||
std::vector<DSCallSite> &getAuxFunctionCalls() {
|
std::list<DSCallSite> &getAuxFunctionCalls() { return AuxFunctionCalls; }
|
||||||
return AuxFunctionCalls;
|
const std::list<DSCallSite> &getAuxFunctionCalls() const {
|
||||||
}
|
|
||||||
const std::vector<DSCallSite> &getAuxFunctionCalls() const {
|
|
||||||
return AuxFunctionCalls;
|
return AuxFunctionCalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function Call iteration
|
||||||
|
typedef std::list<DSCallSite>::const_iterator fc_iterator;
|
||||||
|
fc_iterator fc_begin() const { return FunctionCalls.begin(); }
|
||||||
|
fc_iterator fc_end() const { return FunctionCalls.end(); }
|
||||||
|
|
||||||
|
|
||||||
|
// Aux Function Call iteration
|
||||||
|
typedef std::list<DSCallSite>::const_iterator afc_iterator;
|
||||||
|
afc_iterator afc_begin() const { return AuxFunctionCalls.begin(); }
|
||||||
|
afc_iterator afc_end() const { return AuxFunctionCalls.end(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// getInlinedGlobals - Get the set of globals that are have been inlined
|
/// getInlinedGlobals - Get the set of globals that are have been inlined
|
||||||
/// (from callees in BU or from callers in TD) into the current graph.
|
/// (from callees in BU or from callers in TD) into the current graph.
|
||||||
///
|
///
|
||||||
|
@ -349,7 +349,7 @@ public:
|
|||||||
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
||||||
/// adds to the set, which allows it to only traverse visited nodes once.
|
/// adds to the set, which allows it to only traverse visited nodes once.
|
||||||
///
|
///
|
||||||
void markReachableNodes(hash_set<DSNode*> &ReachableNodes);
|
void markReachableNodes(hash_set<const DSNode*> &ReachableNodes) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DSNodeHandle;
|
friend class DSNodeHandle;
|
||||||
|
@ -289,7 +289,7 @@ public:
|
|||||||
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
||||||
/// adds to the set, which allows it to only traverse visited nodes once.
|
/// adds to the set, which allows it to only traverse visited nodes once.
|
||||||
///
|
///
|
||||||
void markReachableNodes(hash_set<DSNode*> &Nodes);
|
void markReachableNodes(hash_set<const DSNode*> &Nodes) const;
|
||||||
|
|
||||||
bool operator<(const DSCallSite &CS) const {
|
bool operator<(const DSCallSite &CS) const {
|
||||||
if (isDirectCall()) { // This must sort by callee first!
|
if (isDirectCall()) { // This must sort by callee first!
|
||||||
|
@ -247,23 +247,23 @@ void BUDataStructures::releaseMemory() {
|
|||||||
void BUDataStructures::calculateGraph(DSGraph &Graph) {
|
void BUDataStructures::calculateGraph(DSGraph &Graph) {
|
||||||
// Move our call site list into TempFCs so that inline call sites go into the
|
// Move our call site list into TempFCs so that inline call sites go into the
|
||||||
// new call site list and doesn't invalidate our iterators!
|
// new call site list and doesn't invalidate our iterators!
|
||||||
std::vector<DSCallSite> TempFCs;
|
std::list<DSCallSite> TempFCs;
|
||||||
std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
|
std::list<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
|
||||||
TempFCs.swap(AuxCallsList);
|
TempFCs.swap(AuxCallsList);
|
||||||
|
|
||||||
DSGraph::ReturnNodesTy &ReturnNodes = Graph.getReturnNodes();
|
DSGraph::ReturnNodesTy &ReturnNodes = Graph.getReturnNodes();
|
||||||
|
|
||||||
// Loop over all of the resolvable call sites
|
// Loop over all of the resolvable call sites
|
||||||
unsigned LastCallSiteIdx = ~0U;
|
DSCallSiteIterator I = DSCallSiteIterator::begin(TempFCs);
|
||||||
for (DSCallSiteIterator I = DSCallSiteIterator::begin(TempFCs),
|
DSCallSiteIterator E = DSCallSiteIterator::end(TempFCs);
|
||||||
E = DSCallSiteIterator::end(TempFCs); I != E; ++I) {
|
|
||||||
// If we skipped over any call sites, they must be unresolvable, copy them
|
// If DSCallSiteIterator skipped over any call sites, they are unresolvable:
|
||||||
// to the real call site list.
|
// move them back to the AuxCallsList.
|
||||||
LastCallSiteIdx++;
|
std::list<DSCallSite>::iterator LastCallSiteIdx = TempFCs.begin();
|
||||||
for (; LastCallSiteIdx < I.getCallSiteIdx(); ++LastCallSiteIdx)
|
while (LastCallSiteIdx != I.getCallSiteIdx())
|
||||||
AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
|
AuxCallsList.splice(AuxCallsList.end(), TempFCs, LastCallSiteIdx++);
|
||||||
LastCallSiteIdx = I.getCallSiteIdx();
|
|
||||||
|
|
||||||
|
while (I != E) {
|
||||||
// Resolve the current call...
|
// Resolve the current call...
|
||||||
Function *Callee = *I;
|
Function *Callee = *I;
|
||||||
DSCallSite CS = I.getCallSite();
|
DSCallSite CS = I.getCallSite();
|
||||||
@ -301,11 +301,23 @@ void BUDataStructures::calculateGraph(DSGraph &Graph) {
|
|||||||
Callee->getName());
|
Callee->getName());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure to catch any leftover unresolvable calls...
|
LastCallSiteIdx = I.getCallSiteIdx();
|
||||||
for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
|
++I; // Move to the next call site.
|
||||||
AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
|
|
||||||
|
if (I.getCallSiteIdx() != LastCallSiteIdx) {
|
||||||
|
++LastCallSiteIdx; // Skip over the site we already processed.
|
||||||
|
|
||||||
|
// If there are call sites that get skipped over, move them to the aux
|
||||||
|
// calls list: they are not resolvable.
|
||||||
|
if (I != E)
|
||||||
|
while (LastCallSiteIdx != I.getCallSiteIdx())
|
||||||
|
AuxCallsList.splice(AuxCallsList.end(), TempFCs, LastCallSiteIdx++);
|
||||||
|
else
|
||||||
|
while (LastCallSiteIdx != TempFCs.end())
|
||||||
|
AuxCallsList.splice(AuxCallsList.end(), TempFCs, LastCallSiteIdx++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TempFCs.clear();
|
TempFCs.clear();
|
||||||
|
|
||||||
|
@ -49,20 +49,21 @@ bool CompleteBUDataStructures::runOnModule(Module &M) {
|
|||||||
// we hack it like this:
|
// we hack it like this:
|
||||||
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
|
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
|
||||||
if (MI->isExternal()) continue;
|
if (MI->isExternal()) continue;
|
||||||
const std::vector<DSCallSite> &CSs = TD.getDSGraph(*MI).getFunctionCalls();
|
const std::list<DSCallSite> &CSs = TD.getDSGraph(*MI).getFunctionCalls();
|
||||||
|
|
||||||
for (unsigned CSi = 0, e = CSs.size(); CSi != e; ++CSi) {
|
for (std::list<DSCallSite>::const_iterator CSI = CSs.begin(), E = CSs.end();
|
||||||
Instruction *TheCall = CSs[CSi].getCallSite().getInstruction();
|
CSI != E; ++CSI) {
|
||||||
|
Instruction *TheCall = CSI->getCallSite().getInstruction();
|
||||||
|
|
||||||
if (CSs[CSi].isIndirectCall()) { // indirect call: insert all callees
|
if (CSI->isIndirectCall()) { // indirect call: insert all callees
|
||||||
const std::vector<GlobalValue*> &Callees =
|
const std::vector<GlobalValue*> &Callees =
|
||||||
CSs[CSi].getCalleeNode()->getGlobals();
|
CSI->getCalleeNode()->getGlobals();
|
||||||
for (unsigned i = 0, e = Callees.size(); i != e; ++i)
|
for (unsigned i = 0, e = Callees.size(); i != e; ++i)
|
||||||
if (Function *F = dyn_cast<Function>(Callees[i]))
|
if (Function *F = dyn_cast<Function>(Callees[i]))
|
||||||
ActualCallees.insert(std::make_pair(TheCall, F));
|
ActualCallees.insert(std::make_pair(TheCall, F));
|
||||||
} else { // direct call: insert the single callee directly
|
} else { // direct call: insert the single callee directly
|
||||||
ActualCallees.insert(std::make_pair(TheCall,
|
ActualCallees.insert(std::make_pair(TheCall,
|
||||||
CSs[CSi].getCalleeFunc()));
|
CSI->getCalleeFunc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,8 +122,8 @@ unsigned CompleteBUDataStructures::calculateSCCGraphs(DSGraph &FG,
|
|||||||
Stack.push_back(&FG);
|
Stack.push_back(&FG);
|
||||||
|
|
||||||
// The edges out of the current node are the call site targets...
|
// The edges out of the current node are the call site targets...
|
||||||
for (unsigned i = 0, e = FG.getFunctionCalls().size(); i != e; ++i) {
|
for (DSGraph::fc_iterator CI = FG.fc_begin(), E = FG.fc_end(); CI != E; ++CI){
|
||||||
Instruction *Call = FG.getFunctionCalls()[i].getCallSite().getInstruction();
|
Instruction *Call = CI->getCallSite().getInstruction();
|
||||||
|
|
||||||
// Loop over all of the actually called functions...
|
// Loop over all of the actually called functions...
|
||||||
ActualCalleesTy::iterator I, E;
|
ActualCalleesTy::iterator I, E;
|
||||||
@ -183,8 +184,10 @@ void CompleteBUDataStructures::processGraph(DSGraph &G) {
|
|||||||
hash_set<Instruction*> calls;
|
hash_set<Instruction*> calls;
|
||||||
|
|
||||||
// The edges out of the current node are the call site targets...
|
// The edges out of the current node are the call site targets...
|
||||||
for (unsigned i = 0, e = G.getFunctionCalls().size(); i != e; ++i) {
|
unsigned i = 0;
|
||||||
const DSCallSite &CS = G.getFunctionCalls()[i];
|
for (DSGraph::fc_iterator CI = G.fc_begin(), E = G.fc_end(); CI != E;
|
||||||
|
++CI, ++i) {
|
||||||
|
const DSCallSite &CS = *CI;
|
||||||
Instruction *TheCall = CS.getCallSite().getInstruction();
|
Instruction *TheCall = CS.getCallSite().getInstruction();
|
||||||
|
|
||||||
assert(calls.insert(TheCall).second &&
|
assert(calls.insert(TheCall).second &&
|
||||||
@ -208,7 +211,8 @@ void CompleteBUDataStructures::processGraph(DSGraph &G) {
|
|||||||
G.mergeInGraph(CS, *CalleeFunc, GI, DSGraph::KeepModRefBits |
|
G.mergeInGraph(CS, *CalleeFunc, GI, DSGraph::KeepModRefBits |
|
||||||
DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes |
|
DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes |
|
||||||
DSGraph::DontCloneAuxCallNodes);
|
DSGraph::DontCloneAuxCallNodes);
|
||||||
DEBUG(std::cerr << " Inlining graph [" << i << "/" << e-1
|
DEBUG(std::cerr << " Inlining graph [" << i << "/"
|
||||||
|
<< G.getFunctionCalls().size()-1
|
||||||
<< ":" << TNum << "/" << Num-1 << "] for "
|
<< ":" << TNum << "/" << Num-1 << "] for "
|
||||||
<< CalleeFunc->getName() << "["
|
<< CalleeFunc->getName() << "["
|
||||||
<< GI.getGraphSize() << "+" << GI.getAuxFunctionCalls().size()
|
<< GI.getGraphSize() << "+" << GI.getAuxFunctionCalls().size()
|
||||||
|
@ -23,18 +23,18 @@ namespace llvm {
|
|||||||
|
|
||||||
struct DSCallSiteIterator {
|
struct DSCallSiteIterator {
|
||||||
// FCs are the edges out of the current node are the call site targets...
|
// FCs are the edges out of the current node are the call site targets...
|
||||||
const std::vector<DSCallSite> *FCs;
|
std::list<DSCallSite> *FCs;
|
||||||
unsigned CallSite;
|
std::list<DSCallSite>::iterator CallSite;
|
||||||
unsigned CallSiteEntry;
|
unsigned CallSiteEntry;
|
||||||
|
|
||||||
DSCallSiteIterator(const std::vector<DSCallSite> &CS) : FCs(&CS) {
|
DSCallSiteIterator(std::list<DSCallSite> &CS) : FCs(&CS) {
|
||||||
CallSite = 0; CallSiteEntry = 0;
|
CallSite = CS.begin(); CallSiteEntry = 0;
|
||||||
advanceToValidCallee();
|
advanceToValidCallee();
|
||||||
}
|
}
|
||||||
|
|
||||||
// End iterator ctor...
|
// End iterator ctor.
|
||||||
DSCallSiteIterator(const std::vector<DSCallSite> &CS, bool) : FCs(&CS) {
|
DSCallSiteIterator(std::list<DSCallSite> &CS, bool) : FCs(&CS) {
|
||||||
CallSite = FCs->size(); CallSiteEntry = 0;
|
CallSite = CS.end(); CallSiteEntry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isVAHackFn(const Function *F) {
|
static bool isVAHackFn(const Function *F) {
|
||||||
@ -52,13 +52,13 @@ struct DSCallSiteIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void advanceToValidCallee() {
|
void advanceToValidCallee() {
|
||||||
while (CallSite < FCs->size()) {
|
while (CallSite != FCs->end()) {
|
||||||
if ((*FCs)[CallSite].isDirectCall()) {
|
if (CallSite->isDirectCall()) {
|
||||||
if (CallSiteEntry == 0 && // direct call only has one target...
|
if (CallSiteEntry == 0 && // direct call only has one target...
|
||||||
! isUnresolvableFunc((*FCs)[CallSite].getCalleeFunc()))
|
! isUnresolvableFunc(CallSite->getCalleeFunc()))
|
||||||
return; // and not an unresolvable external func
|
return; // and not an unresolvable external func
|
||||||
} else {
|
} else {
|
||||||
DSNode *CalleeNode = (*FCs)[CallSite].getCalleeNode();
|
DSNode *CalleeNode = CallSite->getCalleeNode();
|
||||||
if (CallSiteEntry || isCompleteNode(CalleeNode)) {
|
if (CallSiteEntry || isCompleteNode(CalleeNode)) {
|
||||||
const std::vector<GlobalValue*> &Callees = CalleeNode->getGlobals();
|
const std::vector<GlobalValue*> &Callees = CalleeNode->getGlobals();
|
||||||
while (CallSiteEntry < Callees.size()) {
|
while (CallSiteEntry < Callees.size()) {
|
||||||
@ -98,8 +98,8 @@ public:
|
|||||||
static DSCallSiteIterator end_std(DSGraph &G) {
|
static DSCallSiteIterator end_std(DSGraph &G) {
|
||||||
return DSCallSiteIterator(G.getFunctionCalls(), true);
|
return DSCallSiteIterator(G.getFunctionCalls(), true);
|
||||||
}
|
}
|
||||||
static DSCallSiteIterator begin(std::vector<DSCallSite> &CSs) { return CSs; }
|
static DSCallSiteIterator begin(std::list<DSCallSite> &CSs) { return CSs; }
|
||||||
static DSCallSiteIterator end(std::vector<DSCallSite> &CSs) {
|
static DSCallSiteIterator end(std::list<DSCallSite> &CSs) {
|
||||||
return DSCallSiteIterator(CSs, true);
|
return DSCallSiteIterator(CSs, true);
|
||||||
}
|
}
|
||||||
bool operator==(const DSCallSiteIterator &CSI) const {
|
bool operator==(const DSCallSiteIterator &CSI) const {
|
||||||
@ -109,14 +109,14 @@ public:
|
|||||||
return !operator==(CSI);
|
return !operator==(CSI);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getCallSiteIdx() const { return CallSite; }
|
std::list<DSCallSite>::iterator getCallSiteIdx() const { return CallSite; }
|
||||||
const DSCallSite &getCallSite() const { return (*FCs)[CallSite]; }
|
const DSCallSite &getCallSite() const { return *CallSite; }
|
||||||
|
|
||||||
Function *operator*() const {
|
Function *operator*() const {
|
||||||
if ((*FCs)[CallSite].isDirectCall()) {
|
if (CallSite->isDirectCall()) {
|
||||||
return (*FCs)[CallSite].getCalleeFunc();
|
return CallSite->getCalleeFunc();
|
||||||
} else {
|
} else {
|
||||||
DSNode *Node = (*FCs)[CallSite].getCalleeNode();
|
DSNode *Node = CallSite->getCalleeNode();
|
||||||
return cast<Function>(Node->getGlobals()[CallSiteEntry]);
|
return cast<Function>(Node->getGlobals()[CallSiteEntry]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1201,19 +1201,15 @@ void DSGraph::cloneInto(const DSGraph &G, DSScalarMap &OldValMap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(CloneFlags & DontCloneCallNodes)) {
|
if (!(CloneFlags & DontCloneCallNodes)) {
|
||||||
// Copy the function calls list...
|
// Copy the function calls list.
|
||||||
unsigned FC = FunctionCalls.size(); // FirstCall
|
for (fc_iterator I = G.fc_begin(), E = G.fc_end(); I != E; ++I)
|
||||||
FunctionCalls.reserve(FC+G.FunctionCalls.size());
|
FunctionCalls.push_back(DSCallSite(*I, OldNodeMap));
|
||||||
for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i)
|
|
||||||
FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
||||||
// Copy the auxiliary function calls list...
|
// Copy the auxiliary function calls list.
|
||||||
unsigned FC = AuxFunctionCalls.size(); // FirstCall
|
for (afc_iterator I = G.afc_begin(), E = G.afc_end(); I != E; ++I)
|
||||||
AuxFunctionCalls.reserve(FC+G.AuxFunctionCalls.size());
|
AuxFunctionCalls.push_back(DSCallSite(*I, OldNodeMap));
|
||||||
for (unsigned i = 0, ei = G.AuxFunctionCalls.size(); i != ei; ++i)
|
|
||||||
AuxFunctionCalls.push_back(DSCallSite(G.AuxFunctionCalls[i], OldNodeMap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the return node pointers over...
|
// Map the return node pointers over...
|
||||||
@ -1289,20 +1285,14 @@ void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F,
|
|||||||
|
|
||||||
// If requested, copy all of the calls.
|
// If requested, copy all of the calls.
|
||||||
if (!(CloneFlags & DontCloneCallNodes)) {
|
if (!(CloneFlags & DontCloneCallNodes)) {
|
||||||
// Copy the function calls list...
|
// Copy the function calls list.
|
||||||
FunctionCalls.reserve(FunctionCalls.size()+Graph.FunctionCalls.size());
|
for (fc_iterator I = Graph.fc_begin(), E = Graph.fc_end(); I != E; ++I)
|
||||||
for (unsigned i = 0, ei = Graph.FunctionCalls.size(); i != ei; ++i)
|
FunctionCalls.push_back(DSCallSite(*I, RC));
|
||||||
FunctionCalls.push_back(DSCallSite(Graph.FunctionCalls[i], RC));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user has us copying aux calls (the normal case), set up a data
|
// If the user has us copying aux calls (the normal case), set up a data
|
||||||
// structure to keep track of which ones we've copied over.
|
// structure to keep track of which ones we've copied over.
|
||||||
std::vector<bool> CopiedAuxCall;
|
std::set<const DSCallSite*> CopiedAuxCall;
|
||||||
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
|
||||||
AuxFunctionCalls.reserve(AuxFunctionCalls.size()+
|
|
||||||
Graph.AuxFunctionCalls.size());
|
|
||||||
CopiedAuxCall.resize(Graph.AuxFunctionCalls.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone over all globals that appear in the caller and callee graphs.
|
// Clone over all globals that appear in the caller and callee graphs.
|
||||||
hash_set<GlobalVariable*> NonCopiedGlobals;
|
hash_set<GlobalVariable*> NonCopiedGlobals;
|
||||||
@ -1341,17 +1331,15 @@ void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F,
|
|||||||
|
|
||||||
// If requested, copy any aux calls that can reach copied nodes.
|
// If requested, copy any aux calls that can reach copied nodes.
|
||||||
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
||||||
for (unsigned i = 0, ei = Graph.AuxFunctionCalls.size(); i != ei; ++i)
|
for (afc_iterator I = Graph.afc_begin(), E = Graph.afc_end(); I!=E; ++I)
|
||||||
if (!CopiedAuxCall[i] &&
|
if (CopiedAuxCall.insert(&*I).second &&
|
||||||
PathExistsToClonedNode(Graph.AuxFunctionCalls[i], RC)) {
|
PathExistsToClonedNode(*I, RC)) {
|
||||||
AuxFunctionCalls.push_back(DSCallSite(Graph.AuxFunctionCalls[i],
|
AuxFunctionCalls.push_back(DSCallSite(*I, RC));
|
||||||
RC));
|
|
||||||
CopiedAuxCall[i] = true;
|
|
||||||
MadeChange = true;
|
MadeChange = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DSNodeHandle RetVal = getReturnNodeFor(F);
|
DSNodeHandle RetVal = getReturnNodeFor(F);
|
||||||
|
|
||||||
@ -1458,7 +1446,7 @@ static void markIncomplete(DSCallSite &Call) {
|
|||||||
// added to the NodeType.
|
// added to the NodeType.
|
||||||
//
|
//
|
||||||
void DSGraph::markIncompleteNodes(unsigned Flags) {
|
void DSGraph::markIncompleteNodes(unsigned Flags) {
|
||||||
// Mark any incoming arguments as incomplete...
|
// Mark any incoming arguments as incomplete.
|
||||||
if (Flags & DSGraph::MarkFormalArgs)
|
if (Flags & DSGraph::MarkFormalArgs)
|
||||||
for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end();
|
for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end();
|
||||||
FI != E; ++FI) {
|
FI != E; ++FI) {
|
||||||
@ -1469,14 +1457,15 @@ void DSGraph::markIncompleteNodes(unsigned Flags) {
|
|||||||
markIncompleteNode(getNodeForValue(I).getNode());
|
markIncompleteNode(getNodeForValue(I).getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark stuff passed into functions calls as being incomplete...
|
// Mark stuff passed into functions calls as being incomplete.
|
||||||
if (!shouldPrintAuxCalls())
|
if (!shouldPrintAuxCalls())
|
||||||
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
for (std::list<DSCallSite>::iterator I = FunctionCalls.begin(),
|
||||||
markIncomplete(FunctionCalls[i]);
|
E = FunctionCalls.end(); I != E; ++I)
|
||||||
|
markIncomplete(*I);
|
||||||
else
|
else
|
||||||
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
for (std::list<DSCallSite>::iterator I = AuxFunctionCalls.begin(),
|
||||||
markIncomplete(AuxFunctionCalls[i]);
|
E = AuxFunctionCalls.end(); I != E; ++I)
|
||||||
|
markIncomplete(*I);
|
||||||
|
|
||||||
// Mark all global nodes as incomplete...
|
// Mark all global nodes as incomplete...
|
||||||
if ((Flags & DSGraph::IgnoreGlobals) == 0)
|
if ((Flags & DSGraph::IgnoreGlobals) == 0)
|
||||||
@ -1504,22 +1493,21 @@ static inline bool nodeContainsExternalFunction(const DSNode *N) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) {
|
static void removeIdenticalCalls(std::list<DSCallSite> &Calls) {
|
||||||
// Remove trivially identical function calls
|
// Remove trivially identical function calls
|
||||||
unsigned NumFns = Calls.size();
|
Calls.sort(); // Sort by callee as primary key!
|
||||||
std::sort(Calls.begin(), Calls.end()); // Sort by callee as primary key!
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// Scan the call list cleaning it up as necessary...
|
// Scan the call list cleaning it up as necessary...
|
||||||
DSNode *LastCalleeNode = 0;
|
DSNode *LastCalleeNode = 0;
|
||||||
Function *LastCalleeFunc = 0;
|
Function *LastCalleeFunc = 0;
|
||||||
unsigned NumDuplicateCalls = 0;
|
unsigned NumDuplicateCalls = 0;
|
||||||
bool LastCalleeContainsExternalFunction = false;
|
bool LastCalleeContainsExternalFunction = false;
|
||||||
|
|
||||||
std::vector<unsigned> CallsToDelete;
|
unsigned NumDeleted = 0;
|
||||||
|
for (std::list<DSCallSite>::iterator I = Calls.begin(), E = Calls.end();
|
||||||
for (unsigned i = 0; i != Calls.size(); ++i) {
|
I != E;) {
|
||||||
DSCallSite &CS = Calls[i];
|
DSCallSite &CS = *I;
|
||||||
|
std::list<DSCallSite>::iterator OldIt = I++;
|
||||||
|
|
||||||
// If the Callee is a useless edge, this must be an unreachable call site,
|
// If the Callee is a useless edge, this must be an unreachable call site,
|
||||||
// eliminate it.
|
// eliminate it.
|
||||||
@ -1529,78 +1517,106 @@ static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) {
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cerr << "WARNING: Useless call site found.\n";
|
std::cerr << "WARNING: Useless call site found.\n";
|
||||||
#endif
|
#endif
|
||||||
CallsToDelete.push_back(i);
|
Calls.erase(OldIt);
|
||||||
} else {
|
++NumDeleted;
|
||||||
// If the return value or any arguments point to a void node with no
|
continue;
|
||||||
// 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).
|
|
||||||
//
|
// If the return value or any arguments point to a void node with no
|
||||||
killIfUselessEdge(CS.getRetVal());
|
// information at all in it, and the call node is the only node to point
|
||||||
for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
|
// to it, remove the edge to the node (killing the node).
|
||||||
killIfUselessEdge(CS.getPtrArg(a));
|
//
|
||||||
|
killIfUselessEdge(CS.getRetVal());
|
||||||
// If this call site calls the same function as the last call site, and if
|
for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
|
||||||
// the function pointer contains an external function, this node will
|
killIfUselessEdge(CS.getPtrArg(a));
|
||||||
// never be resolved. Merge the arguments of the call node because no
|
|
||||||
// information will be lost.
|
|
||||||
//
|
|
||||||
if ((CS.isDirectCall() && CS.getCalleeFunc() == LastCalleeFunc) ||
|
|
||||||
(CS.isIndirectCall() && CS.getCalleeNode() == LastCalleeNode)) {
|
|
||||||
++NumDuplicateCalls;
|
|
||||||
if (NumDuplicateCalls == 1) {
|
|
||||||
if (LastCalleeNode)
|
|
||||||
LastCalleeContainsExternalFunction =
|
|
||||||
nodeContainsExternalFunction(LastCalleeNode);
|
|
||||||
else
|
|
||||||
LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is not clear why, but enabling this code makes DSA really
|
|
||||||
// sensitive to node forwarding. Basically, with this enabled, DSA
|
|
||||||
// performs different number of inlinings based on which nodes are
|
|
||||||
// forwarding or not. This is clearly a problem, so this code is
|
|
||||||
// disabled until this can be resolved.
|
|
||||||
#if 1
|
|
||||||
if (LastCalleeContainsExternalFunction
|
|
||||||
#if 0
|
#if 0
|
||||||
||
|
// If this call site calls the same function as the last call site, and if
|
||||||
// This should be more than enough context sensitivity!
|
// the function pointer contains an external function, this node will
|
||||||
// FIXME: Evaluate how many times this is tripped!
|
// never be resolved. Merge the arguments of the call node because no
|
||||||
NumDuplicateCalls > 20
|
// information will be lost.
|
||||||
#endif
|
//
|
||||||
) {
|
if ((CS.isDirectCall() && CS.getCalleeFunc() == LastCalleeFunc) ||
|
||||||
DSCallSite &OCS = Calls[i-1];
|
(CS.isIndirectCall() && CS.getCalleeNode() == LastCalleeNode)) {
|
||||||
OCS.mergeWith(CS);
|
++NumDuplicateCalls;
|
||||||
|
if (NumDuplicateCalls == 1) {
|
||||||
// No need to keep this call anymore.
|
if (LastCalleeNode)
|
||||||
CallsToDelete.push_back(i);
|
LastCalleeContainsExternalFunction =
|
||||||
}
|
nodeContainsExternalFunction(LastCalleeNode);
|
||||||
#endif
|
else
|
||||||
} else {
|
LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal();
|
||||||
if (CS.isDirectCall()) {
|
|
||||||
LastCalleeFunc = CS.getCalleeFunc();
|
|
||||||
LastCalleeNode = 0;
|
|
||||||
} else {
|
|
||||||
LastCalleeNode = CS.getCalleeNode();
|
|
||||||
LastCalleeFunc = 0;
|
|
||||||
}
|
|
||||||
NumDuplicateCalls = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It is not clear why, but enabling this code makes DSA really
|
||||||
|
// sensitive to node forwarding. Basically, with this enabled, DSA
|
||||||
|
// performs different number of inlinings based on which nodes are
|
||||||
|
// forwarding or not. This is clearly a problem, so this code is
|
||||||
|
// disabled until this can be resolved.
|
||||||
|
#if 1
|
||||||
|
if (LastCalleeContainsExternalFunction
|
||||||
|
#if 0
|
||||||
|
||
|
||||||
|
// This should be more than enough context sensitivity!
|
||||||
|
// FIXME: Evaluate how many times this is tripped!
|
||||||
|
NumDuplicateCalls > 20
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
|
||||||
|
std::list<DSCallSite>::iterator PrevIt = OldIt;
|
||||||
|
--PrevIt;
|
||||||
|
PrevIt->mergeWith(CS);
|
||||||
|
|
||||||
|
// No need to keep this call anymore.
|
||||||
|
Calls.erase(OldIt);
|
||||||
|
++NumDeleted;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
if (CS.isDirectCall()) {
|
||||||
|
LastCalleeFunc = CS.getCalleeFunc();
|
||||||
|
LastCalleeNode = 0;
|
||||||
|
} else {
|
||||||
|
LastCalleeNode = CS.getCalleeNode();
|
||||||
|
LastCalleeFunc = 0;
|
||||||
|
}
|
||||||
|
NumDuplicateCalls = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (I != Calls.end() && CS == *I) {
|
||||||
|
Calls.erase(OldIt);
|
||||||
|
++NumDeleted;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned NumDeleted = 0;
|
// Resort now that we simplified things.
|
||||||
for (unsigned i = 0, e = CallsToDelete.size(); i != e; ++i)
|
Calls.sort();
|
||||||
Calls.erase(Calls.begin()+CallsToDelete[i]-NumDeleted++);
|
|
||||||
|
|
||||||
Calls.erase(std::unique(Calls.begin(), Calls.end()), Calls.end());
|
// Now that we are in sorted order, eliminate duplicates.
|
||||||
|
std::list<DSCallSite>::iterator I = Calls.begin(), E = Calls.end();
|
||||||
|
if (I != E)
|
||||||
|
while (1) {
|
||||||
|
std::list<DSCallSite>::iterator OldIt = I++;
|
||||||
|
if (I == E) break;
|
||||||
|
|
||||||
|
// If this call site is now the same as the previous one, we can delete it
|
||||||
|
// as a duplicate.
|
||||||
|
if (*OldIt == *I) {
|
||||||
|
Calls.erase(I);
|
||||||
|
I = OldIt;
|
||||||
|
++NumDeleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calls.erase(std::unique(Calls.begin(), Calls.end()), Calls.end());
|
||||||
|
|
||||||
// Track the number of call nodes merged away...
|
// Track the number of call nodes merged away...
|
||||||
NumCallNodesMerged += NumFns-Calls.size();
|
NumCallNodesMerged += NumDeleted;
|
||||||
|
|
||||||
DEBUG(if (NumFns != Calls.size())
|
DEBUG(if (NumDeleted)
|
||||||
std::cerr << "Merged " << (NumFns-Calls.size()) << " call nodes.\n";);
|
std::cerr << "Merged " << NumDeleted << " call nodes.\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1698,7 +1714,7 @@ void DSGraph::removeTriviallyDeadNodes() {
|
|||||||
/// DSNodes, marking any nodes which are reachable. All reachable nodes it adds
|
/// DSNodes, marking any nodes which are reachable. All reachable nodes it adds
|
||||||
/// to the set, which allows it to only traverse visited nodes once.
|
/// to the set, which allows it to only traverse visited nodes once.
|
||||||
///
|
///
|
||||||
void DSNode::markReachableNodes(hash_set<DSNode*> &ReachableNodes) {
|
void DSNode::markReachableNodes(hash_set<const DSNode*> &ReachableNodes) const {
|
||||||
if (this == 0) return;
|
if (this == 0) return;
|
||||||
assert(getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
assert(getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
||||||
if (ReachableNodes.insert(this).second) // Is newly reachable?
|
if (ReachableNodes.insert(this).second) // Is newly reachable?
|
||||||
@ -1706,7 +1722,7 @@ void DSNode::markReachableNodes(hash_set<DSNode*> &ReachableNodes) {
|
|||||||
getLink(i).getNode()->markReachableNodes(ReachableNodes);
|
getLink(i).getNode()->markReachableNodes(ReachableNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSCallSite::markReachableNodes(hash_set<DSNode*> &Nodes) {
|
void DSCallSite::markReachableNodes(hash_set<const DSNode*> &Nodes) const {
|
||||||
getRetVal().getNode()->markReachableNodes(Nodes);
|
getRetVal().getNode()->markReachableNodes(Nodes);
|
||||||
if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes);
|
if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes);
|
||||||
|
|
||||||
@ -1719,8 +1735,8 @@ void DSCallSite::markReachableNodes(hash_set<DSNode*> &Nodes) {
|
|||||||
// true, otherwise return false. If an alive node is reachable, this node is
|
// true, otherwise return false. If an alive node is reachable, this node is
|
||||||
// marked as alive...
|
// marked as alive...
|
||||||
//
|
//
|
||||||
static bool CanReachAliveNodes(DSNode *N, hash_set<DSNode*> &Alive,
|
static bool CanReachAliveNodes(DSNode *N, hash_set<const DSNode*> &Alive,
|
||||||
hash_set<DSNode*> &Visited,
|
hash_set<const DSNode*> &Visited,
|
||||||
bool IgnoreGlobals) {
|
bool IgnoreGlobals) {
|
||||||
if (N == 0) return false;
|
if (N == 0) return false;
|
||||||
assert(N->getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
assert(N->getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
||||||
@ -1749,8 +1765,9 @@ static bool CanReachAliveNodes(DSNode *N, hash_set<DSNode*> &Alive,
|
|||||||
// CallSiteUsesAliveArgs - Return true if the specified call site can reach any
|
// CallSiteUsesAliveArgs - Return true if the specified call site can reach any
|
||||||
// alive nodes.
|
// alive nodes.
|
||||||
//
|
//
|
||||||
static bool CallSiteUsesAliveArgs(DSCallSite &CS, hash_set<DSNode*> &Alive,
|
static bool CallSiteUsesAliveArgs(const DSCallSite &CS,
|
||||||
hash_set<DSNode*> &Visited,
|
hash_set<const DSNode*> &Alive,
|
||||||
|
hash_set<const DSNode*> &Visited,
|
||||||
bool IgnoreGlobals) {
|
bool IgnoreGlobals) {
|
||||||
if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited,
|
if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited,
|
||||||
IgnoreGlobals))
|
IgnoreGlobals))
|
||||||
@ -1783,7 +1800,7 @@ void DSGraph::removeDeadNodes(unsigned Flags) {
|
|||||||
// FIXME: Merge non-trivially identical call nodes...
|
// FIXME: Merge non-trivially identical call nodes...
|
||||||
|
|
||||||
// Alive - a set that holds all nodes found to be reachable/alive.
|
// Alive - a set that holds all nodes found to be reachable/alive.
|
||||||
hash_set<DSNode*> Alive;
|
hash_set<const DSNode*> Alive;
|
||||||
std::vector<std::pair<Value*, DSNode*> > GlobalNodes;
|
std::vector<std::pair<Value*, DSNode*> > GlobalNodes;
|
||||||
|
|
||||||
// Copy and merge all information about globals to the GlobalsGraph if this is
|
// Copy and merge all information about globals to the GlobalsGraph if this is
|
||||||
@ -1843,16 +1860,16 @@ void DSGraph::removeDeadNodes(unsigned Flags) {
|
|||||||
I->second.getNode()->markReachableNodes(Alive);
|
I->second.getNode()->markReachableNodes(Alive);
|
||||||
|
|
||||||
// Mark any nodes reachable by primary calls as alive...
|
// Mark any nodes reachable by primary calls as alive...
|
||||||
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
for (fc_iterator I = fc_begin(), E = fc_end(); I != E; ++I)
|
||||||
FunctionCalls[i].markReachableNodes(Alive);
|
I->markReachableNodes(Alive);
|
||||||
|
|
||||||
|
|
||||||
// Now find globals and aux call nodes that are already live or reach a live
|
// Now find globals and aux call nodes that are already live or reach a live
|
||||||
// value (which makes them live in turn), and continue till no more are found.
|
// value (which makes them live in turn), and continue till no more are found.
|
||||||
//
|
//
|
||||||
bool Iterate;
|
bool Iterate;
|
||||||
hash_set<DSNode*> Visited;
|
hash_set<const DSNode*> Visited;
|
||||||
std::vector<unsigned char> AuxFCallsAlive(AuxFunctionCalls.size());
|
hash_set<const DSCallSite*> AuxFCallsAlive;
|
||||||
do {
|
do {
|
||||||
Visited.clear();
|
Visited.clear();
|
||||||
// If any global node points to a non-global that is "alive", the global is
|
// If any global node points to a non-global that is "alive", the global is
|
||||||
@ -1873,36 +1890,32 @@ void DSGraph::removeDeadNodes(unsigned Flags) {
|
|||||||
// call nodes that get resolved will be difficult to remove from that graph.
|
// call nodes that get resolved will be difficult to remove from that graph.
|
||||||
// The final unresolved call nodes must be handled specially at the end of
|
// The final unresolved call nodes must be handled specially at the end of
|
||||||
// the BU pass (i.e., in main or other roots of the call graph).
|
// the BU pass (i.e., in main or other roots of the call graph).
|
||||||
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
for (afc_iterator CI = afc_begin(), E = afc_end(); CI != E; ++CI)
|
||||||
if (!AuxFCallsAlive[i] &&
|
if (AuxFCallsAlive.insert(&*CI).second &&
|
||||||
(AuxFunctionCalls[i].isIndirectCall()
|
(CI->isIndirectCall()
|
||||||
|| CallSiteUsesAliveArgs(AuxFunctionCalls[i], Alive, Visited,
|
|| CallSiteUsesAliveArgs(*CI, Alive, Visited,
|
||||||
Flags & DSGraph::RemoveUnreachableGlobals))) {
|
Flags & DSGraph::RemoveUnreachableGlobals))) {
|
||||||
AuxFunctionCalls[i].markReachableNodes(Alive);
|
CI->markReachableNodes(Alive);
|
||||||
AuxFCallsAlive[i] = true;
|
|
||||||
Iterate = true;
|
Iterate = true;
|
||||||
}
|
}
|
||||||
} while (Iterate);
|
} while (Iterate);
|
||||||
|
|
||||||
// Move dead aux function calls to the end of the list
|
// Move dead aux function calls to the end of the list
|
||||||
unsigned CurIdx = 0;
|
unsigned CurIdx = 0;
|
||||||
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
for (std::list<DSCallSite>::iterator CI = AuxFunctionCalls.begin(),
|
||||||
if (AuxFCallsAlive[i])
|
E = AuxFunctionCalls.end(); CI != E; )
|
||||||
AuxFunctionCalls[CurIdx++].swap(AuxFunctionCalls[i]);
|
if (AuxFCallsAlive.count(&*CI))
|
||||||
|
++CI;
|
||||||
|
else {
|
||||||
|
// Copy and merge global nodes and dead aux call nodes into the
|
||||||
|
// GlobalsGraph, and all nodes reachable from those nodes. Update their
|
||||||
|
// target pointers using the GGCloner.
|
||||||
|
//
|
||||||
|
if (!(Flags & DSGraph::RemoveUnreachableGlobals))
|
||||||
|
GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(*CI, GGCloner));
|
||||||
|
|
||||||
// Copy and merge all global nodes and dead aux call nodes into the
|
AuxFunctionCalls.erase(CI++);
|
||||||
// GlobalsGraph, and all nodes reachable from those nodes
|
}
|
||||||
//
|
|
||||||
if (!(Flags & DSGraph::RemoveUnreachableGlobals)) {
|
|
||||||
// Copy the unreachable call nodes to the globals graph, updating their
|
|
||||||
// target pointers using the GGCloner
|
|
||||||
for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
||||||
GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(AuxFunctionCalls[i],
|
|
||||||
GGCloner));
|
|
||||||
}
|
|
||||||
// Crop all the useless ones out...
|
|
||||||
AuxFunctionCalls.erase(AuxFunctionCalls.begin()+CurIdx,
|
|
||||||
AuxFunctionCalls.end());
|
|
||||||
|
|
||||||
// We are finally done with the GGCloner so we can destroy it.
|
// We are finally done with the GGCloner so we can destroy it.
|
||||||
GGCloner.destroy();
|
GGCloner.destroy();
|
||||||
@ -1962,12 +1975,12 @@ void DSGraph::AssertCallSiteInGraph(const DSCallSite &CS) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DSGraph::AssertCallNodesInGraph() const {
|
void DSGraph::AssertCallNodesInGraph() const {
|
||||||
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
for (fc_iterator I = fc_begin(), E = fc_end(); I != E; ++I)
|
||||||
AssertCallSiteInGraph(FunctionCalls[i]);
|
AssertCallSiteInGraph(*I);
|
||||||
}
|
}
|
||||||
void DSGraph::AssertAuxCallNodesInGraph() const {
|
void DSGraph::AssertAuxCallNodesInGraph() const {
|
||||||
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
for (afc_iterator I = afc_begin(), E = afc_end(); I != E; ++I)
|
||||||
AssertCallSiteInGraph(AuxFunctionCalls[i]);
|
AssertCallSiteInGraph(*I);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSGraph::AssertGraphOK() const {
|
void DSGraph::AssertGraphOK() const {
|
||||||
|
@ -75,19 +75,19 @@ static bool isIndirectCallee(Value *V) {
|
|||||||
void DSGraphStats::countCallees(const Function& F) {
|
void DSGraphStats::countCallees(const Function& F) {
|
||||||
unsigned numIndirectCalls = 0, totalNumCallees = 0;
|
unsigned numIndirectCalls = 0, totalNumCallees = 0;
|
||||||
|
|
||||||
const std::vector<DSCallSite> &callSites = TDGraph->getFunctionCalls();
|
for (DSGraph::fc_iterator I = TDGraph->fc_begin(), E = TDGraph->fc_end();
|
||||||
for (unsigned i = 0, N = callSites.size(); i != N; ++i)
|
I != E; ++I)
|
||||||
if (isIndirectCallee(callSites[i].getCallSite().getCalledValue())) {
|
if (isIndirectCallee(I->getCallSite().getCalledValue())) {
|
||||||
// This is an indirect function call
|
// This is an indirect function call
|
||||||
const std::vector<GlobalValue*> &Callees =
|
const std::vector<GlobalValue*> &Callees =
|
||||||
callSites[i].getCalleeNode()->getGlobals();
|
I->getCalleeNode()->getGlobals();
|
||||||
if (Callees.size() > 0) {
|
if (Callees.size() > 0) {
|
||||||
totalNumCallees += Callees.size();
|
totalNumCallees += Callees.size();
|
||||||
++numIndirectCalls;
|
++numIndirectCalls;
|
||||||
} else
|
} else
|
||||||
std::cerr << "WARNING: No callee in Function '" << F.getName()
|
std::cerr << "WARNING: No callee in Function '" << F.getName()
|
||||||
<< "' at call: \n"
|
<< "' at call: \n"
|
||||||
<< *callSites[i].getCallSite().getInstruction();
|
<< *I->getCallSite().getInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalNumCallees += totalNumCallees;
|
TotalNumCallees += totalNumCallees;
|
||||||
|
@ -73,11 +73,11 @@ namespace {
|
|||||||
DSGraph &G;
|
DSGraph &G;
|
||||||
DSNodeHandle *RetNode; // Node that gets returned...
|
DSNodeHandle *RetNode; // Node that gets returned...
|
||||||
DSScalarMap &ScalarMap;
|
DSScalarMap &ScalarMap;
|
||||||
std::vector<DSCallSite> *FunctionCalls;
|
std::list<DSCallSite> *FunctionCalls;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GraphBuilder(Function &f, DSGraph &g, DSNodeHandle &retNode,
|
GraphBuilder(Function &f, DSGraph &g, DSNodeHandle &retNode,
|
||||||
std::vector<DSCallSite> &fc)
|
std::list<DSCallSite> &fc)
|
||||||
: G(g), RetNode(&retNode), ScalarMap(G.getScalarMap()),
|
: G(g), RetNode(&retNode), ScalarMap(G.getScalarMap()),
|
||||||
FunctionCalls(&fc) {
|
FunctionCalls(&fc) {
|
||||||
|
|
||||||
|
@ -174,11 +174,12 @@ struct DOTGraphTraits<const DSGraph*> : public DefaultDOTGraphTraits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Output all of the call nodes...
|
// Output all of the call nodes...
|
||||||
const std::vector<DSCallSite> &FCs =
|
const std::list<DSCallSite> &FCs =
|
||||||
G->shouldPrintAuxCalls() ? G->getAuxFunctionCalls()
|
G->shouldPrintAuxCalls() ? G->getAuxFunctionCalls()
|
||||||
: G->getFunctionCalls();
|
: G->getFunctionCalls();
|
||||||
for (unsigned i = 0, e = FCs.size(); i != e; ++i) {
|
for (std::list<DSCallSite>::const_iterator I = FCs.begin(), E = FCs.end();
|
||||||
const DSCallSite &Call = FCs[i];
|
I != E; ++I) {
|
||||||
|
const DSCallSite &Call = *I;
|
||||||
std::vector<std::string> EdgeSourceCaptions(Call.getNumPtrArgs()+2);
|
std::vector<std::string> EdgeSourceCaptions(Call.getNumPtrArgs()+2);
|
||||||
EdgeSourceCaptions[0] = "r";
|
EdgeSourceCaptions[0] = "r";
|
||||||
if (Call.isDirectCall())
|
if (Call.isDirectCall())
|
||||||
|
@ -152,15 +152,15 @@ bool Steens::runOnModule(Module &M) {
|
|||||||
// Now that we have all of the graphs inlined, we can go about eliminating
|
// Now that we have all of the graphs inlined, we can go about eliminating
|
||||||
// call nodes...
|
// call nodes...
|
||||||
//
|
//
|
||||||
std::vector<DSCallSite> &Calls =
|
std::list<DSCallSite> &Calls = ResultGraph->getAuxFunctionCalls();
|
||||||
ResultGraph->getAuxFunctionCalls();
|
|
||||||
assert(Calls.empty() && "Aux call list is already in use??");
|
assert(Calls.empty() && "Aux call list is already in use??");
|
||||||
|
|
||||||
// Start with a copy of the original call sites...
|
// Start with a copy of the original call sites.
|
||||||
Calls = ResultGraph->getFunctionCalls();
|
Calls = ResultGraph->getFunctionCalls();
|
||||||
|
|
||||||
for (unsigned i = 0; i != Calls.size(); ) {
|
for (std::list<DSCallSite>::iterator CI = Calls.begin(), E = Calls.end();
|
||||||
DSCallSite &CurCall = Calls[i];
|
CI != E;) {
|
||||||
|
DSCallSite &CurCall = *CI++;
|
||||||
|
|
||||||
// Loop over the called functions, eliminating as many as possible...
|
// Loop over the called functions, eliminating as many as possible...
|
||||||
std::vector<GlobalValue*> CallTargets;
|
std::vector<GlobalValue*> CallTargets;
|
||||||
@ -185,10 +185,9 @@ bool Steens::runOnModule(Module &M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CallTargets.empty()) { // Eliminated all calls?
|
if (CallTargets.empty()) { // Eliminated all calls?
|
||||||
CurCall = Calls.back(); // Remove entry
|
std::list<DSCallSite>::iterator I = CI;
|
||||||
Calls.pop_back();
|
Calls.erase(--I); // Remove entry
|
||||||
} else
|
}
|
||||||
++i; // Skip this call site...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RetValMap.clear();
|
RetValMap.clear();
|
||||||
|
@ -70,13 +70,11 @@ bool TDDataStructures::runOnModule(Module &M) {
|
|||||||
// Loop over unresolved call nodes. Any functions passed into (but not
|
// Loop over unresolved call nodes. Any functions passed into (but not
|
||||||
// returned!) from unresolvable call nodes may be invoked outside of the
|
// returned!) from unresolvable call nodes may be invoked outside of the
|
||||||
// current module.
|
// current module.
|
||||||
const std::vector<DSCallSite> &Calls = GlobalsGraph->getAuxFunctionCalls();
|
for (DSGraph::afc_iterator I = GlobalsGraph->afc_begin(),
|
||||||
for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
|
E = GlobalsGraph->afc_end(); I != E; ++I)
|
||||||
const DSCallSite &CS = Calls[i];
|
for (unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg)
|
||||||
for (unsigned arg = 0, e = CS.getNumPtrArgs(); arg != e; ++arg)
|
markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(),
|
||||||
markReachableFunctionsExternallyAccessible(CS.getPtrArg(arg).getNode(),
|
|
||||||
Visited);
|
Visited);
|
||||||
}
|
|
||||||
Visited.clear();
|
Visited.clear();
|
||||||
|
|
||||||
// Functions without internal linkage also have unknown incoming arguments!
|
// Functions without internal linkage also have unknown incoming arguments!
|
||||||
@ -135,10 +133,8 @@ void TDDataStructures::ComputePostOrder(Function &F,hash_set<DSGraph*> &Visited,
|
|||||||
Visited.insert(&G);
|
Visited.insert(&G);
|
||||||
|
|
||||||
// Recursively traverse all of the callee graphs.
|
// Recursively traverse all of the callee graphs.
|
||||||
const std::vector<DSCallSite> &FunctionCalls = G.getFunctionCalls();
|
for (DSGraph::fc_iterator CI = G.fc_begin(), E = G.fc_end(); CI != E; ++CI) {
|
||||||
|
Instruction *CallI = CI->getCallSite().getInstruction();
|
||||||
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
|
|
||||||
Instruction *CallI = FunctionCalls[i].getCallSite().getInstruction();
|
|
||||||
std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
|
std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
|
||||||
BUDataStructures::ActualCalleesTy::const_iterator>
|
BUDataStructures::ActualCalleesTy::const_iterator>
|
||||||
IP = ActualCallees.equal_range(CallI);
|
IP = ActualCallees.equal_range(CallI);
|
||||||
@ -211,8 +207,7 @@ void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
|
|||||||
// We are done with computing the current TD Graph! Now move on to
|
// We are done with computing the current TD Graph! Now move on to
|
||||||
// inlining the current graph into the graphs for its callees, if any.
|
// inlining the current graph into the graphs for its callees, if any.
|
||||||
//
|
//
|
||||||
const std::vector<DSCallSite> &FunctionCalls = Graph.getFunctionCalls();
|
if (Graph.fc_begin() == Graph.fc_end()) {
|
||||||
if (FunctionCalls.empty()) {
|
|
||||||
DEBUG(std::cerr << " [TD] No callees for: " << Graph.getFunctionNames()
|
DEBUG(std::cerr << " [TD] No callees for: " << Graph.getFunctionNames()
|
||||||
<< "\n");
|
<< "\n");
|
||||||
return;
|
return;
|
||||||
@ -224,7 +219,7 @@ void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
|
|||||||
// would be cloned only once, this should still be better on average).
|
// would be cloned only once, this should still be better on average).
|
||||||
//
|
//
|
||||||
DEBUG(std::cerr << " [TD] Inlining '" << Graph.getFunctionNames() <<"' into "
|
DEBUG(std::cerr << " [TD] Inlining '" << Graph.getFunctionNames() <<"' into "
|
||||||
<< FunctionCalls.size() << " call nodes.\n");
|
<< Graph.getFunctionCalls().size() << " call nodes.\n");
|
||||||
|
|
||||||
const BUDataStructures::ActualCalleesTy &ActualCallees =
|
const BUDataStructures::ActualCalleesTy &ActualCallees =
|
||||||
getAnalysis<BUDataStructures>().getActualCallees();
|
getAnalysis<BUDataStructures>().getActualCallees();
|
||||||
@ -235,12 +230,13 @@ void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
|
|||||||
// multiple call sites to the callees in the graph from this caller.
|
// multiple call sites to the callees in the graph from this caller.
|
||||||
std::multimap<DSGraph*, std::pair<Function*, const DSCallSite*> > CallSites;
|
std::multimap<DSGraph*, std::pair<Function*, const DSCallSite*> > CallSites;
|
||||||
|
|
||||||
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
|
for (DSGraph::fc_iterator CI = Graph.fc_begin(), E = Graph.fc_end();
|
||||||
Instruction *CallI = FunctionCalls[i].getCallSite().getInstruction();
|
CI != E; ++CI) {
|
||||||
|
Instruction *CallI = CI->getCallSite().getInstruction();
|
||||||
// For each function in the invoked function list at this call site...
|
// For each function in the invoked function list at this call site...
|
||||||
std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
|
std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
|
||||||
BUDataStructures::ActualCalleesTy::const_iterator>
|
BUDataStructures::ActualCalleesTy::const_iterator>
|
||||||
IP = ActualCallees.equal_range(CallI);
|
IP = ActualCallees.equal_range(CallI);
|
||||||
// Loop over each actual callee at this call site
|
// Loop over each actual callee at this call site
|
||||||
for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
|
for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
|
||||||
I != IP.second; ++I) {
|
I != IP.second; ++I) {
|
||||||
@ -248,7 +244,7 @@ void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
|
|||||||
assert(&CalleeGraph != &Graph && "TD need not inline graph into self!");
|
assert(&CalleeGraph != &Graph && "TD need not inline graph into self!");
|
||||||
|
|
||||||
CallSites.insert(std::make_pair(&CalleeGraph,
|
CallSites.insert(std::make_pair(&CalleeGraph,
|
||||||
std::make_pair(I->second, &FunctionCalls[i])));
|
std::make_pair(I->second, &*CI)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user