blob: 9fd7d607e146667bab5a7731103fe94f62a5dc8c [file] [log] [blame]
Chris Lattnerbb2a28f2002-03-26 22:39:06 +00001//===- 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//
22static 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
30static 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
75static 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 Lattnerea4af652002-03-27 19:44:33 +000082 Shadow->resetCriticalMark();
Chris Lattnerbb2a28f2002-03-26 22:39:06 +000083
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 Lattnerbb2a28f2002-03-26 22:39:06 +000089 // 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 Lattnerea4af652002-03-27 19:44:33 +000096 PointerValSet PVSx;
97 PVSx.add(Node);
98 copyEdgesFromTo(ShadNode, PVSx);
Chris Lattnerbb2a28f2002-03-26 22:39:06 +000099
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//
137static 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//
149static 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//
166void 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 Lattnerea4af652002-03-27 19:44:33 +0000203 unsigned StartShadowNodes = ShadowNodes.size();
204
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000205 // 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 Lattnerea4af652002-03-27 19:44:33 +0000211 // 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 Lattnerbb2a28f2002-03-26 22:39:06 +0000217 } 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 Lattnerdf8af1c2002-03-27 00:53:57 +0000231 // are seperated by a single shadow node, but that shadow node might get
232 // eliminated in the process of optimization.
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000233 //
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 Lattnerdf8af1c2002-03-27 00:53:57 +0000237 while (!isa<ArgDSNode>(Nodes[ArgOffset])) // Scan for next arg node
238 ArgOffset++;
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000239 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 Lattnerdf8af1c2002-03-27 00:53:57 +0000247 if (StartNode) { // Not Self recursion?
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000248 // 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 Lattnerea4af652002-03-27 19:44:33 +0000253 } else {
254 ArgOffset++; // Step to the next argument...
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000255 }
256 }
257 }
258
Chris Lattnerea4af652002-03-27 19:44:33 +0000259 // 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 Lattnerbb2a28f2002-03-26 22:39:06 +0000277 // Now the call node is completely destructable. Eliminate it now.
278 delete CN;
279
Chris Lattnerdf8af1c2002-03-27 00:53:57 +0000280 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 Lattnerbb2a28f2002-03-26 22:39:06 +0000286
Chris Lattnerdf8af1c2002-03-27 00:53:57 +0000287 // Eliminate shadow nodes that are now extraneous due to linking...
288 Changed |= RemoveUnreachableShadowNodes();
289 }
Chris Lattnerbb2a28f2002-03-26 22:39:06 +0000290
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}