| #include "dsa/DSGraph.h" |
| #include "dsa/DSNode.h" |
| #include "BottomUpCallGraph.h" |
| #include "llvm/Function.h" |
| #include "llvm/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; |
| |
| 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) { |
| CompleteBUDataStructures &CBU = getAnalysis<CompleteBUDataStructures>(); |
| const CompleteBUDataStructures::ActualCalleesTy &AC = CBU.getActualCallees(); |
| |
| for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { |
| Function * F = MI; |
| for (inst_iterator I = inst_begin(MI), E = inst_end(MI); I != E; ++I) { |
| if (Instruction *CI = dyn_cast<Instruction>(&*I)) { |
| if (isa<CallInst>(CI)) { |
| CompleteBUDataStructures::callee_iterator cI = CBU.callee_begin(CI), |
| cE = CBU.callee_end(CI); |
| if (cI == cE) { |
| //Hmm 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)); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| for (CompleteBUDataStructures::ActualCalleesTy::const_iterator |
| I = AC.begin(), E = AC.end(); I != E; ++I) { |
| CallSite CS = CallSite::get(I->first); |
| DOUT << "CALLEE: " << I->second->getName() << " from : " << *(I->first) << std::endl; |
| FuncCallSiteMap[I->second].push_back(CS); |
| //see if this is equivalent to any other callsites of this function..... |
| //FIXME This is very expensive way of doing it, |
| Function *parenFunc = I->first->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 I->second should also be added to the funccallsitemap |
| FuncCallSiteMap[I->second].push_back(cI->second); |
| } |
| } |
| figureOutSCCs(M); |
| return false; |
| } |
| |
| |
| void BottomUpCallGraph::visit(Function *f) { |
| if (Visited.find(f) == Visited.end()) { |
| //Have not visited it before |
| Visited.insert(f); |
| //not visited implies it won't be there on the stack anyways, so push it |
| //on stack |
| Stack.push_back(f); |
| 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 { |
| //Have already visited it, check if it forms 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); |
| } |
| } |
| } |
| |
| RegisterPass<BottomUpCallGraph> bucg("bucg","Call Graph from CBUDS"); |