blob: 93ba1a8a0bf41e7bd3d0c98e4eda7130888a862d [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);
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//
135static 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//
147static 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//
164void 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}