Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 1 | //===- ComputeClosure.cpp - Implement interprocedural closing of graphs ---===// |
| 2 | // |
| 3 | // Compute the interprocedural closure of a data structure graph |
| 4 | // |
| 5 | //===----------------------------------------------------------------------===// |
| 6 | |
| 7 | // DEBUG_IP_CLOSURE - Define this to debug the act of linking up graphs |
| 8 | //#define DEBUG_IP_CLOSURE 1 |
| 9 | |
| 10 | #include "llvm/Analysis/DataStructure.h" |
| 11 | #include "llvm/iOther.h" |
| 12 | #include "Support/STLExtras.h" |
| 13 | #include <algorithm> |
| 14 | #ifdef DEBUG_IP_CLOSURE |
| 15 | #include "llvm/Assembly/Writer.h" |
| 16 | #endif |
| 17 | |
| 18 | // copyEdgesFromTo - Make a copy of all of the edges to Node to also point |
| 19 | // PV. If there are edges out of Node, the edges are added to the subgraph |
| 20 | // starting at PV. |
| 21 | // |
| 22 | static void copyEdgesFromTo(DSNode *Node, const PointerValSet &PVS) { |
| 23 | // Make all of the pointers that pointed to Node now also point to PV... |
| 24 | const vector<PointerValSet*> &PVSToUpdate(Node->getReferrers()); |
| 25 | for (unsigned i = 0, e = PVSToUpdate.size(); i != e; ++i) |
| 26 | for (unsigned pn = 0, pne = PVS.size(); pn != pne; ++pn) |
| 27 | PVSToUpdate[i]->add(PVS[pn]); |
| 28 | } |
| 29 | |
| 30 | static void CalculateNodeMapping(ShadowDSNode *Shadow, DSNode *Node, |
| 31 | multimap<ShadowDSNode *, DSNode *> &NodeMapping) { |
| 32 | #ifdef DEBUG_IP_CLOSURE |
| 33 | cerr << "Mapping " << (void*)Shadow << " to " << (void*)Node << "\n"; |
| 34 | cerr << "Type = '" << Shadow->getType() << "' and '" |
| 35 | << Node->getType() << "'\n"; |
| 36 | cerr << "Shadow Node:\n"; |
| 37 | Shadow->print(cerr); |
| 38 | cerr << "\nMapped Node:\n"; |
| 39 | Node->print(cerr); |
| 40 | #endif |
| 41 | assert(Shadow->getType() == Node->getType() && |
| 42 | "Shadow and mapped nodes disagree about type!"); |
| 43 | |
| 44 | multimap<ShadowDSNode *, DSNode *>::iterator |
| 45 | NI = NodeMapping.lower_bound(Shadow), |
| 46 | NE = NodeMapping.upper_bound(Shadow); |
| 47 | |
| 48 | for (; NI != NE; ++NI) |
| 49 | if (NI->second == Node) return; // Already processed node, return. |
| 50 | |
| 51 | NodeMapping.insert(make_pair(Shadow, Node)); // Add a mapping... |
| 52 | |
| 53 | // Loop over all of the outgoing links in the shadow node... |
| 54 | // |
| 55 | assert(Node->getNumLinks() == Shadow->getNumLinks() && |
| 56 | "Same type, but different number of links?"); |
| 57 | for (unsigned i = 0, e = Shadow->getNumLinks(); i != e; ++i) { |
| 58 | PointerValSet &Link = Shadow->getLink(i); |
| 59 | |
| 60 | // Loop over all of the values coming out of this pointer... |
| 61 | for (unsigned l = 0, le = Link.size(); l != le; ++l) { |
| 62 | // If the outgoing node points to a shadow node, map the shadow node to |
| 63 | // all of the outgoing values in Node. |
| 64 | // |
| 65 | if (ShadowDSNode *ShadOut = dyn_cast<ShadowDSNode>(Link[l].Node)) { |
| 66 | PointerValSet &NLink = Node->getLink(i); |
| 67 | for (unsigned ol = 0, ole = NLink.size(); ol != ole; ++ol) |
| 68 | CalculateNodeMapping(ShadOut, NLink[ol].Node, NodeMapping); |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | |
| 75 | static void ResolveNodesTo(const PointerVal &FromPtr, |
| 76 | const PointerValSet &ToVals) { |
| 77 | assert(FromPtr.Index == 0 && |
| 78 | "Resolved node return pointer should be index 0!"); |
| 79 | if (!isa<ShadowDSNode>(FromPtr.Node)) return; |
| 80 | |
| 81 | ShadowDSNode *Shadow = cast<ShadowDSNode>(FromPtr.Node); |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 82 | Shadow->resetCriticalMark(); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 83 | |
| 84 | typedef multimap<ShadowDSNode *, DSNode *> ShadNodeMapTy; |
| 85 | ShadNodeMapTy NodeMapping; |
| 86 | for (unsigned i = 0, e = ToVals.size(); i != e; ++i) |
| 87 | CalculateNodeMapping(Shadow, ToVals[i].Node, NodeMapping); |
| 88 | |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 89 | // Now loop through the shadow node graph, mirroring the edges in the shadow |
| 90 | // graph onto the realized graph... |
| 91 | // |
| 92 | for (ShadNodeMapTy::iterator I = NodeMapping.begin(), |
| 93 | E = NodeMapping.end(); I != E; ++I) { |
| 94 | DSNode *Node = I->second; |
| 95 | ShadowDSNode *ShadNode = I->first; |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 96 | PointerValSet PVSx; |
| 97 | PVSx.add(Node); |
| 98 | copyEdgesFromTo(ShadNode, PVSx); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 99 | |
| 100 | // Must loop over edges in the shadow graph, adding edges in the real graph |
| 101 | // that correspond to to the edges, but are mapped into real values by the |
| 102 | // NodeMapping. |
| 103 | // |
| 104 | for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) { |
| 105 | const PointerValSet &ShadLinks = ShadNode->getLink(i); |
| 106 | PointerValSet &NewLinks = Node->getLink(i); |
| 107 | |
| 108 | // Add a link to all of the nodes pointed to by the shadow field... |
| 109 | for (unsigned l = 0, le = ShadLinks.size(); l != le; ++l) { |
| 110 | DSNode *ShadLink = ShadLinks[l].Node; |
| 111 | |
| 112 | if (ShadowDSNode *SL = dyn_cast<ShadowDSNode>(ShadLink)) { |
| 113 | // Loop over all of the values in the range |
| 114 | ShadNodeMapTy::iterator St = NodeMapping.lower_bound(SL), |
| 115 | En = NodeMapping.upper_bound(SL); |
| 116 | if (St != En) { |
| 117 | for (; St != En; ++St) |
| 118 | NewLinks.add(PointerVal(St->second, ShadLinks[l].Index)); |
| 119 | } else { |
| 120 | // We must retain the shadow node... |
| 121 | NewLinks.add(ShadLinks[l]); |
| 122 | } |
| 123 | } else { |
| 124 | // Otherwise, add a direct link to the data structure pointed to by |
| 125 | // the shadow node... |
| 126 | NewLinks.add(ShadLinks[l]); |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | |
| 134 | // ResolveNodeTo - The specified node is now known to point to the set of values |
| 135 | // in ToVals, instead of the old shadow node subgraph that it was pointing to. |
| 136 | // |
| 137 | static void ResolveNodeTo(DSNode *Node, const PointerValSet &ToVals) { |
| 138 | assert(Node->getNumLinks() == 1 && "Resolved node can only be a scalar!!"); |
| 139 | |
| 140 | PointerValSet PVS = Node->getLink(0); |
| 141 | |
| 142 | for (unsigned i = 0, e = PVS.size(); i != e; ++i) |
| 143 | ResolveNodesTo(PVS[i], ToVals); |
| 144 | } |
| 145 | |
| 146 | // isResolvableCallNode - Return true if node is a call node and it is a call |
| 147 | // node that we can inline... |
| 148 | // |
| 149 | static bool isResolvableCallNode(DSNode *N) { |
| 150 | // Only operate on call nodes... |
| 151 | CallDSNode *CN = dyn_cast<CallDSNode>(N); |
| 152 | if (CN == 0) return false; |
| 153 | |
| 154 | // Only operate on call nodes with direct method calls |
| 155 | Function *F = CN->getCall()->getCalledFunction(); |
| 156 | if (F == 0) return false; |
| 157 | |
| 158 | // Only work on call nodes with direct calls to methods with bodies. |
| 159 | return !F->isExternal(); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | // computeClosure - Replace all of the resolvable call nodes with the contents |
| 164 | // of their corresponding method data structure graph... |
| 165 | // |
| 166 | void FunctionDSGraph::computeClosure(const DataStructure &DS) { |
| 167 | vector<DSNode*>::iterator NI = std::find_if(Nodes.begin(), Nodes.end(), |
| 168 | isResolvableCallNode); |
| 169 | |
| 170 | map<Function*, unsigned> InlineCount; // FIXME |
| 171 | |
| 172 | // Loop over the resolvable call nodes... |
| 173 | while (NI != Nodes.end()) { |
| 174 | CallDSNode *CN = cast<CallDSNode>(*NI); |
| 175 | Function *F = CN->getCall()->getCalledFunction(); |
| 176 | //if (F == Func) return; // Do not do self inlining |
| 177 | |
| 178 | // FIXME: Gross hack to prevent explosions when inlining a recursive func. |
| 179 | if (InlineCount[F]++ > 2) return; |
| 180 | |
| 181 | Nodes.erase(NI); // Remove the call node from the graph |
| 182 | |
| 183 | unsigned CallNodeOffset = NI-Nodes.begin(); |
| 184 | |
| 185 | // StartNode - The first node of the incorporated graph, last node of the |
| 186 | // preexisting data structure graph... |
| 187 | // |
| 188 | unsigned StartNode = Nodes.size(); |
| 189 | |
| 190 | // Hold the set of values that correspond to the incorporated methods |
| 191 | // return set. |
| 192 | // |
| 193 | PointerValSet RetVals; |
| 194 | |
| 195 | if (F != Func) { // If this is not a recursive call... |
| 196 | // Get the datastructure graph for the new method. Note that we are not |
| 197 | // allowed to modify this graph because it will be the cached graph that |
| 198 | // is returned by other users that want the local datastructure graph for |
| 199 | // a method. |
| 200 | // |
| 201 | const FunctionDSGraph &NewFunction = DS.getDSGraph(F); |
| 202 | |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 203 | unsigned StartShadowNodes = ShadowNodes.size(); |
| 204 | |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 205 | // Incorporate a copy of the called function graph into the current graph, |
| 206 | // allowing us to do local transformations to local graph to link |
| 207 | // arguments to call values, and call node to return value... |
| 208 | // |
| 209 | RetVals = cloneFunctionIntoSelf(NewFunction, false); |
| 210 | |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 211 | // Only detail is that we need to reset all of the critical shadow nodes |
| 212 | // in the incorporated graph, because they are now no longer critical. |
| 213 | // |
| 214 | for (unsigned i = StartShadowNodes, e = ShadowNodes.size(); i != e; ++i) |
| 215 | ShadowNodes[i]->resetCriticalMark(); |
| 216 | |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 217 | } else { // We are looking at a recursive function! |
| 218 | StartNode = 0; // Arg nodes start at 0 now... |
| 219 | RetVals = RetNode; |
| 220 | } |
| 221 | |
| 222 | // If the function returns a pointer value... Resolve values pointing to |
| 223 | // the shadow nodes pointed to by CN to now point the values in RetVals... |
| 224 | // |
| 225 | if (CN->getNumLinks()) ResolveNodeTo(CN, RetVals); |
| 226 | |
| 227 | // If the call node has arguments, process them now! |
| 228 | if (CN->getNumArgs()) { |
| 229 | // The ArgNodes of the incorporated graph should be the nodes starting at |
| 230 | // StartNode, ordered the same way as the call arguments. The arg nodes |
Chris Lattner | df8af1c | 2002-03-27 00:53:57 +0000 | [diff] [blame] | 231 | // are seperated by a single shadow node, but that shadow node might get |
| 232 | // eliminated in the process of optimization. |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 233 | // |
| 234 | unsigned ArgOffset = StartNode; |
| 235 | for (unsigned i = 0, e = CN->getNumArgs(); i != e; ++i) { |
| 236 | // Get the arg node of the incorporated method... |
Chris Lattner | df8af1c | 2002-03-27 00:53:57 +0000 | [diff] [blame] | 237 | while (!isa<ArgDSNode>(Nodes[ArgOffset])) // Scan for next arg node |
| 238 | ArgOffset++; |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 239 | ArgDSNode *ArgNode = cast<ArgDSNode>(Nodes[ArgOffset]); |
| 240 | |
| 241 | // Now we make all of the nodes inside of the incorporated method point |
| 242 | // to the real arguments values, not to the shadow nodes for the |
| 243 | // argument. |
| 244 | // |
| 245 | ResolveNodeTo(ArgNode, CN->getArgValues(i)); |
| 246 | |
Chris Lattner | df8af1c | 2002-03-27 00:53:57 +0000 | [diff] [blame] | 247 | if (StartNode) { // Not Self recursion? |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 248 | // Remove the argnode from the set of nodes in this method... |
| 249 | Nodes.erase(Nodes.begin()+ArgOffset); |
| 250 | |
| 251 | // ArgNode is no longer useful, delete now! |
| 252 | delete ArgNode; |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 253 | } else { |
| 254 | ArgOffset++; // Step to the next argument... |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 255 | } |
| 256 | } |
| 257 | } |
| 258 | |
Chris Lattner | ea4af65 | 2002-03-27 19:44:33 +0000 | [diff] [blame] | 259 | // Loop through the nodes, deleting alloc nodes in the inlined function... |
| 260 | // Since the memory has been released, we cannot access their pointer |
| 261 | // fields (with defined results at least), so it is not possible to use any |
| 262 | // pointers to the alloca. Drop them now, and remove the alloca's since |
| 263 | // they are dead (we just removed all links to them). Only do this if we |
| 264 | // are not self recursing though. :) |
| 265 | // |
| 266 | if (StartNode) // Don't do this if self recursing... |
| 267 | for (unsigned i = StartNode; i != Nodes.size(); ++i) |
| 268 | if (NewDSNode *NDS = dyn_cast<NewDSNode>(Nodes[i])) |
| 269 | if (NDS->isAllocaNode()) { |
| 270 | NDS->removeAllIncomingEdges(); // These edges are invalid now! |
| 271 | delete NDS; // Node is dead |
| 272 | Nodes.erase(Nodes.begin()+i); // Remove slot in Nodes array |
| 273 | --i; // Don't skip the next node |
| 274 | } |
| 275 | |
| 276 | |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 277 | // Now the call node is completely destructable. Eliminate it now. |
| 278 | delete CN; |
| 279 | |
Chris Lattner | df8af1c | 2002-03-27 00:53:57 +0000 | [diff] [blame] | 280 | bool Changed = true; |
| 281 | while (Changed) { |
| 282 | // Eliminate shadow nodes that are not distinguishable from some other |
| 283 | // node in the graph... |
| 284 | // |
| 285 | Changed = UnlinkUndistinguishableShadowNodes(); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 286 | |
Chris Lattner | df8af1c | 2002-03-27 00:53:57 +0000 | [diff] [blame] | 287 | // Eliminate shadow nodes that are now extraneous due to linking... |
| 288 | Changed |= RemoveUnreachableShadowNodes(); |
| 289 | } |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 290 | |
| 291 | //if (F == Func) return; // Only do one self inlining |
| 292 | |
| 293 | // Move on to the next call node... |
| 294 | NI = std::find_if(Nodes.begin(), Nodes.end(), isResolvableCallNode); |
| 295 | } |
| 296 | } |