static void printCollection(const Collection &C, llvm::raw_ostream &O, const Module *M, const std::string &Prefix) { if (M == 0) { O << "Null Module pointer, cannot continue!\n"; return; } unsigned TotalNumNodes = 0, TotalCallNodes = 0; for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) if (C.hasDSGraph(*I)) { DSGraph* Gr = C.getDSGraph((const Function&)*I); unsigned NumCalls = Gr->shouldUseAuxCalls() ? Gr->getAuxFunctionCalls().size() : Gr->getFunctionCalls().size(); bool IsDuplicateGraph = false; //if no only print options, print everything bool doPrint = OnlyPrint.begin() == OnlyPrint.end(); //otherwise check the name if (!doPrint) doPrint = OnlyPrint.end() != std::find(OnlyPrint.begin(), OnlyPrint.end(), I->getName().str()); if (doPrint) { const Function *SCCFn = Gr->retnodes_begin()->first; if (&*I == SCCFn) { Gr->writeGraphToFile(O, Prefix+I->getName().str()); } else { IsDuplicateGraph = true; // Don't double count node/call nodes. O << "Didn't write '" << Prefix+I->getName().str() << ".dot' - Graph already emitted to '" << Prefix+SCCFn->getName().str() << "\n"; } } else { const Function *SCCFn = Gr->retnodes_begin()->first; if (&*I == SCCFn) { //O << "Skipped Writing '" << Prefix+I->getName().str() << ".dot'... [" // << Gr->getGraphSize() << "+" << NumCalls << "]\n"; } else { IsDuplicateGraph = true; // Don't double count node/call nodes. } } if (!IsDuplicateGraph) { unsigned GraphSize = Gr->getGraphSize(); if (MaxGraphSize < GraphSize) MaxGraphSize = GraphSize; TotalNumNodes += Gr->getGraphSize(); TotalCallNodes += NumCalls; for (DSGraph::node_iterator NI = Gr->node_begin(), E = Gr->node_end(); NI != E; ++NI) if (NI->isNodeCompletelyFolded()) ++NumFoldedNodes; } } DSGraph* GG = C.getGlobalsGraph(); TotalNumNodes += GG->getGraphSize(); TotalCallNodes += GG->getFunctionCalls().size(); GG->writeGraphToFile(O, Prefix + "GlobalsGraph"); O << "\nGraphs contain [" << TotalNumNodes << "+" << TotalCallNodes << "] nodes total\n"; }
// // 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; } }
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 }