blob: ca4828d1d4b12bafdea9bfec960fea67159621d2 [file] [log] [blame]
Vikram S. Adveaaeee752002-07-30 22:06:40 +00001//===- TopDownClosure.cpp - Compute the top-down interprocedure closure ---===//
2//
3// This file implements the TDDataStructures class, which represents the
4// Top-down Interprocedural closure of the data structure graph over the
5// program. This is useful (but not strictly necessary?) for applications
6// like pointer analysis.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Analysis/DataStructure.h"
11#include "llvm/Module.h"
12#include "llvm/DerivedTypes.h"
13#include "Support/StatisticReporter.h"
14using std::map;
15
16static RegisterAnalysis<TDDataStructures>
17Y("tddatastructure", "Top-down Data Structure Analysis Closure");
Vikram S. Adveaaeee752002-07-30 22:06:40 +000018
19// releaseMemory - If the pass pipeline is done with this pass, we can release
20// our memory... here...
21//
22void TDDataStructures::releaseMemory() {
23 for (map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
24 E = DSInfo.end(); I != E; ++I)
25 delete I->second;
26
27 // Empty map so next time memory is released, data structures are not
28 // re-deleted.
29 DSInfo.clear();
30}
31
32// run - Calculate the top down data structure graphs for each function in the
33// program.
34//
35bool TDDataStructures::run(Module &M) {
36 // Simply calculate the graphs for each function...
37 for (Module::reverse_iterator I = M.rbegin(), E = M.rend(); I != E; ++I)
38 if (!I->isExternal())
39 calculateGraph(*I);
40 return false;
41}
42
43
44// ResolveArguments - Resolve the formal and actual arguments for a function
45// call by merging the nodes for the actual arguments at the call site Call[]
46// (these were copied over from the caller's graph into the callee's graph
47// by cloneInto, and the nodes can be found from OldNodeMap) with the
48// corresponding nodes for the formal arguments in the callee.
49//
50static void ResolveArguments(std::vector<DSNodeHandle> &Call,
51 Function &callee,
52 std::map<Value*, DSNodeHandle> &CalleeValueMap,
53 std::map<const DSNode*, DSNode*> OldNodeMap,
54 bool ignoreNodeMap) {
55 // Resolve all of the function formal arguments...
56 Function::aiterator AI = callee.abegin();
57 for (unsigned i = 2, e = Call.size(); i != e; ++i) {
58 // Advance the argument iterator to the first pointer argument...
59 while (!isa<PointerType>(AI->getType())) ++AI;
60
61 // TD ...Merge the formal arg scalar with the actual arg node
62 DSNode* actualArg = Call[i];
63 DSNode *nodeForActual = ignoreNodeMap? actualArg : OldNodeMap[actualArg];
64 assert(nodeForActual && "No node found for actual arg in callee graph!");
65
66 DSNode *nodeForFormal = CalleeValueMap[AI]->getLink(0);
67 if (nodeForFormal)
68 nodeForFormal->mergeWith(nodeForActual);
69 ++AI;
70 }
71}
72
73// MergeGlobalNodes - Merge all existing global nodes with globals
74// inlined from the callee or with globals from the GlobalsGraph.
75//
76static void MergeGlobalNodes(DSGraph& Graph,
77 map<Value*, DSNodeHandle> &OldValMap) {
78 map<Value*, DSNodeHandle> &ValMap = Graph.getValueMap();
79 for (map<Value*, DSNodeHandle>::iterator I = ValMap.begin(), E = ValMap.end();
80 I != E; ++I)
81 if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) {
82 map<Value*, DSNodeHandle>:: iterator NHI = OldValMap.find(GV);
83 if (NHI != OldValMap.end()) // was it inlined from the callee?
84 I->second->mergeWith(NHI->second);
85 else // get it from the GlobalsGraph
86 I->second->mergeWith(Graph.cloneGlobalInto(GV));
87 }
88
89 // Add unused inlined global nodes into the value map
90 for (map<Value*, DSNodeHandle>::iterator I = OldValMap.begin(),
91 E = OldValMap.end(); I != E; ++I)
92 if (isa<GlobalValue>(I->first)) {
93 DSNodeHandle &NH = ValMap[I->first]; // If global is not in ValMap...
94 if (NH == 0)
95 NH = I->second; // Add the one just inlined.
96 }
97}
98
99// Helper function to push a caller's graph into the calleeGraph,
100// once per call between the caller and the callee.
101// Remove each such resolved call from the OrigFunctionCalls vector.
102// NOTE: This may produce O(N^2) behavior because it uses linear search
103// through the vector OrigFunctionCalls to find all calls to this callee.
104//
105void TDDataStructures::pushGraphIntoCallee(DSGraph &callerGraph,
106 DSGraph &calleeGraph,
107 std::map<Value*, DSNodeHandle> &OldValMap,
108 std::map<const DSNode*, DSNode*> &OldNodeMap) {
109
110 Function& caller = callerGraph.getFunction();
111
112 // Loop over all function calls in the caller to find those to this callee
113 std::vector<std::vector<DSNodeHandle> >& FunctionCalls =
114 callerGraph.getOrigFunctionCalls();
115
116 for (unsigned i = 0, ei = FunctionCalls.size(); i != ei; ++i) {
117
118 std::vector<DSNodeHandle>& Call = FunctionCalls[i];
119 assert(Call.size() >= 2 && "No function pointer in Call?");
120 DSNodeHandle& callee = Call[1];
121 std::vector<GlobalValue*> funcPtrs(callee->getGlobals());
122
123 // Loop over the function pointers in the call, looking for the callee
124 for (unsigned f = 0; f != funcPtrs.size(); ++f) {
125
126 // Must be a function type, so this cast MUST succeed.
127 Function &callee = cast<Function>(*funcPtrs[f]);
128 if (&callee != &calleeGraph.getFunction())
129 continue;
130
131 // Found a call to the callee. Inline its graph
132 // copy caller pointer because inlining may modify the callers vector
133
134 // Merge actual arguments from the caller with formals in the callee.
135 // Don't use the old->new node map if this is a self-recursive call.
136 ResolveArguments(Call, callee, calleeGraph.getValueMap(), OldNodeMap,
137 /*ignoreNodeMap*/ &caller == &callee);
138
139 // If its not a self-recursive call, merge global nodes in the inlined
140 // graph with the corresponding global nodes in the current graph
141 if (&caller != &callee)
142 MergeGlobalNodes(calleeGraph, OldValMap);
143
144 // Merge returned node in the caller with the "return" node in callee
145 if (Call[0])
146 calleeGraph.getRetNode()->mergeWith(OldNodeMap[Call[0]]);
147
148 // Erase the entry in the globals vector
149 funcPtrs.erase(funcPtrs.begin()+f--);
150
151 } // for each function pointer in the call node
152 } // for each original call node
153}
154
155
156DSGraph &TDDataStructures::calculateGraph(Function &F) {
157 // Make sure this graph has not already been calculated, or that we don't get
158 // into an infinite loop with mutually recursive functions.
159 //
160 DSGraph *&Graph = DSInfo[&F];
161 if (Graph) return *Graph;
162
163 // Copy the local version into DSInfo...
164 DSGraph& BUGraph = getAnalysis<BUDataStructures>().getDSGraph(F);
165 Graph = new DSGraph(BUGraph);
166
167 // Find the callers of this function recorded during the BU pass
168 std::set<Function*> &PendingCallers = BUGraph.getPendingCallers();
169
Chris Lattner7541b892002-07-31 19:32:12 +0000170 DEBUG(std::cerr << " [TD] Inlining callers for: " << F.getName() << "\n");
Vikram S. Adveaaeee752002-07-30 22:06:40 +0000171
172 for (std::set<Function*>::iterator I=PendingCallers.begin(),
173 E=PendingCallers.end(); I != E; ++I) {
174 Function& caller = **I;
175 assert(! caller.isExternal() && "Externals unexpected in callers list");
176
177 DEBUG(std::cerr << "\t [TD] Inlining " << caller.getName()
Chris Lattner7541b892002-07-31 19:32:12 +0000178 << " into callee: " << F.getName() << "\n");
Vikram S. Adveaaeee752002-07-30 22:06:40 +0000179
180 // These two maps keep track of where scalars in the old graph _used_
181 // to point to, and of new nodes matching nodes of the old graph.
182 // These remain empty if no other graph is inlined (i.e., self-recursive).
183 std::map<const DSNode*, DSNode*> OldNodeMap;
184 std::map<Value*, DSNodeHandle> OldValMap;
185
186 if (&caller == &F) {
187 // Self-recursive call: this can happen after a cycle of calls is inlined.
188 pushGraphIntoCallee(*Graph, *Graph, OldValMap, OldNodeMap);
189 }
190 else {
191 // Recursively compute the graph for the caller. That should
192 // be fully resolved except if there is mutual recursion...
193 //
194 DSGraph &callerGraph = calculateGraph(caller); // Graph to inline
195
Chris Lattner7541b892002-07-31 19:32:12 +0000196 DEBUG(std::cerr << "\t\t[TD] Got graph for " << caller.getName()
197 << " in: " << F.getName() << "\n");
Vikram S. Adveaaeee752002-07-30 22:06:40 +0000198
199 // Clone the caller's graph into the current graph, keeping
200 // track of where scalars in the old graph _used_ to point...
201 // Do this here because it only needs to happens once for each caller!
202 // Strip scalars but not allocas since they are visible in callee.
203 //
204 DSNode *RetVal = Graph->cloneInto(callerGraph, OldValMap, OldNodeMap,
205 /*StripScalars*/ true,
206 /*StripAllocas*/ false,
207 /*CopyCallers*/ true,
208 /*CopyOrigCalls*/ false);
209
210 pushGraphIntoCallee(callerGraph, *Graph, OldValMap, OldNodeMap);
211 }
212 }
213
214 // Recompute the Incomplete markers and eliminate unreachable nodes.
215 Graph->maskIncompleteMarkers();
216 Graph->markIncompleteNodes(/*markFormals*/ ! F.hasInternalLinkage()
217 /*&& FIXME: NEED TO CHECK IF ALL CALLERS FOUND!*/);
218 Graph->removeDeadNodes(/*KeepAllGlobals*/ false, /*KeepCalls*/ false);
219
Chris Lattner221c9792002-08-07 21:41:11 +0000220 DEBUG(std::cerr << " [TD] Done inlining callers for: " << F.getName() << " ["
221 << Graph->getGraphSize() << "+" << Graph->getFunctionCalls().size()
222 << "]\n");
Vikram S. Adveaaeee752002-07-30 22:06:40 +0000223
224 return *Graph;
225}