Fix steensgaard to work on a lot more cases...
[oota-llvm.git] / lib / Analysis / DataStructure / Steensgaard.cpp
1 //===- Steensgaard.cpp - Context Insensitive Alias Analysis ---------------===//
2 //
3 // This pass uses the data structure graphs to implement a simple context
4 // insensitive alias analysis.  It does this by computing the local analysis
5 // graphs for all of the functions, then merging them together into a single big
6 // graph without cloning.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/Analysis/DataStructure.h"
11 #include "llvm/Analysis/DSGraph.h"
12 #include "llvm/Analysis/AliasAnalysis.h"
13 #include "llvm/Module.h"
14 #include "Support/Statistic.h"
15
16 namespace {
17   Statistic<> NumNoAlias  ("steens", "Number of 'no alias' replies");
18   Statistic<> NumMayAlias ("steens", "Number of 'may alias' replies");
19 };
20
21 namespace {
22   class Steens : public Pass, public AliasAnalysis {
23     DSGraph *ResultGraph;
24     DSGraph *GlobalsGraph;  // FIXME: Eliminate globals graph stuff from DNE
25   public:
26     Steens() : ResultGraph(0) {}
27     ~Steens() { assert(ResultGraph == 0 && "releaseMemory not called?"); }
28
29     //------------------------------------------------
30     // Implement the Pass API
31     //
32
33     // run - Build up the result graph, representing the pointer graph for the
34     // program.
35     //
36     bool run(Module &M);
37
38     virtual void releaseMemory() { delete ResultGraph; ResultGraph = 0; }
39
40     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
41       AU.setPreservesAll();                    // Does not transform code...
42       AU.addRequired<LocalDataStructures>();   // Uses local dsgraph
43       AU.addRequired<AliasAnalysis>();         // Chains to another AA impl...
44     }
45
46     // print - Implement the Pass::print method...
47     void print(std::ostream &O, const Module *M) const {
48       assert(ResultGraph && "Result graph has not yet been computed!");
49       ResultGraph->writeGraphToFile(O, "steensgaards");
50     }
51
52     //------------------------------------------------
53     // Implement the AliasAnalysis API
54     //  
55
56     // alias - This is the only method here that does anything interesting...
57     Result alias(const Value *V1, const Value *V2);
58     
59     /// canCallModify - Not implemented yet: FIXME
60     ///
61     Result canCallModify(const CallInst &CI, const Value *Ptr) {
62       return MayAlias;
63     }
64     
65     /// canInvokeModify - Not implemented yet: FIXME
66     ///
67     Result canInvokeModify(const InvokeInst &I, const Value *Ptr) {
68       return MayAlias;
69     }
70
71   private:
72     void ResolveFunctionCall(Function *F, const DSCallSite &Call,
73                              DSNodeHandle &RetVal);
74   };
75
76   // Register the pass...
77   RegisterOpt<Steens> X("steens-aa",
78                         "Steensgaard's FlowInsensitive/ConIns alias analysis");
79
80   // Register as an implementation of AliasAnalysis
81   RegisterAnalysisGroup<AliasAnalysis, Steens> Y;
82 }
83
84
85 /// ResolveFunctionCall - Resolve the actual arguments of a call to function F
86 /// with the specified call site descriptor.  This function links the arguments
87 /// and the return value for the call site context-insensitively.
88 ///
89 void Steens::ResolveFunctionCall(Function *F, const DSCallSite &Call,
90                                  DSNodeHandle &RetVal) {
91   assert(ResultGraph != 0 && "Result graph not allocated!");
92   hash_map<Value*, DSNodeHandle> &ValMap = ResultGraph->getScalarMap();
93
94   // Handle the return value of the function...
95   if (Call.getRetVal().getNode() && RetVal.getNode())
96     RetVal.mergeWith(Call.getRetVal());
97
98   // Loop over all pointer arguments, resolving them to their provided pointers
99   unsigned PtrArgIdx = 0;
100   for (Function::aiterator AI = F->abegin(), AE = F->aend(); AI != AE; ++AI) {
101     hash_map<Value*, DSNodeHandle>::iterator I = ValMap.find(AI);
102     if (I != ValMap.end())    // If its a pointer argument...
103       I->second.mergeWith(Call.getPtrArg(PtrArgIdx++));
104   }
105
106   assert(PtrArgIdx == Call.getNumPtrArgs() && "Argument resolution mismatch!");
107 }
108
109
110 /// run - Build up the result graph, representing the pointer graph for the
111 /// program.
112 ///
113 bool Steens::run(Module &M) {
114   assert(ResultGraph == 0 && "Result graph already allocated!");
115   LocalDataStructures &LDS = getAnalysis<LocalDataStructures>();
116
117   // Create a new, empty, graph...
118   ResultGraph = new DSGraph();
119   GlobalsGraph = new DSGraph();
120   ResultGraph->setGlobalsGraph(GlobalsGraph);
121   // RetValMap - Keep track of the return values for all functions that return
122   // valid pointers.
123   //
124   hash_map<Function*, DSNodeHandle> RetValMap;
125
126   // Loop over the rest of the module, merging graphs for non-external functions
127   // into this graph.
128   //
129   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
130     if (!I->isExternal()) {
131       hash_map<Value*, DSNodeHandle> ValMap;
132       {  // Scope to free NodeMap memory ASAP
133         hash_map<const DSNode*, DSNodeHandle> NodeMap;
134         const DSGraph &FDSG = LDS.getDSGraph(*I);
135         DSNodeHandle RetNode = ResultGraph->cloneInto(FDSG, ValMap, NodeMap);
136
137         // Keep track of the return node of the function's graph if it returns a
138         // value...
139         //
140         if (RetNode.getNode())
141           RetValMap[I] = RetNode;
142       }
143
144       // Incorporate the inlined Function's ScalarMap into the global
145       // ScalarMap...
146       hash_map<Value*, DSNodeHandle> &GVM = ResultGraph->getScalarMap();
147       for (hash_map<Value*, DSNodeHandle>::iterator I = ValMap.begin(),
148              E = ValMap.end(); I != E; ++I)
149         GVM[I->first].mergeWith(I->second);
150     }
151
152   // FIXME: Must recalculate and use the Incomplete markers!!
153
154   // Now that we have all of the graphs inlined, we can go about eliminating
155   // call nodes...
156   //
157   std::vector<DSCallSite> &Calls =
158     ResultGraph->getAuxFunctionCalls();
159   assert(Calls.empty() && "Aux call list is already in use??");
160
161   // Start with a copy of the original call sites...
162   Calls = ResultGraph->getFunctionCalls();
163
164   for (unsigned i = 0; i != Calls.size(); ) {
165     DSCallSite &CurCall = Calls[i];
166     
167     // Loop over the called functions, eliminating as many as possible...
168     std::vector<GlobalValue*> CallTargets =
169       CurCall.getCallee().getNode()->getGlobals();
170     for (unsigned c = 0; c != CallTargets.size(); ) {
171       // If we can eliminate this function call, do so!
172       bool Eliminated = false;
173       if (Function *F = dyn_cast<Function>(CallTargets[c]))
174         if (!F->isExternal()) {
175           ResolveFunctionCall(F, CurCall, RetValMap[F]);
176           Eliminated = true;
177         }
178       if (Eliminated)
179         CallTargets.erase(CallTargets.begin()+c);
180       else
181         ++c;  // Cannot eliminate this call, skip over it...
182     }
183
184     if (CallTargets.empty())          // Eliminated all calls?
185       Calls.erase(Calls.begin()+i);   // Remove from call list...
186     else
187       ++i;                            // Skip this call site...
188   }
189
190   // Update the "incomplete" markers on the nodes, ignoring unknownness due to
191   // incoming arguments...
192   ResultGraph->maskIncompleteMarkers();
193   ResultGraph->markIncompleteNodes(DSGraph::IgnoreFormalArgs);
194
195   // Remove any nodes that are dead after all of the merging we have done...
196   // FIXME: We should be able to disable the globals graph for steens!
197   ResultGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
198
199   DEBUG(print(std::cerr, &M));
200   return false;
201 }
202
203 // alias - This is the only method here that does anything interesting...
204 AliasAnalysis::Result Steens::alias(const Value *V1, const Value *V2) {
205   assert(ResultGraph && "Result graph has not been computed yet!");
206
207   hash_map<Value*, DSNodeHandle> &GSM = ResultGraph->getScalarMap();
208
209   hash_map<Value*, DSNodeHandle>::iterator I = GSM.find(const_cast<Value*>(V1));
210   if (I != GSM.end() && I->second.getNode()) {
211     DSNodeHandle &V1H = I->second;
212     hash_map<Value*, DSNodeHandle>::iterator J=GSM.find(const_cast<Value*>(V2));
213     if (J != GSM.end() && J->second.getNode()) {
214       DSNodeHandle &V2H = J->second;
215       // If the two pointers point to different data structure graph nodes, they
216       // cannot alias!
217       if (V1H.getNode() != V2H.getNode()) {  // FIXME: Handle incompleteness!
218         ++NumNoAlias;
219         return NoAlias;
220       }
221       // FIXME: If the two pointers point to the same node, and the offsets are
222       // different, and the LinkIndex vector doesn't alias the section, then the
223       // two pointers do not alias.  We need access size information for the two
224       // accesses though!
225       //
226     }
227   }
228
229   // Since Steensgaard cannot do any better, count it as a 'may alias'
230   ++NumMayAlias;
231
232   // If we cannot determine alias properties based on our graph, fall back on
233   // some other AA implementation.
234   //
235   return getAnalysis<AliasAnalysis>().alias(V1, V2);
236 }