#include "llvm/Analysis/CallGraph.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"
#include <ostream>
using namespace llvm;
namespace {
class VISIBILITY_HIDDEN BasicCallGraph : public CallGraph, public ModulePass {
CallGraphNode *Root;
CallGraphNode *ExternalCallingNode;
CallGraphNode *CallsExternalNode;
public:
static char ID; BasicCallGraph() : ModulePass(&ID), Root(0),
ExternalCallingNode(0), CallsExternalNode(0) {}
virtual bool runOnModule(Module &M) {
CallGraph::initialize(M);
ExternalCallingNode = getOrInsertFunction(0);
CallsExternalNode = new CallGraphNode(0);
Root = 0;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
addToCallGraph(I);
if (Root == 0) Root = ExternalCallingNode;
return false;
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
void print(std::ostream *o, const Module *M) const {
if (o) print(*o, M);
}
virtual void print(std::ostream &o, const Module *M) const {
o << "CallGraph Root is: ";
if (Function *F = getRoot()->getFunction())
o << F->getName() << "\n";
else
o << "<<null function: 0x" << getRoot() << ">>\n";
CallGraph::print(o, M);
}
virtual void releaseMemory() {
destroy();
}
inline void dump() const {
print(cerr, Mod);
}
CallGraphNode* getExternalCallingNode() const { return ExternalCallingNode; }
CallGraphNode* getCallsExternalNode() const { return CallsExternalNode; }
CallGraphNode *getRoot() { return Root; }
const CallGraphNode *getRoot() const { return Root; }
private:
void addToCallGraph(Function *F) {
CallGraphNode *Node = getOrInsertFunction(F);
if (!F->hasLocalLinkage()) {
ExternalCallingNode->addCalledFunction(CallSite(), Node);
if (F->getName() == "main") {
if (Root) Root = ExternalCallingNode;
else
Root = Node; }
}
for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I)
if ((!isa<CallInst>(I) && !isa<InvokeInst>(I))
|| !CallSite(cast<Instruction>(I)).isCallee(I)) {
ExternalCallingNode->addCalledFunction(CallSite(), Node);
break;
}
if (F->isDeclaration() && !F->isIntrinsic())
Node->addCalledFunction(CallSite(), CallsExternalNode);
for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
for (BasicBlock::iterator II = BB->begin(), IE = BB->end();
II != IE; ++II) {
CallSite CS = CallSite::get(II);
if (CS.getInstruction() && !isa<DbgInfoIntrinsic>(II)) {
const Function *Callee = CS.getCalledFunction();
if (Callee)
Node->addCalledFunction(CS, getOrInsertFunction(Callee));
else
Node->addCalledFunction(CS, CallsExternalNode);
}
}
}
virtual void destroy() {
delete CallsExternalNode;
CallsExternalNode = 0;
CallGraph::destroy();
}
};
}
static RegisterAnalysisGroup<CallGraph> X("Call Graph");
static RegisterPass<BasicCallGraph>
Y("basiccg", "Basic CallGraph Construction", false, true);
static RegisterAnalysisGroup<CallGraph, true> Z(Y);
char CallGraph::ID = 0;
char BasicCallGraph::ID = 0;
void CallGraph::initialize(Module &M) {
Mod = &M;
}
void CallGraph::destroy() {
if (!FunctionMap.empty()) {
for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
I != E; ++I)
delete I->second;
FunctionMap.clear();
}
}
void CallGraph::print(std::ostream &OS, const Module *M) const {
for (CallGraph::const_iterator I = begin(), E = end(); I != E; ++I)
I->second->print(OS);
}
void CallGraph::dump() const {
print(cerr, 0);
}
Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
assert(CGN->CalledFunctions.empty() && "Cannot remove function from call "
"graph if it references other functions!");
Function *F = CGN->getFunction(); delete CGN; FunctionMap.erase(F);
Mod->getFunctionList().remove(F);
return F;
}
void CallGraph::changeFunction(Function *OldF, Function *NewF) {
iterator I = FunctionMap.find(OldF);
CallGraphNode *&New = FunctionMap[NewF];
assert(I != FunctionMap.end() && I->second && !New &&
"OldF didn't exist in CG or NewF already does!");
New = I->second;
New->F = NewF;
FunctionMap.erase(I);
}
CallGraphNode *CallGraph::getOrInsertFunction(const Function *F) {
CallGraphNode *&CGN = FunctionMap[F];
if (CGN) return CGN;
assert((!F || F->getParent() == Mod) && "Function not in current module!");
return CGN = new CallGraphNode(const_cast<Function*>(F));
}
void CallGraphNode::print(std::ostream &OS) const {
if (Function *F = getFunction())
OS << "Call graph node for function: '" << F->getName() <<"'\n";
else
OS << "Call graph node <<null function: 0x" << this << ">>:\n";
for (const_iterator I = begin(), E = end(); I != E; ++I)
if (Function *FI = I->second->getFunction())
OS << " Calls function '" << FI->getName() <<"'\n";
else
OS << " Calls external node\n";
OS << "\n";
}
void CallGraphNode::dump() const { print(cerr); }
void CallGraphNode::removeCallEdgeFor(CallSite CS) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
if (I->first == CS) {
CalledFunctions.erase(I);
return;
}
}
}
void CallGraphNode::removeAnyCallEdgeTo(CallGraphNode *Callee) {
for (unsigned i = 0, e = CalledFunctions.size(); i != e; ++i)
if (CalledFunctions[i].second == Callee) {
CalledFunctions[i] = CalledFunctions.back();
CalledFunctions.pop_back();
--i; --e;
}
}
void CallGraphNode::removeOneAbstractEdgeTo(CallGraphNode *Callee) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callee to remove!");
CallRecord &CR = *I;
if (CR.second == Callee && !CR.first.getInstruction()) {
CalledFunctions.erase(I);
return;
}
}
}
void CallGraphNode::replaceCallSite(CallSite Old, CallSite New) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callsite to replace!");
if (I->first == Old) {
I->first = New;
return;
}
}
}
DEFINING_FILE_FOR(CallGraph)