blob: 36a3d1763ac5c34eb58832009ce14f78c9ecf76a [file] [log] [blame]
Chris Lattner55c10582002-10-03 20:38:41 +00001//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===//
Chris Lattner0d9bab82002-07-18 00:12:30 +00002//
3// This file implements the BUDataStructures class, which represents the
4// Bottom-Up Interprocedural closure of the data structure graph over the
5// program. This is useful for applications like pool allocation, but **not**
Chris Lattner55c10582002-10-03 20:38:41 +00006// applications like alias analysis.
Chris Lattner0d9bab82002-07-18 00:12:30 +00007//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Analysis/DataStructure.h"
Chris Lattner55c10582002-10-03 20:38:41 +000011#include "llvm/Analysis/DSGraph.h"
Chris Lattner0d9bab82002-07-18 00:12:30 +000012#include "llvm/Module.h"
Chris Lattnerfccd06f2002-10-01 22:33:50 +000013#include "Support/Statistic.h"
Chris Lattner0d9bab82002-07-18 00:12:30 +000014using std::map;
15
Chris Lattner1e435162002-07-26 21:12:44 +000016static RegisterAnalysis<BUDataStructures>
Vikram S. Adve355e2ca2002-07-30 22:05:22 +000017X("budatastructure", "Bottom-up Data Structure Analysis Closure");
Chris Lattner0d9bab82002-07-18 00:12:30 +000018
Chris Lattnerb1060432002-11-07 05:20:53 +000019using namespace DS;
Chris Lattner55c10582002-10-03 20:38:41 +000020
Chris Lattneraa0b4682002-11-09 21:12:07 +000021// run - Calculate the bottom up data structure graphs for each function in the
22// program.
23//
24bool BUDataStructures::run(Module &M) {
25 GlobalsGraph = new DSGraph();
26
27 // Simply calculate the graphs for each function...
28 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
29 if (!I->isExternal())
Chris Lattnera1079052002-11-10 06:52:47 +000030 calculateGraph(*I, 0);
Chris Lattneraa0b4682002-11-09 21:12:07 +000031 return false;
32}
Chris Lattner55c10582002-10-03 20:38:41 +000033
Chris Lattner0d9bab82002-07-18 00:12:30 +000034// releaseMemory - If the pass pipeline is done with this pass, we can release
35// our memory... here...
36//
37void BUDataStructures::releaseMemory() {
Vikram S. Adve355e2ca2002-07-30 22:05:22 +000038 for (map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
Chris Lattner0d9bab82002-07-18 00:12:30 +000039 E = DSInfo.end(); I != E; ++I)
40 delete I->second;
41
42 // Empty map so next time memory is released, data structures are not
43 // re-deleted.
44 DSInfo.clear();
Chris Lattneraa0b4682002-11-09 21:12:07 +000045 delete GlobalsGraph;
46 GlobalsGraph = 0;
Chris Lattner0d9bab82002-07-18 00:12:30 +000047}
48
Chris Lattner8a5db462002-11-11 00:01:34 +000049
50// Return true if a graph was inlined
51// Can not modify the part of the AuxCallList < FirstResolvableCall.
52//
53bool BUDataStructures::ResolveFunctionCalls(DSGraph &G,
54 unsigned &FirstResolvableCall,
55 std::map<Function*, DSCallSite> &InProcess,
56 unsigned Indent) {
57 std::vector<DSCallSite> &FCs = G.getAuxFunctionCalls();
58 bool Changed = false;
59
60 // Loop while there are call sites that we can resolve!
61 while (FirstResolvableCall != FCs.size()) {
62 DSCallSite Call = FCs[FirstResolvableCall];
63
64 // If the function list is incomplete...
65 if (Call.getCallee().getNode()->NodeType & DSNode::Incomplete) {
66 // If incomplete, we cannot resolve it, so leave it at the beginning of
67 // the call list with the other unresolvable calls...
68 ++FirstResolvableCall;
69 } else {
70 // Start inlining all of the functions we can... some may not be
71 // inlinable if they are external...
72 //
73 const std::vector<GlobalValue*> &Callees =
74 Call.getCallee().getNode()->getGlobals();
75
76 bool hasExternalTarget = false;
77
78 // Loop over the functions, inlining whatever we can...
79 for (unsigned c = 0, e = Callees.size(); c != e; ++c) {
80 // Must be a function type, so this cast should succeed unless something
81 // really wierd is happening.
82 Function &FI = cast<Function>(*Callees[c]);
83
84 if (FI.getName() == "printf" || FI.getName() == "sscanf" ||
85 FI.getName() == "fprintf" || FI.getName() == "open" ||
86 FI.getName() == "sprintf" || FI.getName() == "fputs") {
87 // Ignore
88 } else if (FI.isExternal()) {
89 // If the function is external, then we cannot resolve this call site!
90 hasExternalTarget = true;
91 break;
92 } else {
93 std::map<Function*, DSCallSite>::iterator I =
94 InProcess.lower_bound(&FI);
95
96 if (I != InProcess.end() && I->first == &FI) { // Recursion detected?
97 // Merge two call sites to eliminate recursion...
98 Call.mergeWith(I->second);
99
100 DEBUG(std::cerr << std::string(Indent*2, ' ')
101 << "* Recursion detected for function " << FI.getName()<<"\n");
102 } else {
103 DEBUG(std::cerr << std::string(Indent*2, ' ')
104 << "Inlining: " << FI.getName() << "\n");
105
106 // Get the data structure graph for the called function, closing it
107 // if possible...
108 //
109 DSGraph &GI = calculateGraph(FI, Indent+1); // Graph to inline
110
111 DEBUG(std::cerr << std::string(Indent*2, ' ')
112 << "Got graph for: " << FI.getName() << "["
113 << GI.getGraphSize() << "+"
114 << GI.getAuxFunctionCalls().size() << "] "
115 << " in: " << G.getFunction().getName() << "["
116 << G.getGraphSize() << "+"
117 << G.getAuxFunctionCalls().size() << "]\n");
118
119 // Keep track of how many call sites are added by the inlining...
120 unsigned NumCalls = FCs.size();
121
122 // Resolve the arguments and return value
123 G.mergeInGraph(Call, GI, DSGraph::StripAllocaBit |
124 DSGraph::DontCloneCallNodes);
125
126 // Added a call site?
127 if (FCs.size() != NumCalls) {
128 // Otherwise we need to inline the graph. Temporarily add the
129 // current function to the InProcess map to be able to handle
130 // recursion successfully.
131 //
132 I = InProcess.insert(I, std::make_pair(&FI, Call));
133
134 // ResolveFunctionCalls - Resolve the function calls that just got
135 // inlined...
136 //
137 Changed |= ResolveFunctionCalls(G, NumCalls, InProcess, Indent+1);
138
139 // Now that we are done processing the inlined graph, remove our
140 // cycle detector record...
141 //
142 //InProcess.erase(I);
143 }
144 }
145 }
146 }
147
148 if (hasExternalTarget) {
149 // If we cannot resolve this call site...
150 ++FirstResolvableCall;
151 } else {
152 Changed = true;
153 FCs.erase(FCs.begin()+FirstResolvableCall);
154 }
155 }
156 }
157
158 return Changed;
159}
160
Chris Lattnera1079052002-11-10 06:52:47 +0000161DSGraph &BUDataStructures::calculateGraph(Function &F, unsigned Indent) {
Chris Lattner0d9bab82002-07-18 00:12:30 +0000162 // Make sure this graph has not already been calculated, or that we don't get
163 // into an infinite loop with mutually recursive functions.
164 //
Chris Lattner8a5db462002-11-11 00:01:34 +0000165 DSGraph *&GraphPtr = DSInfo[&F];
166 if (GraphPtr) return *GraphPtr;
Chris Lattner0d9bab82002-07-18 00:12:30 +0000167
168 // Copy the local version into DSInfo...
Chris Lattner8a5db462002-11-11 00:01:34 +0000169 GraphPtr = new DSGraph(getAnalysis<LocalDataStructures>().getDSGraph(F));
170 DSGraph &Graph = *GraphPtr;
171
172 Graph.setGlobalsGraph(GlobalsGraph);
173 Graph.setPrintAuxCalls();
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000174
Chris Lattner0d9bab82002-07-18 00:12:30 +0000175 // Start resolving calls...
Chris Lattner8a5db462002-11-11 00:01:34 +0000176 std::vector<DSCallSite> &FCs = Graph.getAuxFunctionCalls();
Chris Lattner1a948a82002-11-08 21:25:24 +0000177
178 // Start with a copy of the original call sites...
Chris Lattner8a5db462002-11-11 00:01:34 +0000179 FCs = Graph.getFunctionCalls();
Chris Lattner0d9bab82002-07-18 00:12:30 +0000180
Chris Lattner8a5db462002-11-11 00:01:34 +0000181 DEBUG(std::cerr << std::string(Indent*2, ' ')
Chris Lattnera1079052002-11-10 06:52:47 +0000182 << "[BU] Calculating graph for: " << F.getName() << "\n");
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000183
Chris Lattner8a5db462002-11-11 00:01:34 +0000184 bool Changed;
185 while (1) {
186 unsigned FirstResolvableCall = 0;
187 std::map<Function *, DSCallSite> InProcess;
188
189 // Insert a call site for self to handle self recursion...
190 std::vector<DSNodeHandle> Args;
191 Args.reserve(F.asize());
192 for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
193 if (isPointerType(I->getType()))
194 Args.push_back(Graph.getNodeForValue(I));
195
196 InProcess.insert(std::make_pair(&F,
197 DSCallSite(*(CallInst*)0, Graph.getRetNode(),(DSNode*)0,Args)));
198
199 Changed = ResolveFunctionCalls(Graph, FirstResolvableCall, InProcess,
200 Indent);
201
202 if (Changed) {
203 Graph.maskIncompleteMarkers();
204 Graph.markIncompleteNodes();
205 Graph.removeDeadNodes();
206 break;
207 } else {
208 break;
209 }
210 }
211
212#if 0
Chris Lattner0d9bab82002-07-18 00:12:30 +0000213 bool Inlined;
214 do {
215 Inlined = false;
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000216
Chris Lattner0d9bab82002-07-18 00:12:30 +0000217 for (unsigned i = 0; i != FCs.size(); ++i) {
218 // Copy the call, because inlining graphs may invalidate the FCs vector.
Vikram S. Adve42fd1692002-10-20 18:07:37 +0000219 DSCallSite Call = FCs[i];
Chris Lattner0d9bab82002-07-18 00:12:30 +0000220
Chris Lattner55c10582002-10-03 20:38:41 +0000221 // If the function list is complete...
Chris Lattner0969c502002-10-21 02:08:03 +0000222 if ((Call.getCallee().getNode()->NodeType & DSNode::Incomplete)==0) {
Chris Lattner0d9bab82002-07-18 00:12:30 +0000223 // Start inlining all of the functions we can... some may not be
224 // inlinable if they are external...
225 //
Chris Lattner7836d602002-10-20 22:11:17 +0000226 std::vector<GlobalValue*> Callees =
Chris Lattner0969c502002-10-21 02:08:03 +0000227 Call.getCallee().getNode()->getGlobals();
Chris Lattner0d9bab82002-07-18 00:12:30 +0000228
Chris Lattnera1079052002-11-10 06:52:47 +0000229 unsigned OldNumCalls = FCs.size();
230
Chris Lattner0d9bab82002-07-18 00:12:30 +0000231 // Loop over the functions, inlining whatever we can...
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000232 for (unsigned c = 0; c != Callees.size(); ++c) {
Chris Lattner0d9bab82002-07-18 00:12:30 +0000233 // Must be a function type, so this cast MUST succeed.
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000234 Function &FI = cast<Function>(*Callees[c]);
Chris Lattner613692c2002-10-17 04:24:08 +0000235
Chris Lattner0d9bab82002-07-18 00:12:30 +0000236 if (&FI == &F) {
237 // Self recursion... simply link up the formal arguments with the
238 // actual arguments...
Chris Lattner8a5db462002-11-11 00:01:34 +0000239 DEBUG(std::cerr << std::string(Indent*2, ' ')
240 << "[BU] Self Inlining: " << F.getName() << "\n");
Chris Lattner0d9bab82002-07-18 00:12:30 +0000241
Chris Lattner076c1f92002-11-07 06:31:54 +0000242 // Handle self recursion by resolving the arguments and return value
Chris Lattner8a5db462002-11-11 00:01:34 +0000243 Graph.mergeInGraph(Call, Graph, DSGraph::StripAllocaBit);
Chris Lattner0d9bab82002-07-18 00:12:30 +0000244
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000245 // Erase the entry in the callees vector
246 Callees.erase(Callees.begin()+c--);
Chris Lattner613692c2002-10-17 04:24:08 +0000247
Chris Lattner0d9bab82002-07-18 00:12:30 +0000248 } else if (!FI.isExternal()) {
Chris Lattner8a5db462002-11-11 00:01:34 +0000249 DEBUG(std::cerr << std::string(Indent*2, ' ')
250 << "[BU] In " << F.getName() << " inlining: "
Chris Lattner0d9bab82002-07-18 00:12:30 +0000251 << FI.getName() << "\n");
Vikram S. Advec44e9bf2002-07-18 16:13:52 +0000252
Chris Lattner0d9bab82002-07-18 00:12:30 +0000253 // Get the data structure graph for the called function, closing it
254 // if possible (which is only impossible in the case of mutual
255 // recursion...
256 //
Chris Lattnera1079052002-11-10 06:52:47 +0000257 DSGraph &GI = calculateGraph(FI, Indent+1); // Graph to inline
Chris Lattner0d9bab82002-07-18 00:12:30 +0000258
Chris Lattner8a5db462002-11-11 00:01:34 +0000259 DEBUG(std::cerr << std::string(Indent*2, ' ')
260 << "[BU] Got graph for " << FI.getName()
Chris Lattnera1079052002-11-10 06:52:47 +0000261 << " in: " << F.getName() << "[" << GI.getGraphSize() << "+"
262 << GI.getAuxFunctionCalls().size() << "]\n");
Chris Lattner0d9bab82002-07-18 00:12:30 +0000263
Chris Lattner076c1f92002-11-07 06:31:54 +0000264 // Handle self recursion by resolving the arguments and return value
Chris Lattner8a5db462002-11-11 00:01:34 +0000265 Graph.mergeInGraph(Call, GI, DSGraph::StripAllocaBit |
Chris Lattner70925b02002-11-08 22:27:25 +0000266 DSGraph::DontCloneCallNodes);
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000267
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000268 // Erase the entry in the Callees vector
269 Callees.erase(Callees.begin()+c--);
270
Chris Lattner9eee58d2002-07-19 18:11:43 +0000271 } else if (FI.getName() == "printf" || FI.getName() == "sscanf" ||
272 FI.getName() == "fprintf" || FI.getName() == "open" ||
Chris Lattnera1079052002-11-10 06:52:47 +0000273 FI.getName() == "sprintf" || FI.getName() == "fputs") {
Chris Lattner92673292002-11-02 00:13:20 +0000274 // FIXME: These special cases (eg printf) should go away when we can
275 // define functions that take a variable number of arguments.
Chris Lattner9eee58d2002-07-19 18:11:43 +0000276
Chris Lattner92673292002-11-02 00:13:20 +0000277 // FIXME: at the very least, this should update mod/ref info
Chris Lattner9eee58d2002-07-19 18:11:43 +0000278 // Erase the entry in the globals vector
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000279 Callees.erase(Callees.begin()+c--);
Chris Lattner0d9bab82002-07-18 00:12:30 +0000280 }
281 }
282
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000283 if (Callees.empty()) { // Inlined all of the function calls?
Chris Lattner0d9bab82002-07-18 00:12:30 +0000284 // Erase the call if it is resolvable...
285 FCs.erase(FCs.begin()+i--); // Don't skip a the next call...
286 Inlined = true;
Chris Lattner0969c502002-10-21 02:08:03 +0000287 } else if (Callees.size() !=
288 Call.getCallee().getNode()->getGlobals().size()) {
Chris Lattner0d9bab82002-07-18 00:12:30 +0000289 // Was able to inline SOME, but not all of the functions. Construct a
290 // new global node here.
291 //
292 assert(0 && "Unimpl!");
293 Inlined = true;
294 }
Chris Lattnera1079052002-11-10 06:52:47 +0000295
Chris Lattner8a5db462002-11-11 00:01:34 +0000296
297#if 0
Chris Lattnera1079052002-11-10 06:52:47 +0000298 // If we just inlined a function that had call nodes, chances are that
299 // the call nodes are redundant with ones we already have. Eliminate
300 // those call nodes now.
301 //
Chris Lattner8a5db462002-11-11 00:01:34 +0000302 if (FCs.size() >= OldNumCalls)
303 Graph.removeTriviallyDeadNodes();
304#endif
Chris Lattner0d9bab82002-07-18 00:12:30 +0000305 }
Chris Lattnera1079052002-11-10 06:52:47 +0000306
307 if (FCs.size() > 200) {
308 std::cerr << "Aborted inlining fn: '" << F.getName() << "'!"
309 << std::endl;
Chris Lattner8a5db462002-11-11 00:01:34 +0000310 Graph.maskIncompleteMarkers();
311 Graph.markIncompleteNodes();
312 Graph.removeDeadNodes();
313 Graph.writeGraphToFile(std::cerr, "crap."+F.getName());
Chris Lattnera1079052002-11-10 06:52:47 +0000314 exit(1);
Chris Lattner8a5db462002-11-11 00:01:34 +0000315 return Graph;
Chris Lattnera1079052002-11-10 06:52:47 +0000316 }
317
Chris Lattner0d9bab82002-07-18 00:12:30 +0000318 }
319
320 // Recompute the Incomplete markers. If there are any function calls left
321 // now that are complete, we must loop!
322 if (Inlined) {
Chris Lattner8a5db462002-11-11 00:01:34 +0000323 Graph.maskIncompleteMarkers();
324 Graph.markIncompleteNodes();
325 Graph.removeDeadNodes();
Chris Lattner0d9bab82002-07-18 00:12:30 +0000326 }
Chris Lattnera1079052002-11-10 06:52:47 +0000327
Chris Lattner0d9bab82002-07-18 00:12:30 +0000328 } while (Inlined && !FCs.empty());
Chris Lattner8a5db462002-11-11 00:01:34 +0000329#endif
Chris Lattner0d9bab82002-07-18 00:12:30 +0000330
Chris Lattner8a5db462002-11-11 00:01:34 +0000331 DEBUG(std::cerr << std::string(Indent*2, ' ')
Chris Lattnera1079052002-11-10 06:52:47 +0000332 << "[BU] Done inlining: " << F.getName() << " ["
Chris Lattner8a5db462002-11-11 00:01:34 +0000333 << Graph.getGraphSize() << "+" << Graph.getAuxFunctionCalls().size()
Chris Lattner221c9792002-08-07 21:41:11 +0000334 << "]\n");
Vikram S. Adve355e2ca2002-07-30 22:05:22 +0000335
Chris Lattner8a5db462002-11-11 00:01:34 +0000336 Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
Chris Lattnera1079052002-11-10 06:52:47 +0000337
Chris Lattner8a5db462002-11-11 00:01:34 +0000338 return Graph;
Chris Lattner0d9bab82002-07-18 00:12:30 +0000339}