/** * @brief Finds a next SCC and its represent and returns them. * * @param[in] sccs All SCCs in the call graph. * @param[in] computedFuncs Functions that already have been included in * FuncInfoCompOrder::order. * @param[in] remainingFuncs Functions that haven't been included in * FuncInfoCompOrder::order. * * @par Preconditions * - @a remainingFuncs is non-empty * - @a remainingFuncs doesn't contain a function which calls just functions * from @a computedFuncs. */ CallInfoObtainer::SCCWithRepresent CallInfoObtainer::findNextSCC(const FuncSetSet &sccs, const FuncSet &computedFuncs, const FuncSet &remainingFuncs) const { PRECONDITION(!remainingFuncs.empty(), "it should not be empty"); // // We try to locate an SCC whose members call just the functions in // the SCC or in computedFuncs. Then, if the found SCC contains a function // from remainingFuncs, return the function. // // For every SCC... for (const auto &scc : sccs) { bool sccFound = true; ShPtr<Function> funcFromRemainingFuncs; // For every function in the SCC... for (const auto &func : scc) { // Check whether the function calls just the functions in the SCC // or in computedFuncs. ShPtr<CG::CalledFuncs> calledFuncs(cg->getCalledFuncs(func)); FuncSet mayCall(setUnion(scc, computedFuncs)); if (!setDifference(calledFuncs->callees, mayCall).empty()) { sccFound = false; } else { // Have we encountered a function from remainingFuncs? if (hasItem(remainingFuncs, func)) { funcFromRemainingFuncs = func; } } } if (sccFound && funcFromRemainingFuncs) { return SCCWithRepresent(scc, funcFromRemainingFuncs); } } // TODO Can this happen? printWarningMessage("[SCCComputer] No viable SCC has been found."); FuncSet scc; ShPtr<Function> func(*(remainingFuncs.begin())); scc.insert(func); return SCCWithRepresent(scc, func); }
// // 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; } }