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); |
| 82 | |
| 83 | typedef multimap<ShadowDSNode *, DSNode *> ShadNodeMapTy; |
| 84 | ShadNodeMapTy NodeMapping; |
| 85 | for (unsigned i = 0, e = ToVals.size(); i != e; ++i) |
| 86 | CalculateNodeMapping(Shadow, ToVals[i].Node, NodeMapping); |
| 87 | |
| 88 | copyEdgesFromTo(Shadow, ToVals); |
| 89 | |
| 90 | // Now loop through the shadow node graph, mirroring the edges in the shadow |
| 91 | // graph onto the realized graph... |
| 92 | // |
| 93 | for (ShadNodeMapTy::iterator I = NodeMapping.begin(), |
| 94 | E = NodeMapping.end(); I != E; ++I) { |
| 95 | DSNode *Node = I->second; |
| 96 | ShadowDSNode *ShadNode = I->first; |
| 97 | |
| 98 | // Must loop over edges in the shadow graph, adding edges in the real graph |
| 99 | // that correspond to to the edges, but are mapped into real values by the |
| 100 | // NodeMapping. |
| 101 | // |
| 102 | for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) { |
| 103 | const PointerValSet &ShadLinks = ShadNode->getLink(i); |
| 104 | PointerValSet &NewLinks = Node->getLink(i); |
| 105 | |
| 106 | // Add a link to all of the nodes pointed to by the shadow field... |
| 107 | for (unsigned l = 0, le = ShadLinks.size(); l != le; ++l) { |
| 108 | DSNode *ShadLink = ShadLinks[l].Node; |
| 109 | |
| 110 | if (ShadowDSNode *SL = dyn_cast<ShadowDSNode>(ShadLink)) { |
| 111 | // Loop over all of the values in the range |
| 112 | ShadNodeMapTy::iterator St = NodeMapping.lower_bound(SL), |
| 113 | En = NodeMapping.upper_bound(SL); |
| 114 | if (St != En) { |
| 115 | for (; St != En; ++St) |
| 116 | NewLinks.add(PointerVal(St->second, ShadLinks[l].Index)); |
| 117 | } else { |
| 118 | // We must retain the shadow node... |
| 119 | NewLinks.add(ShadLinks[l]); |
| 120 | } |
| 121 | } else { |
| 122 | // Otherwise, add a direct link to the data structure pointed to by |
| 123 | // the shadow node... |
| 124 | NewLinks.add(ShadLinks[l]); |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | |
| 132 | // ResolveNodeTo - The specified node is now known to point to the set of values |
| 133 | // in ToVals, instead of the old shadow node subgraph that it was pointing to. |
| 134 | // |
| 135 | static void ResolveNodeTo(DSNode *Node, const PointerValSet &ToVals) { |
| 136 | assert(Node->getNumLinks() == 1 && "Resolved node can only be a scalar!!"); |
| 137 | |
| 138 | PointerValSet PVS = Node->getLink(0); |
| 139 | |
| 140 | for (unsigned i = 0, e = PVS.size(); i != e; ++i) |
| 141 | ResolveNodesTo(PVS[i], ToVals); |
| 142 | } |
| 143 | |
| 144 | // isResolvableCallNode - Return true if node is a call node and it is a call |
| 145 | // node that we can inline... |
| 146 | // |
| 147 | static bool isResolvableCallNode(DSNode *N) { |
| 148 | // Only operate on call nodes... |
| 149 | CallDSNode *CN = dyn_cast<CallDSNode>(N); |
| 150 | if (CN == 0) return false; |
| 151 | |
| 152 | // Only operate on call nodes with direct method calls |
| 153 | Function *F = CN->getCall()->getCalledFunction(); |
| 154 | if (F == 0) return false; |
| 155 | |
| 156 | // Only work on call nodes with direct calls to methods with bodies. |
| 157 | return !F->isExternal(); |
| 158 | } |
| 159 | |
| 160 | |
| 161 | // computeClosure - Replace all of the resolvable call nodes with the contents |
| 162 | // of their corresponding method data structure graph... |
| 163 | // |
| 164 | void FunctionDSGraph::computeClosure(const DataStructure &DS) { |
| 165 | vector<DSNode*>::iterator NI = std::find_if(Nodes.begin(), Nodes.end(), |
| 166 | isResolvableCallNode); |
| 167 | |
| 168 | map<Function*, unsigned> InlineCount; // FIXME |
| 169 | |
| 170 | // Loop over the resolvable call nodes... |
| 171 | while (NI != Nodes.end()) { |
| 172 | CallDSNode *CN = cast<CallDSNode>(*NI); |
| 173 | Function *F = CN->getCall()->getCalledFunction(); |
| 174 | //if (F == Func) return; // Do not do self inlining |
| 175 | |
| 176 | // FIXME: Gross hack to prevent explosions when inlining a recursive func. |
| 177 | if (InlineCount[F]++ > 2) return; |
| 178 | |
| 179 | Nodes.erase(NI); // Remove the call node from the graph |
| 180 | |
| 181 | unsigned CallNodeOffset = NI-Nodes.begin(); |
| 182 | |
| 183 | // StartNode - The first node of the incorporated graph, last node of the |
| 184 | // preexisting data structure graph... |
| 185 | // |
| 186 | unsigned StartNode = Nodes.size(); |
| 187 | |
| 188 | // Hold the set of values that correspond to the incorporated methods |
| 189 | // return set. |
| 190 | // |
| 191 | PointerValSet RetVals; |
| 192 | |
| 193 | if (F != Func) { // If this is not a recursive call... |
| 194 | // Get the datastructure graph for the new method. Note that we are not |
| 195 | // allowed to modify this graph because it will be the cached graph that |
| 196 | // is returned by other users that want the local datastructure graph for |
| 197 | // a method. |
| 198 | // |
| 199 | const FunctionDSGraph &NewFunction = DS.getDSGraph(F); |
| 200 | |
| 201 | // Incorporate a copy of the called function graph into the current graph, |
| 202 | // allowing us to do local transformations to local graph to link |
| 203 | // arguments to call values, and call node to return value... |
| 204 | // |
| 205 | RetVals = cloneFunctionIntoSelf(NewFunction, false); |
| 206 | |
| 207 | } else { // We are looking at a recursive function! |
| 208 | StartNode = 0; // Arg nodes start at 0 now... |
| 209 | RetVals = RetNode; |
| 210 | } |
| 211 | |
| 212 | // If the function returns a pointer value... Resolve values pointing to |
| 213 | // the shadow nodes pointed to by CN to now point the values in RetVals... |
| 214 | // |
| 215 | if (CN->getNumLinks()) ResolveNodeTo(CN, RetVals); |
| 216 | |
| 217 | // If the call node has arguments, process them now! |
| 218 | if (CN->getNumArgs()) { |
| 219 | // The ArgNodes of the incorporated graph should be the nodes starting at |
| 220 | // StartNode, ordered the same way as the call arguments. The arg nodes |
| 221 | // are seperated by a single shadow node, so we need to be sure to step |
| 222 | // over them. |
| 223 | // |
| 224 | unsigned ArgOffset = StartNode; |
| 225 | for (unsigned i = 0, e = CN->getNumArgs(); i != e; ++i) { |
| 226 | // Get the arg node of the incorporated method... |
| 227 | ArgDSNode *ArgNode = cast<ArgDSNode>(Nodes[ArgOffset]); |
| 228 | |
| 229 | // Now we make all of the nodes inside of the incorporated method point |
| 230 | // to the real arguments values, not to the shadow nodes for the |
| 231 | // argument. |
| 232 | // |
| 233 | ResolveNodeTo(ArgNode, CN->getArgValues(i)); |
| 234 | |
| 235 | if (StartNode == 0) { // Self recursion? |
| 236 | ArgOffset += 2; // Skip over the argument & the shadow node... |
| 237 | } else { |
| 238 | // Remove the argnode from the set of nodes in this method... |
| 239 | Nodes.erase(Nodes.begin()+ArgOffset); |
| 240 | |
| 241 | // ArgNode is no longer useful, delete now! |
| 242 | delete ArgNode; |
| 243 | |
| 244 | ArgOffset++; // Skip over the shadow node for the argument |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | // Now the call node is completely destructable. Eliminate it now. |
| 250 | delete CN; |
| 251 | |
| 252 | // Eliminate shadow nodes that are not distinguishable from some other |
| 253 | // node in the graph... |
| 254 | // |
| 255 | UnlinkUndistinguishableShadowNodes(); |
| 256 | |
| 257 | // Eliminate shadow nodes that are now extraneous due to linking... |
| 258 | RemoveUnreachableShadowNodes(); |
| 259 | |
| 260 | //if (F == Func) return; // Only do one self inlining |
| 261 | |
| 262 | // Move on to the next call node... |
| 263 | NI = std::find_if(Nodes.begin(), Nodes.end(), isResolvableCallNode); |
| 264 | } |
| 265 | } |