blob: c9aff4d672613d75cc87ff1f816a0064f163bb7f [file] [log] [blame]
//===- BottomUpCallGraph.cpp - -----------------------------------------------//
//
// The SAFECode Compiler
//
// 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.
//
//===----------------------------------------------------------------------===//
//
// I believe this pass does two things:
// o) It attempts to improve upon the call graph calculated by DSA for those
// call sites in which a callee was not found.
// o) It finds functions that are part of Strongly Connected Components (SCCs)
// in the call graph and marks them being a part of an SCC.
//
// FIXME:
// I believe the fixup of the call graph is no longer necessary; DSA asserts
// if it can't find a callee for a call instruction.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "bucg"
#include "dsa/DSGraph.h"
#include "dsa/DSNode.h"
#include "BottomUpCallGraph.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CallSite.h"
#include <iostream>
using namespace llvm;
static RegisterPass<BottomUpCallGraph> bucg("bucg","Call Graph from CBUDS");
namespace llvm {
char BottomUpCallGraph::ID = 0;
//
// This is needed because some call sites get merged away during DSA if they
// have the same inputs for instance.
// But for array bounds checking we need to get constraints from all the call
// sites
// So we have to get them some how.
//
bool
BottomUpCallGraph::runOnModule(Module &M) {
EQTDDataStructures &CBU = getAnalysis<EQTDDataStructures>();
const DSCallGraph & callGraph = CBU.getCallGraph();
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
for (inst_iterator I = inst_begin(MI), E = inst_end(MI); I != E; ++I) {
if (CallInst *CI = dyn_cast<CallInst>(&*I)) {
DSCallGraph::callee_iterator cI = callGraph.callee_begin(CI),
cE = callGraph.callee_end(CI);
if (cI == cE) {
// This call site is not included in the cbuds
// so we need to extra stuff.
CallSite CS = CallSite::get(CI);
if (Function *FCI = dyn_cast<Function>(CI->getOperand(0))) {
//if it is a direct call, we can just add it!
FuncCallSiteMap[FCI].push_back(CS);
} else {
// Here comes the ugly part
Function *parenFunc = CI->getParent()->getParent();
DSNode *calleeNode = CBU.getDSGraph(*parenFunc)->getNodeForValue(CS.getCalledValue()).getNode();
CalleeNodeCallSiteMap.insert(std::make_pair(calleeNode, CS));
}
}
}
}
}
#if 0
//
// Get the set of instructions for which the points-to graph has callee
// information.
//
std::vector<const Instruction *> Instructions;
CBU.callee_get_keys (Instructions);
#endif
//
// Process each callee of each indirect call site. We scan through each
// indirect call site known by the EQTD DSA pass and process its callees.
//
DSCallGraph::callee_key_iterator I = callGraph.key_begin();
DSCallGraph::callee_key_iterator E = callGraph.key_end();
for (; I != E; ++I) {
CallSite CS = *I;
DSCallGraph::callee_iterator i = callGraph.callee_begin(CS);
DSCallGraph::callee_iterator e = callGraph.callee_end(CS);
for (; i != e; ++i) {
const Function * Target = *i;
#if 0
DOUT << "CALLEE: " << Target->getName()
<< " from : " << *(CI) << std::endl;
#endif
FuncCallSiteMap[Target].push_back(CS);
// FIXME:
// This is a very expensive way of doing it,
//
// Determine if this is equivalent to any other callsites of this
// function.
Function *parenFunc = CS.getInstruction()->getParent()->getParent();
DSNode *calleeNode = CBU.getDSGraph(*parenFunc)
->getNodeForValue(CS.getCalledValue()).getNode();
CalleeNodeCallSiteMapTy::const_iterator cI, cE;
tie(cI, cE) = CalleeNodeCallSiteMap.equal_range(calleeNode);
for (; cI != cE; ++cI) {
//
// All the call sites Target should also be added to the
// funccallsitemap
//
FuncCallSiteMap[Target].push_back(cI->second);
}
}
}
figureOutSCCs(M);
return false;
}
void
BottomUpCallGraph::visit (Function *f) {
if (Visited.find(f) == Visited.end()) {
// Record that we have now visited this function
Visited.insert(f);
//
// If we have not visited this function before, that implies that the
// function won't be on the stack; therefore, push it on stack
//
Stack.push_back(f);
//
// Visit all the functions that can call this function.
//
if (FuncCallSiteMap.count(f)) {
std::vector<CallSite> & callsitelist = FuncCallSiteMap[f];
for (unsigned idx = 0, sz = callsitelist.size(); idx != sz; ++idx) {
Function *parent = callsitelist[idx].getInstruction()->getParent()
->getParent();
visit(parent);
}
}
Stack.pop_back();
} else {
// We have already visited this function; check if it forms an SCC
std::vector<Function*>::iterator res = std::find (Stack.begin(),
Stack.end(),
f);
if (res != Stack.end()) {
// Cycle detected.
for (; res != Stack.end() ; ++res) {
SccList.insert(*res);
}
}
}
}
void
BottomUpCallGraph::figureOutSCCs (Module &M) {
for (Module::iterator I = M.begin(), E= M.end(); I != E ; ++I) {
visit(I);
}
}
}