// // Method: calculateGraphs() // // Description: // Perform recursive bottom-up inlining of DSGraphs from callee to caller. // // Inputs: // F - The function which should have its callees' DSGraphs merged into its // own DSGraph. // Stack - The stack used for Tarjan's SCC-finding algorithm. // NextID - The nextID value used for Tarjan's SCC-finding algorithm. // ValMap - The map used for Tarjan's SCC-finding algorithm. // // Return value: // unsigned BUDataStructures::calculateGraphs (const Function *F, TarjanStack & Stack, unsigned & NextID, TarjanMap & ValMap) { assert(!ValMap.count(F) && "Shouldn't revisit functions!"); unsigned Min = NextID++, MyID = Min; ValMap[F] = Min; Stack.push_back(F); // // FIXME: This test should be generalized to be any function that we have // already processed in the case when there isn't a main() or there are // unreachable functions! // if (F->isDeclaration()) { // sprintf, fprintf, sscanf, etc... // No callees! Stack.pop_back(); ValMap[F] = ~0; return Min; } // // Get the DSGraph of the current function. Make one if one doesn't exist. // DSGraph* Graph = getOrCreateGraph(F); // // Find all callee functions. Use the DSGraph for this (do not use the call // graph (DSCallgraph) as we're still in the process of constructing it). // FuncSet CalleeFunctions; getAllAuxCallees(Graph, CalleeFunctions); // // Iterate through each call target (these are the edges out of the current // node (i.e., the current function) in Tarjan graph parlance). Find the // minimum assigned ID. // for (FuncSet::iterator I = CalleeFunctions.begin(), E = CalleeFunctions.end(); I != E; ++I) { const Function *Callee = *I; unsigned M; // // If we have not visited this callee before, visit it now (this is the // post-order component of the Bottom-Up algorithm). Otherwise, look up // the assigned ID value from the Tarjan Value Map. // TarjanMap::iterator It = ValMap.find(Callee); if (It == ValMap.end()) // No, visit it now. M = calculateGraphs(Callee, Stack, NextID, ValMap); else // Yes, get it's number. M = It->second; // // If we've found a function with a smaller ID than this funtion, record // that ID as the minimum ID. // if (M < Min) Min = M; } assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); // // If the minimum ID found is not this function's ID, then this function is // part of a larger SCC. // if (Min != MyID) return Min; // // If this is a new SCC, process it now. // if (Stack.back() == F) { // Special case the single "SCC" case here. DEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: " << F->getName() << "\n"); Stack.pop_back(); DEBUG(errs() << " [BU] Calculating graph for: " << F->getName()<< "\n"); DSGraph* G = getOrCreateGraph(F); calculateGraph(G); DEBUG(errs() << " [BU] Done inlining: " << F->getName() << " [" << G->getGraphSize() << "+" << G->getAuxFunctionCalls().size() << "]\n"); if (MaxSCC < 1) MaxSCC = 1; // // Should we revisit the graph? Only do it if there are now new resolvable // callees. FuncSet NewCallees; getAllAuxCallees(G, NewCallees); if (!NewCallees.empty()) { if (hasNewCallees(NewCallees, CalleeFunctions)) { DEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n"); ValMap.erase(F); ++NumRecalculations; return calculateGraphs(F, Stack, NextID, ValMap); } ++NumRecalculationsSkipped; } ValMap[F] = ~0U; return MyID; } else { unsigned SCCSize = 1; const Function *NF = Stack.back(); if(NF != F) ValMap[NF] = ~0U; DSGraph* SCCGraph = getDSGraph(*NF); // // First thing first: collapse all of the DSGraphs into a single graph for // the entire SCC. Splice all of the graphs into one and discard all of // the old graphs. // while (NF != F) { Stack.pop_back(); NF = Stack.back(); if(NF != F) ValMap[NF] = ~0U; DSGraph* NFG = getDSGraph(*NF); if (NFG != SCCGraph) { // Update the Function -> DSG map. for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(), E = NFG->retnodes_end(); I != E; ++I) setDSGraph(*I->first, SCCGraph); SCCGraph->spliceFrom(NFG); delete NFG; ++SCCSize; } } Stack.pop_back(); DEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: " << SCCSize << "\n"); // Compute the Max SCC Size. if (MaxSCC < SCCSize) MaxSCC = SCCSize; // Clean up the graph before we start inlining a bunch again... SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); // Now that we have one big happy family, resolve all of the call sites in // the graph... calculateGraph(SCCGraph); DEBUG(errs() << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize() << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n" << "DONE with SCC #: " << MyID << "\n"); FuncSet NewCallees; getAllAuxCallees(SCCGraph, NewCallees); if (!NewCallees.empty()) { if (hasNewCallees(NewCallees, CalleeFunctions)) { DEBUG(errs() << "Recalculating SCC Graph " << F->getName() << " due to new knowledge\n"); ValMap.erase(F); ++NumRecalculations; return calculateGraphs(F, Stack, NextID, ValMap); } ++NumRecalculationsSkipped; } ValMap[F] = ~0U; return MyID; } }
// 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; }
unsigned BUDataStructures::calculateGraphs(const Function *F, std::vector<const Function*> &Stack, unsigned &NextID, hash_map<const Function*, unsigned> &ValMap) { assert(!ValMap.count(F) && "Shouldn't revisit functions!"); unsigned Min = NextID++, MyID = Min; ValMap[F] = Min; Stack.push_back(F); // FIXME! This test should be generalized to be any function that we have // already processed, in the case when there isn't a main or there are // unreachable functions! if (F->isDeclaration()) { // sprintf, fprintf, sscanf, etc... // No callees! Stack.pop_back(); ValMap[F] = ~0; return Min; } DSGraph* Graph = getOrFetchDSGraph(F); // Find all callee functions. std::vector<const Function*> CalleeFunctions; GetAllAuxCallees(Graph, CalleeFunctions); std::sort(CalleeFunctions.begin(), CalleeFunctions.end()); std::vector<const Function*>::iterator uid = std::unique(CalleeFunctions.begin(), CalleeFunctions.end()); CalleeFunctions.resize(uid - CalleeFunctions.begin()); // The edges out of the current node are the call site targets... for (unsigned i = 0, e = CalleeFunctions.size(); i != e; ++i) { const Function *Callee = CalleeFunctions[i]; unsigned M; // Have we visited the destination function yet? hash_map<const Function*, unsigned>::iterator It = ValMap.find(Callee); if (It == ValMap.end()) // No, visit it now. M = calculateGraphs(Callee, Stack, NextID, ValMap); else // Yes, get it's number. M = It->second; if (M < Min) Min = M; } assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); if (Min != MyID) return Min; // This is part of a larger SCC! // If this is a new SCC, process it now. if (Stack.back() == F) { // Special case the single "SCC" case here. DEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: " << F->getName() << "\n"); Stack.pop_back(); DEBUG(errs() << " [BU] Calculating graph for: " << F->getName()<< "\n"); calculateGraph(Graph); DEBUG(errs() << " [BU] Done inlining: " << F->getName() << " [" << Graph->getGraphSize() << "+" << Graph->getAuxFunctionCalls().size() << "]\n"); if (MaxSCC < 1) MaxSCC = 1; // Should we revisit the graph? Only do it if there are now new resolvable // callees or new callees GetAllAuxCallees(Graph, CalleeFunctions); if (CalleeFunctions.size()) { DEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n"); ValMap.erase(F); return calculateGraphs(F, Stack, NextID, ValMap); } else { ValMap[F] = ~0U; return MyID; } } else { // SCCFunctions - Keep track of the functions in the current SCC // std::vector<DSGraph*> SCCGraphs; unsigned SCCSize = 1; const Function *NF = Stack.back(); ValMap[NF] = ~0U; DSGraph* SCCGraph = getDSGraph(NF); // First thing first, collapse all of the DSGraphs into a single graph for // the entire SCC. Splice all of the graphs into one and discard all of the // old graphs. // while (NF != F) { Stack.pop_back(); NF = Stack.back(); ValMap[NF] = ~0U; DSGraph* NFG = getDSGraph(NF); if (NFG != SCCGraph) { // Update the Function -> DSG map. for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(), E = NFG->retnodes_end(); I != E; ++I) setDSGraph(I->first, SCCGraph); SCCGraph->spliceFrom(NFG); delete NFG; ++SCCSize; } } Stack.pop_back(); DEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: " << SCCSize << "\n"); // Compute the Max SCC Size. if (MaxSCC < SCCSize) MaxSCC = SCCSize; // Clean up the graph before we start inlining a bunch again... SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); // Now that we have one big happy family, resolve all of the call sites in // the graph... calculateGraph(SCCGraph); DEBUG(errs() << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize() << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n" << "DONE with SCC #: " << MyID << "\n"); // We never have to revisit "SCC" processed functions... return MyID; } return MyID; // == Min }