//===- ComputeClosure.cpp - Implement interprocedural closing of graphs ---===// // // Compute the interprocedural closure of a data structure graph // //===----------------------------------------------------------------------===// // DEBUG_IP_CLOSURE - Define this to debug the act of linking up graphs //#define DEBUG_IP_CLOSURE 1 #include "llvm/Analysis/DataStructure.h" #include "llvm/iOther.h" #include "Support/STLExtras.h" #include #ifdef DEBUG_IP_CLOSURE #include "llvm/Assembly/Writer.h" #endif // copyEdgesFromTo - Make a copy of all of the edges to Node to also point // PV. If there are edges out of Node, the edges are added to the subgraph // starting at PV. // static void copyEdgesFromTo(DSNode *Node, const PointerValSet &PVS) { // Make all of the pointers that pointed to Node now also point to PV... const vector &PVSToUpdate(Node->getReferrers()); for (unsigned i = 0, e = PVSToUpdate.size(); i != e; ++i) for (unsigned pn = 0, pne = PVS.size(); pn != pne; ++pn) PVSToUpdate[i]->add(PVS[pn]); } static void CalculateNodeMapping(ShadowDSNode *Shadow, DSNode *Node, multimap &NodeMapping) { #ifdef DEBUG_IP_CLOSURE cerr << "Mapping " << (void*)Shadow << " to " << (void*)Node << "\n"; cerr << "Type = '" << Shadow->getType() << "' and '" << Node->getType() << "'\n"; cerr << "Shadow Node:\n"; Shadow->print(cerr); cerr << "\nMapped Node:\n"; Node->print(cerr); #endif assert(Shadow->getType() == Node->getType() && "Shadow and mapped nodes disagree about type!"); multimap::iterator NI = NodeMapping.lower_bound(Shadow), NE = NodeMapping.upper_bound(Shadow); for (; NI != NE; ++NI) if (NI->second == Node) return; // Already processed node, return. NodeMapping.insert(make_pair(Shadow, Node)); // Add a mapping... // Loop over all of the outgoing links in the shadow node... // assert(Node->getNumLinks() == Shadow->getNumLinks() && "Same type, but different number of links?"); for (unsigned i = 0, e = Shadow->getNumLinks(); i != e; ++i) { PointerValSet &Link = Shadow->getLink(i); // Loop over all of the values coming out of this pointer... for (unsigned l = 0, le = Link.size(); l != le; ++l) { // If the outgoing node points to a shadow node, map the shadow node to // all of the outgoing values in Node. // if (ShadowDSNode *ShadOut = dyn_cast(Link[l].Node)) { PointerValSet &NLink = Node->getLink(i); for (unsigned ol = 0, ole = NLink.size(); ol != ole; ++ol) CalculateNodeMapping(ShadOut, NLink[ol].Node, NodeMapping); } } } } static void ResolveNodesTo(const PointerVal &FromPtr, const PointerValSet &ToVals) { assert(FromPtr.Index == 0 && "Resolved node return pointer should be index 0!"); if (!isa(FromPtr.Node)) return; ShadowDSNode *Shadow = cast(FromPtr.Node); typedef multimap ShadNodeMapTy; ShadNodeMapTy NodeMapping; for (unsigned i = 0, e = ToVals.size(); i != e; ++i) CalculateNodeMapping(Shadow, ToVals[i].Node, NodeMapping); copyEdgesFromTo(Shadow, ToVals); // Now loop through the shadow node graph, mirroring the edges in the shadow // graph onto the realized graph... // for (ShadNodeMapTy::iterator I = NodeMapping.begin(), E = NodeMapping.end(); I != E; ++I) { DSNode *Node = I->second; ShadowDSNode *ShadNode = I->first; // Must loop over edges in the shadow graph, adding edges in the real graph // that correspond to to the edges, but are mapped into real values by the // NodeMapping. // for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) { const PointerValSet &ShadLinks = ShadNode->getLink(i); PointerValSet &NewLinks = Node->getLink(i); // Add a link to all of the nodes pointed to by the shadow field... for (unsigned l = 0, le = ShadLinks.size(); l != le; ++l) { DSNode *ShadLink = ShadLinks[l].Node; if (ShadowDSNode *SL = dyn_cast(ShadLink)) { // Loop over all of the values in the range ShadNodeMapTy::iterator St = NodeMapping.lower_bound(SL), En = NodeMapping.upper_bound(SL); if (St != En) { for (; St != En; ++St) NewLinks.add(PointerVal(St->second, ShadLinks[l].Index)); } else { // We must retain the shadow node... NewLinks.add(ShadLinks[l]); } } else { // Otherwise, add a direct link to the data structure pointed to by // the shadow node... NewLinks.add(ShadLinks[l]); } } } } } // ResolveNodeTo - The specified node is now known to point to the set of values // in ToVals, instead of the old shadow node subgraph that it was pointing to. // static void ResolveNodeTo(DSNode *Node, const PointerValSet &ToVals) { assert(Node->getNumLinks() == 1 && "Resolved node can only be a scalar!!"); PointerValSet PVS = Node->getLink(0); for (unsigned i = 0, e = PVS.size(); i != e; ++i) ResolveNodesTo(PVS[i], ToVals); } // isResolvableCallNode - Return true if node is a call node and it is a call // node that we can inline... // static bool isResolvableCallNode(DSNode *N) { // Only operate on call nodes... CallDSNode *CN = dyn_cast(N); if (CN == 0) return false; // Only operate on call nodes with direct method calls Function *F = CN->getCall()->getCalledFunction(); if (F == 0) return false; // Only work on call nodes with direct calls to methods with bodies. return !F->isExternal(); } // computeClosure - Replace all of the resolvable call nodes with the contents // of their corresponding method data structure graph... // void FunctionDSGraph::computeClosure(const DataStructure &DS) { vector::iterator NI = std::find_if(Nodes.begin(), Nodes.end(), isResolvableCallNode); map InlineCount; // FIXME // Loop over the resolvable call nodes... while (NI != Nodes.end()) { CallDSNode *CN = cast(*NI); Function *F = CN->getCall()->getCalledFunction(); //if (F == Func) return; // Do not do self inlining // FIXME: Gross hack to prevent explosions when inlining a recursive func. if (InlineCount[F]++ > 2) return; Nodes.erase(NI); // Remove the call node from the graph unsigned CallNodeOffset = NI-Nodes.begin(); // StartNode - The first node of the incorporated graph, last node of the // preexisting data structure graph... // unsigned StartNode = Nodes.size(); // Hold the set of values that correspond to the incorporated methods // return set. // PointerValSet RetVals; if (F != Func) { // If this is not a recursive call... // Get the datastructure graph for the new method. Note that we are not // allowed to modify this graph because it will be the cached graph that // is returned by other users that want the local datastructure graph for // a method. // const FunctionDSGraph &NewFunction = DS.getDSGraph(F); // Incorporate a copy of the called function graph into the current graph, // allowing us to do local transformations to local graph to link // arguments to call values, and call node to return value... // RetVals = cloneFunctionIntoSelf(NewFunction, false); } else { // We are looking at a recursive function! StartNode = 0; // Arg nodes start at 0 now... RetVals = RetNode; } // If the function returns a pointer value... Resolve values pointing to // the shadow nodes pointed to by CN to now point the values in RetVals... // if (CN->getNumLinks()) ResolveNodeTo(CN, RetVals); // If the call node has arguments, process them now! if (CN->getNumArgs()) { // The ArgNodes of the incorporated graph should be the nodes starting at // StartNode, ordered the same way as the call arguments. The arg nodes // are seperated by a single shadow node, so we need to be sure to step // over them. // unsigned ArgOffset = StartNode; for (unsigned i = 0, e = CN->getNumArgs(); i != e; ++i) { // Get the arg node of the incorporated method... ArgDSNode *ArgNode = cast(Nodes[ArgOffset]); // Now we make all of the nodes inside of the incorporated method point // to the real arguments values, not to the shadow nodes for the // argument. // ResolveNodeTo(ArgNode, CN->getArgValues(i)); if (StartNode == 0) { // Self recursion? ArgOffset += 2; // Skip over the argument & the shadow node... } else { // Remove the argnode from the set of nodes in this method... Nodes.erase(Nodes.begin()+ArgOffset); // ArgNode is no longer useful, delete now! delete ArgNode; ArgOffset++; // Skip over the shadow node for the argument } } } // Now the call node is completely destructable. Eliminate it now. delete CN; // Eliminate shadow nodes that are not distinguishable from some other // node in the graph... // UnlinkUndistinguishableShadowNodes(); // Eliminate shadow nodes that are now extraneous due to linking... RemoveUnreachableShadowNodes(); //if (F == Func) return; // Only do one self inlining // Move on to the next call node... NI = std::find_if(Nodes.begin(), Nodes.end(), isResolvableCallNode); } }