void BUDataStructures::CloneAuxIntoGlobal(DSGraph* G) { DSGraph* GG = G->getGlobalsGraph(); ReachabilityCloner RC(GG, G, 0); for(DSGraph::afc_iterator ii = G->afc_begin(), ee = G->afc_end(); ii != ee; ++ii) { //cerr << "Pushing " << ii->getCallSite().getInstruction()->getOperand(0) << "\n"; //If we can, merge with an existing call site for this instruction if (GG->hasNodeForValue(ii->getCallSite().getInstruction()->getOperand(0))) { DSGraph::afc_iterator GGii; for(GGii = GG->afc_begin(); GGii != GG->afc_end(); ++GGii) if (GGii->getCallSite().getInstruction()->getOperand(0) == ii->getCallSite().getInstruction()->getOperand(0)) break; if (GGii != GG->afc_end()) RC.cloneCallSite(*ii).mergeWith(*GGii); else GG->addAuxFunctionCall(RC.cloneCallSite(*ii)); } else { GG->addAuxFunctionCall(RC.cloneCallSite(*ii)); } } }
// run - Calculate the top down data structure graphs for each function in the // program. // bool TDDataStructures::runOnModule(Module &M) { init(useEQBU ? &getAnalysis<EquivBUDataStructures>() : &getAnalysis<BUDataStructures>(), true, true, true, false); // Figure out which functions must not mark their arguments complete because // they are accessible outside this compilation unit. Currently, these // arguments are functions which are reachable by incomplete or external // nodes in the globals graph. const DSScalarMap &GGSM = GlobalsGraph->getScalarMap(); DenseSet<DSNode*> Visited; for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end(); I != E; ++I) { DSNode *N = GGSM.find(*I)->second.getNode(); if (N->isIncompleteNode() || N->isExternalNode()) markReachableFunctionsExternallyAccessible(N, Visited); } // Loop over unresolved call nodes. Any functions passed into (but not // returned!) from unresolvable call nodes may be invoked outside of the // current module. for (DSGraph::afc_iterator I = GlobalsGraph->afc_begin(), E = GlobalsGraph->afc_end(); I != E; ++I) for (unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg) markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(), Visited); Visited.clear(); // Clear Aux of Globals Graph to be refilled in later by post-TD unresolved // functions GlobalsGraph->getAuxFunctionCalls().clear(); // Functions without internal linkage are definitely externally callable! for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration() && !I->hasInternalLinkage() && !I->hasPrivateLinkage()) ExternallyCallable.insert(I); // Debug code to print the functions that are externally callable #if 0 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (ExternallyCallable.count(I)) { errs() << "ExternallyCallable: " << I->getNameStr() << "\n"; } #endif // We want to traverse the call graph in reverse post-order. To do this, we // calculate a post-order traversal, then reverse it. DenseSet<DSGraph*> VisitedGraph; std::vector<DSGraph*> PostOrder; {TIME_REGION(XXX, "td:Compute postorder"); // Calculate top-down from main... if (Function *F = M.getFunction("main")) ComputePostOrder(*F, VisitedGraph, PostOrder); // Next calculate the graphs for each unreachable function... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) ComputePostOrder(*I, VisitedGraph, PostOrder); VisitedGraph.clear(); // Release memory! } {TIME_REGION(XXX, "td:Inline stuff"); // Visit each of the graphs in reverse post-order now! while (!PostOrder.empty()) { InlineCallersIntoGraph(PostOrder.back()); PostOrder.pop_back(); } } // Free the IndCallMap. while (!IndCallMap.empty()) { delete IndCallMap.begin()->second; IndCallMap.erase(IndCallMap.begin()); } formGlobalECs(); ExternallyCallable.clear(); GlobalsGraph->removeTriviallyDeadNodes(); GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); GlobalsGraph->computeIntPtrFlags(); // Make sure each graph has updated external information about globals // in the globals graph. VisitedGraph.clear(); for (Module::iterator F = M.begin(); F != M.end(); ++F) { if (!(F->isDeclaration())){ DSGraph *Graph = getOrCreateGraph(F); if (!VisitedGraph.insert(Graph).second) continue; cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal); Graph->computeIntPtrFlags(); // Clean up uninteresting nodes Graph->removeDeadNodes(0); } } // CBU contains the correct call graph. // Restore it, so that subsequent passes and clients can get it. restoreCorrectCallGraph(); /// Added by Zhiyuan: print out the DSGraph. if (llvm::DebugFlag) { print(errs(), &M); } return false; }
// run - Calculate the top down data structure graphs for each function in the // program. // bool TDDataStructures::runOnModule(Module &M) { init(useEQBU ? &getAnalysis<EquivBUDataStructures>() : &getAnalysis<BUDataStructures>(), true, true, true, false); // Figure out which functions must not mark their arguments complete because // they are accessible outside this compilation unit. Currently, these // arguments are functions which are reachable by global variables in the // globals graph. const DSScalarMap &GGSM = GlobalsGraph->getScalarMap(); hash_set<DSNode*> Visited; for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end(); I != E; ++I) { DSNode *N = GGSM.find(*I)->second.getNode(); if (N->NodeType.isIncompleteNode()) markReachableFunctionsExternallyAccessible(N, Visited); } // Loop over unresolved call nodes. Any functions passed into (but not // returned!) from unresolvable call nodes may be invoked outside of the // current module. for (DSGraph::afc_iterator I = GlobalsGraph->afc_begin(), E = GlobalsGraph->afc_end(); I != E; ++I) for (unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg) markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(), Visited); Visited.clear(); // Clear Aux of Globals Graph to be refilled in later by post-TD unresolved // functions GlobalsGraph->getAuxFunctionCalls().clear(); // Functions without internal linkage also have unknown incoming arguments! for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration() && !I->hasInternalLinkage()) ArgsRemainIncomplete.insert(I); // We want to traverse the call graph in reverse post-order. To do this, we // calculate a post-order traversal, then reverse it. hash_set<DSGraph*> VisitedGraph; std::vector<DSGraph*> PostOrder; {TIME_REGION(XXX, "td:Compute postorder"); // Calculate top-down from main... if (Function *F = M.getFunction("main")) ComputePostOrder(F, VisitedGraph, PostOrder); // Next calculate the graphs for each unreachable function... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) ComputePostOrder(I, VisitedGraph, PostOrder); VisitedGraph.clear(); // Release memory! } {TIME_REGION(XXX, "td:Inline stuff"); // Visit each of the graphs in reverse post-order now! while (!PostOrder.empty()) { InlineCallersIntoGraph(PostOrder.back()); PostOrder.pop_back(); } } // Free the IndCallMap. while (!IndCallMap.empty()) { delete IndCallMap.begin()->second; IndCallMap.erase(IndCallMap.begin()); } formGlobalECs(); ArgsRemainIncomplete.clear(); GlobalsGraph->removeTriviallyDeadNodes(); return false; }
// // Method: CloneAuxIntoGlobal() // // Description: // This method takes the specified graph and processes each unresolved call // site (a call site for which all targets are not yet known). For each // unresolved call site, it adds it to the globals graph and merges // information about the call site if the globals graph already had the call // site in its own list of unresolved call sites. // void BUDataStructures::CloneAuxIntoGlobal(DSGraph* G) { // // If this DSGraph has no unresolved call sites, do nothing. We do enough // work that wastes time even when the list is empty that this extra check // is probably worth it. // if (G->afc_begin() == G->afc_end()) return; DSGraph* GG = G->getGlobalsGraph(); ReachabilityCloner RC(GG, G, 0); // // Determine which called values are both within the local graph DSCallsites // and the global graph DSCallsites. Note that we require that the global // graph have a DSNode for the called value. // std::map<Value *, DSCallSite *> CommonCallValues; for (DSGraph::afc_iterator ii = G->afc_begin(), ee = G->afc_end(); ii != ee; ++ii) { // // If the globals graph has a DSNode for the LLVM value used in the local // unresolved call site, then it might have a DSCallSite for it, too. // Record this call site as a potential call site that will need to be // merged. // // Otherwise, just add the call site to the globals graph. // Value * V = ii->getCallSite().getCalledValue(); if (GG->hasNodeForValue(V)) { DSCallSite & DS = *ii; CommonCallValues[V] = &DS; } else { GG->addAuxFunctionCall(RC.cloneCallSite(*ii)); } } // // Scan through all the unresolved call sites in the globals graph and see if // the local graph has a call using the same LLVM value. If so, merge the // call sites. // DSGraph::afc_iterator GGii = GG->afc_begin(); for (; GGii != GG->afc_end(); ++GGii) { // // Determine if this unresolved call site is also in the local graph. // If so, then merge it. // Value * CalledValue = GGii->getCallSite().getCalledValue(); std::map<Value *, DSCallSite *>::iterator v; v = CommonCallValues.find (CalledValue); if (v != CommonCallValues.end()) { // // Merge the unresolved call site into the globals graph. // RC.cloneCallSite(*(v->second)).mergeWith(*GGii); // // Mark that this call site was merged by removing the called LLVM value // from the set of values common to both the local and global DSGraphs. // CommonCallValues.erase (v); } } // // We've now merged all DSCallSites that were known both to the local graph // and the globals graph. Now, there are still some local call sites that // need to be *added* to the globals graph; they are in DSCallSites remaining // in CommonCallValues. // std::map<Value *, DSCallSite *>::iterator v = CommonCallValues.begin (); for (; v != CommonCallValues.end(); ++v) { GG->addAuxFunctionCall(RC.cloneCallSite(*(v->second))); } return; }