From 301764e28ce035c93b7fa13af59ec0f2f2e51103 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Thu, 24 Mar 2005 23:06:02 +0000 Subject: [PATCH] This replaces the correct but slow code with a more aggressive scc-finder based approach to find globals and call sites that need to be copied. This speeds up the BU pass on 176.gcc from 22s back up to 2.3s. Not as good as 1.5s, but at least it's correct :) llvm-svn: 20820 --- .../Analysis/DataStructure/DataStructure.cpp | 159 +++++++++++------- 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/llvm/lib/Analysis/DataStructure/DataStructure.cpp b/llvm/lib/Analysis/DataStructure/DataStructure.cpp index ae4d51b3435a..e0833c19621f 100644 --- a/llvm/lib/Analysis/DataStructure/DataStructure.cpp +++ b/llvm/lib/Analysis/DataStructure/DataStructure.cpp @@ -1320,65 +1320,109 @@ void DSGraph::getFunctionArgumentsForCall(Function *F, } } -/// PathExistsToClonedNode - Return true if there is a path from this node to a -/// node cloned by RC that does not go through another global node. Use the -/// NodeInfo map to cache information so this is an efficient depth first -/// traversal. -static bool PathExistsToClonedNode(const DSNode *N, ReachabilityCloner &RC, - std::map &NodeInfo) { - std::map::iterator I = NodeInfo.find(N); - if (I != NodeInfo.end()) - return I->second; - - // FIXME: we are potentially re-scc'ing chunks of the graph for all of the - // roots! We need an SCC iterator that supports multiple roots. - // - // FIXME: This should stop traversal of SCCs when we find something in RC! - scc_iterator SCCI = scc_begin(N), SCCE = scc_end(N); - for (; SCCI != SCCE; ++SCCI) { - std::vector &SCC = *SCCI; - assert(!SCC.empty() && "empty scc??"); - - if (NodeInfo.count(SCC[0])) - continue; // already processed. - - bool SCCReachesClonedNode = false; - - for (unsigned i = 0, e = SCC.size(); i != e; ++i) { - const DSNode *N = SCC[i]; - - if (RC.hasClonedNode(N)) { - SCCReachesClonedNode = true; - goto OutOfLoop; - } - - for (DSNode::const_edge_iterator EI = N->edge_begin(), E = N->edge_end(); - EI != E; ++EI) - if (const DSNode *Succ = EI->getNode()) - if (NodeInfo[Succ]) { - SCCReachesClonedNode = true; - goto OutOfLoop; - } +namespace { + // HackedGraphSCCFinder - This is used to find nodes that have a path from the + // node to a node cloned by the ReachabilityCloner object contained. To be + // extra obnoxious it ignores edges from nodes that are globals, and truncates + // search at RC marked nodes. This is designed as an object so that + // intermediate results can be memoized across invocations of + // PathExistsToClonedNode. + struct HackedGraphSCCFinder { + ReachabilityCloner &RC; + unsigned CurNodeId; + std::vector SCCStack; + std::map > NodeInfo; + + HackedGraphSCCFinder(ReachabilityCloner &rc) : RC(rc), CurNodeId(1) { + // Remove null pointer as a special case. + NodeInfo[0] = std::make_pair(0, false); } - OutOfLoop: - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - NodeInfo[SCC[i]] = SCCReachesClonedNode; + std::pair &VisitForSCCs(const DSNode *N); + + bool PathExistsToClonedNode(const DSNode *N) { + return VisitForSCCs(N).second; + } + + bool PathExistsToClonedNode(const DSCallSite &CS) { + if (PathExistsToClonedNode(CS.getRetVal().getNode())) + return true; + for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) + if (PathExistsToClonedNode(CS.getPtrArg(i).getNode())) + return true; + return false; + } + }; +} + +std::pair &HackedGraphSCCFinder:: +VisitForSCCs(const DSNode *N) { + std::map >::iterator + NodeInfoIt = NodeInfo.lower_bound(N); + if (NodeInfoIt != NodeInfo.end() && NodeInfoIt->first == N) + return NodeInfoIt->second; + + unsigned Min = CurNodeId++; + unsigned MyId = Min; + std::pair &ThisNodeInfo = + NodeInfo.insert(NodeInfoIt, + std::make_pair(N, std::make_pair(MyId, false)))->second; + + // Base case: if we find a global, this doesn't reach the cloned graph + // portion. + if (N->isGlobalNode()) { + ThisNodeInfo.second = false; + return ThisNodeInfo; } - return NodeInfo[N]; -} + // Base case: if this does reach the cloned graph portion... it does. :) + if (RC.hasClonedNode(N)) { + ThisNodeInfo.second = true; + return ThisNodeInfo; + } -static bool PathExistsToClonedNode(const DSCallSite &CS, ReachabilityCloner &RC, - std::map &NodeInfo) { - if (PathExistsToClonedNode(CS.getRetVal().getNode(), RC, NodeInfo)) - return true; - for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) - if (PathExistsToClonedNode(CS.getPtrArg(i).getNode(), RC, NodeInfo)) - return true; - return false; -} + SCCStack.push_back(N); + // Otherwise, check all successors. + bool AnyDirectSuccessorsReachClonedNodes = false; + for (DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end(); + EI != EE; ++EI) { + std::pair &SuccInfo = VisitForSCCs(EI->getNode()); + if (SuccInfo.first < Min) Min = SuccInfo.first; + AnyDirectSuccessorsReachClonedNodes |= SuccInfo.second; + } + + if (Min != MyId) + return ThisNodeInfo; // Part of a large SCC. Leave self on stack. + + if (SCCStack.back() == N) { // Special case single node SCC. + SCCStack.pop_back(); + ThisNodeInfo.second = AnyDirectSuccessorsReachClonedNodes; + return ThisNodeInfo; + } + + // Find out if any direct successors of any node reach cloned nodes. + if (!AnyDirectSuccessorsReachClonedNodes) + for (unsigned i = SCCStack.size()-1; SCCStack[i] != N; --i) + for (DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end(); + EI != EE; ++EI) + if (DSNode *N = EI->getNode()) + if (NodeInfo[N].second) { + AnyDirectSuccessorsReachClonedNodes = true; + goto OutOfLoop; + } +OutOfLoop: + // If any successor reaches a cloned node, mark all nodes in this SCC as + // reaching the cloned node. + if (AnyDirectSuccessorsReachClonedNodes) + while (SCCStack.back() != N) { + NodeInfo[SCCStack.back()].second = true; + SCCStack.pop_back(); + } + SCCStack.pop_back(); + ThisNodeInfo.second = true; + return ThisNodeInfo; +} /// mergeInCallFromOtherGraph - This graph merges in the minimal number of /// nodes from G2 into 'this' graph, merging the bindings specified by the @@ -1438,21 +1482,20 @@ void DSGraph::mergeInGraph(const DSCallSite &CS, // NodesReachCopiedNodes - Memoize results for efficiency. Contains a // true/false value for every visited node that reaches a copied node without // going through a global. - std::map NodesReachCopiedNodes; - NodesReachCopiedNodes[0] = false; // Initialize null. + HackedGraphSCCFinder SCCFinder(RC); if (!(CloneFlags & DontCloneAuxCallNodes)) for (afc_iterator I = Graph.afc_begin(), E = Graph.afc_end(); I!=E; ++I) - if (PathExistsToClonedNode(*I, RC, NodesReachCopiedNodes)) + if (SCCFinder.PathExistsToClonedNode(*I)) AuxCallToCopy.push_back(&*I); - DSScalarMap GSM = Graph.getScalarMap(); + const DSScalarMap &GSM = Graph.getScalarMap(); for (DSScalarMap::global_iterator GI = GSM.global_begin(), E = GSM.global_end(); GI != E; ++GI) { DSNode *GlobalNode = Graph.getNodeForValue(*GI).getNode(); for (DSNode::edge_iterator EI = GlobalNode->edge_begin(), EE = GlobalNode->edge_end(); EI != EE; ++EI) - if (PathExistsToClonedNode(EI->getNode(), RC, NodesReachCopiedNodes)) { + if (SCCFinder.PathExistsToClonedNode(EI->getNode())) { GlobalsToCopy.push_back(*GI); break; }