// BU: // Construct the callgraph from the local graphs // Find SCCs // inline bottom up // bool BUDataStructures::runOnModuleInternal(Module& M) { // // Make sure we have a DSGraph for all declared functions in the Module. // While we may not need them in this DSA pass, a later DSA pass may ask us // for their DSGraphs, and we want to have them if asked. // for (Function &F : M) { if (!(F.isDeclaration())){ getOrCreateGraph(&F); } } // // Do a post-order traversal of the SCC callgraph and do bottom-up inlining. // postOrderInline (M); // At the end of the bottom-up pass, the globals graph becomes complete. // FIXME: This is not the right way to do this, but it is sorta better than // nothing! In particular, externally visible globals and unresolvable call // nodes at the end of the BU phase should make things that they point to // incomplete in the globals graph. // GlobalsGraph->removeTriviallyDeadNodes(); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); GlobalsGraph->computeIntPtrFlags(); // // Create equivalence classes for aliasing globals so that we only need to // record one global per DSNode. // formGlobalECs(); // Merge the globals variables (not the calls) from the globals graph back // into the individual function's graph so that changes made to globals during // BU can be reflected. This is specifically needed for correct call graph // for (Function &F : M) { if (!(F.isDeclaration())){ DSGraph *Graph = getOrCreateGraph(&F); cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); Graph->maskIncompleteMarkers(); Graph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); Graph->computeIntPtrFlags(); } } // Once the correct flags have been calculated. Update the callgraph. for (Function &F : M) { if (!(F.isDeclaration())){ DSGraph *Graph = getOrCreateGraph(&F); Graph->buildCompleteCallGraph(callgraph, GlobalFunctionList, filterCallees); } } NumCallEdges += callgraph.size(); // Put the call graph in canonical form callgraph.buildSCCs(); callgraph.buildRoots(); DEBUG(print(errs(), &M)); return false; }
bool StdLibDataStructures::runOnModule (Module &M) { // // Get the results from the local pass. // init (&getAnalysis<LocalDataStructures>(), true, true, false, false); AllocWrappersAnalysis = &getAnalysis<AllocIdentify>(); // // Fetch the DSGraphs for all defined functions within the module. // for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) getOrCreateGraph(&*I); // // Erase direct calls to functions that don't return a pointer and are marked // with the readnone annotation. // for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (I->isDeclaration() && I->doesNotAccessMemory() && !isa<PointerType>(I->getReturnType())) eraseCallsTo(I); // // Erase direct calls to external functions that are not varargs, do not // return a pointer, and do not take pointers. // for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (I->isDeclaration() && !I->isVarArg() && !isa<PointerType>(I->getReturnType())) { bool hasPtr = false; for (Function::arg_iterator ii = I->arg_begin(), ee = I->arg_end(); ii != ee; ++ii) if (isa<PointerType>(ii->getType())) { hasPtr = true; break; } if (!hasPtr) eraseCallsTo(I); } if(!DisableStdLib) { // // Scan through the function summaries and process functions by summary. // for (int x = 0; recFuncs[x].name; ++x) if (Function* F = M.getFunction(recFuncs[x].name)) if (F->isDeclaration()) { processFunction(x, F); } std::set<std::string>::iterator ai = AllocWrappersAnalysis->alloc_begin(); std::set<std::string>::iterator ae = AllocWrappersAnalysis->alloc_end(); int x; for (x = 0; recFuncs[x].name; ++x) { if(recFuncs[x].name == std::string("malloc")) break; } for(;ai != ae; ++ai) { if(Function* F = M.getFunction(*ai)) processFunction(x, F); } ai = AllocWrappersAnalysis->dealloc_begin(); ae = AllocWrappersAnalysis->dealloc_end(); for (x = 0; recFuncs[x].name; ++x) { if(recFuncs[x].name == std::string("free")) break; } for(;ai != ae; ++ai) { if(Function* F = M.getFunction(*ai)) processFunction(x, F); } // // Merge return values and checked pointer values for SAFECode run-time // checks. // processRuntimeCheck (M, "boundscheck", 2); processRuntimeCheck (M, "boundscheckui", 2); processRuntimeCheck (M, "exactcheck2", 1); processRuntimeCheck (M, "boundscheck_debug", 2); processRuntimeCheck (M, "boundscheckui_debug", 2); processRuntimeCheck (M, "exactcheck2_debug", 1); processRuntimeCheck (M, "pchk_getActualValue", 1); } // // In the Local DSA Pass, we marked nodes passed to/returned from 'StdLib' // functions as External because, at that point, they were. However, they no // longer are necessarily External, and we need to update accordingly. // GlobalsGraph->maskIncompleteMarkers(); GlobalsGraph->computeExternalFlags(DSGraph::ResetExternal); for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) { DSGraph * G = getDSGraph(*I); unsigned EFlags = 0 | DSGraph::ResetExternal | DSGraph::DontMarkFormalsExternal | DSGraph::ProcessCallSites; G->maskIncompleteMarkers(); G->markIncompleteNodes(DSGraph::MarkFormalArgs |DSGraph::IgnoreGlobals); G->computeExternalFlags(EFlags); DEBUG(G->AssertGraphOK()); } GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs |DSGraph::IgnoreGlobals); GlobalsGraph->computeExternalFlags(DSGraph::ProcessCallSites); DEBUG(GlobalsGraph->AssertGraphOK()); for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) { DSGraph *Graph = getOrCreateGraph(I); Graph->maskIncompleteMarkers(); cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); Graph->markIncompleteNodes(DSGraph::MarkFormalArgs |DSGraph::IgnoreGlobals); } return false; }
// // Method: postOrderInline() // // Description: // This methods does a post order traversal of the call graph and performs // bottom-up inlining of the DSGraphs. // void BUDataStructures::postOrderInline (Module & M) { // Variables used for Tarjan SCC-finding algorithm. These are passed into // the recursive function used to find SCCs. std::vector<const Function*> Stack; std::map<const Function*, unsigned> ValMap; unsigned NextID = 1; // Do post order traversal on the global ctors. Use this information to update // the globals graph. const char *Name = "llvm.global_ctors"; GlobalVariable *GV = M.getNamedGlobal(Name); if (GV && !(GV->isDeclaration()) && !(GV->hasLocalLinkage())) { // Should be an array of '{ int, void ()* }' structs. The first value is // the init priority, which we ignore. ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); if (InitList) { for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))) { if (CS->getNumOperands() != 2) break; // Not array of 2-element structs. Constant *FP = CS->getOperand(1); if (FP->isNullValue()) break; // Found a null terminator, exit. if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) if (CE->isCast()) FP = CE->getOperand(0); Function *F = dyn_cast<Function>(FP); if (F && !F->isDeclaration() && !ValMap.count(F)) { calculateGraphs(F, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(*F)); } } GlobalsGraph->removeTriviallyDeadNodes(); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); GlobalsGraph->computeIntPtrFlags(); // // Create equivalence classes for aliasing globals so that we only need to // record one global per DSNode. // formGlobalECs(); // propogte information calculated // from the globals graph to the other graphs. for (Module::iterator F = M.begin(); F != M.end(); ++F) { if (!(F->isDeclaration())){ DSGraph *Graph = getDSGraph(*F); cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); Graph->buildCallGraph(callgraph, GlobalFunctionList, filterCallees); Graph->maskIncompleteMarkers(); Graph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); Graph->computeIntPtrFlags(); } } } } // // Start the post order traversal with the main() function. If there is no // main() function, don't worry; we'll have a separate traversal for inlining // graphs for functions not reachable from main(). // Function *MainFunc = M.getFunction ("main"); if (MainFunc && !MainFunc->isDeclaration()) { calculateGraphs(MainFunc, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(*MainFunc)); } // // Calculate the graphs for any functions that are unreachable from main... // for (Function &F : M) if (!F.isDeclaration() && !ValMap.count(&F)) { if (MainFunc) DEBUG(errs() << debugname << ": Function unreachable from main: " << F.getName() << "\n"); calculateGraphs(&F, Stack, NextID, ValMap); // Calculate all graphs. CloneAuxIntoGlobal(getDSGraph(F)); // Mark this graph as processed. Do this by finding all functions // in the graph that map to it, and mark them visited. // Note that this really should be handled neatly by calculateGraphs // itself, not here. However this catches the worst offenders. DSGraph *G = getDSGraph(F); for(DSGraph::retnodes_iterator RI = G->retnodes_begin(), RE = G->retnodes_end(); RI != RE; ++RI) { if (getDSGraph(*RI->first) == G) { if (!ValMap.count(RI->first)) ValMap[RI->first] = ~0U; else assert(ValMap[RI->first] == ~0U); } } } return; }
bool BUDataStructures::runOnModuleInternal(Module& M) { std::vector<const Function*> Stack; hash_map<const Function*, unsigned> ValMap; unsigned NextID = 1; Function *MainFunc = M.getFunction("main"); if (MainFunc && !MainFunc->isDeclaration()) { calculateGraphs(MainFunc, Stack, NextID, ValMap); CloneAuxIntoGlobal(getDSGraph(MainFunc)); } else { DEBUG(errs() << debugname << ": No 'main' function found!\n"); } // Calculate the graphs for any functions that are unreachable from main... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration() && !hasDSGraph(I)) { if (MainFunc) DEBUG(errs() << debugname << ": Function unreachable from main: " << I->getName() << "\n"); calculateGraphs(I, Stack, NextID, ValMap); // Calculate all graphs. CloneAuxIntoGlobal(getDSGraph(I)); } // If we computed any temporary indcallgraphs, free them now. for (std::map<std::vector<const Function*>, std::pair<DSGraph*, std::vector<DSNodeHandle> > >::iterator I = IndCallGraphMap.begin(), E = IndCallGraphMap.end(); I != E; ++I) { I->second.second.clear(); // Drop arg refs into the graph. delete I->second.first; } IndCallGraphMap.clear(); // At the end of the bottom-up pass, the globals graph becomes complete. // FIXME: This is not the right way to do this, but it is sorta better than // nothing! In particular, externally visible globals and unresolvable call // nodes at the end of the BU phase should make things that they point to // incomplete in the globals graph. // finalizeGlobals(); GlobalsGraph->removeTriviallyDeadNodes(true); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); formGlobalECs(); // Merge the globals variables (not the calls) from the globals graph back // into the main function's graph so that the main function contains all of // the information about global pools and GV usage in the program. if (MainFunc && !MainFunc->isDeclaration()) { DSGraph* MainGraph = getDSGraph(MainFunc); const DSGraph* GG = MainGraph->getGlobalsGraph(); ReachabilityCloner RC(MainGraph, GG, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); // Clone the global nodes into this graph. for (DSScalarMap::global_iterator I = GG->getScalarMap().global_begin(), E = GG->getScalarMap().global_end(); I != E; ++I) if (isa<GlobalVariable>(*I)) RC.getClonedNH(GG->getNodeForValue(*I)); MainGraph->maskIncompleteMarkers(); MainGraph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); } NumCallEdges += callee.size(); return false; }