1 cananian 1.1 // SingularFinder.java, created Sat May  3 20:00:14 2003 by cananian
  2 cananian 1.1 // Copyright (C) 2003 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1 package harpoon.Analysis.Companions;
  5 cananian 1.1 
  6 cananian 1.1 import harpoon.ClassFile.HCode;
  7 cananian 1.1 import harpoon.ClassFile.HCodeFactory;
  8 cananian 1.1 import harpoon.ClassFile.HMethod;
  9 cananian 1.3 import harpoon.IR.Quads.ANEW;
 10 cananian 1.3 import harpoon.IR.Quads.Edge;
 11 cananian 1.3 import harpoon.IR.Quads.METHOD;
 12 cananian 1.3 import harpoon.IR.Quads.MOVE;
 13 cananian 1.3 import harpoon.IR.Quads.NEW;
 14 cananian 1.3 import harpoon.IR.Quads.PHI;
 15 cananian 1.3 import harpoon.IR.Quads.SIGMA;
 16 cananian 1.1 import harpoon.IR.Quads.Quad;
 17 cananian 1.1 import harpoon.Temp.Temp;
 18 cananian 1.5 import net.cscott.jutil.Default;
 19 cananian 1.5 import net.cscott.jutil.AggregateMapFactory;
 20 cananian 1.5 import net.cscott.jutil.AggregateSetFactory;
 21 cananian 1.2 import harpoon.Util.Collections.Graph;
 22 cananian 1.5 import net.cscott.jutil.MapFactory;
 23 cananian 1.5 import net.cscott.jutil.SetFactory;
 24 cananian 1.5 import net.cscott.jutil.WorkSet;
 25 cananian 1.1 import java.util.ArrayList;
 26 cananian 1.1 import java.util.Arrays;
 27 cananian 1.1 import java.util.Collection;
 28 cananian 1.3 import java.util.Collections;
 29 cananian 1.1 import java.util.HashMap;
 30 cananian 1.1 import java.util.HashSet;
 31 cananian 1.1 import java.util.Iterator;
 32 cananian 1.1 import java.util.List;
 33 cananian 1.1 import java.util.Map;
 34 cananian 1.1 import java.util.Set;
 35 cananian 1.4 import java.util.TreeMap;
 36 cananian 1.3 import java.util.TreeSet;
 37 cananian 1.1 /**
 38 cananian 1.1  * <code>SingularFinder</code> is an implementation of
 39 cananian 1.1  * <code>SingularOracle</code> for quad IRs.
 40 cananian 1.1  * 
 41 cananian 1.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 42 cananian 1.6  * @version $Id: SingularFinder.java,v 1.6 2004/02/08 03:19:17 cananian Exp $
 43 cananian 1.1  */
 44 cananian 1.1 public class SingularFinder implements SingularOracle<Quad> {
 45 cananian 1.1     private final HCodeFactory hcf;
 46 cananian 1.1     /** Creates a <code>SingularFinder</code>. */
 47 cananian 1.1     public SingularFinder(HCodeFactory hcf) {
 48 cananian 1.1         this.hcf = hcf;
 49 cananian 1.1     }
 50 cananian 1.1     
 51 cananian 1.1     public Set<Temp> conditionallySingular(HMethod m, StaticValue<Quad> sv) {
 52 cananian 1.3         return mutuallySingular(m, Collections.singleton(sv));
 53 cananian 1.1     }
 54 cananian 1.1 
 55 cananian 1.4     // XXX cache this result?
 56 cananian 1.1     public Set<Temp> mutuallySingular(HMethod m,
 57 cananian 1.1                                       Collection<StaticValue<Quad>> svs) {
 58 cananian 1.3         if (!methodCache.containsKey(m))
 59 cananian 1.3             computeSingularity(m);
 60 cananian 1.3         assert methodCache.containsKey(m);
 61 cananian 1.3         PerMethodInfo pmi = methodCache.get(m);
 62 cananian 1.3         Set<StaticValue<Quad>> svsset = new HashSet<StaticValue<Quad>>(svs);
 63 cananian 1.3         Set<Temp> result = new TreeSet<Temp>();// compactness?
 64 cananian 1.3         // mutually singular iff
 65 cananian 1.3         //  \forall <v,s> \in svs : RDin[s](v)!=\bot &&
 66 cananian 1.3         //              {} = (svs \intersect RUin[s][RDin[s](v)])
 67 cananian 1.6         for (StaticValue<Quad> sv : svs) {
 68 cananian 1.3             assert pmi.rdResult.containsKey(sv.right());
 69 cananian 1.3             // first condition.
 70 cananian 1.3             Set<DefPoint> dps = pmi.rdResult.get(sv.right()).get(sv.left());
 71 cananian 1.3             if (dps==null)
 72 cananian 1.3                 return null; // this static value is not singular!
 73 cananian 1.3             // second condition.  first, compute RUin[s] of all dp in dps.
 74 cananian 1.6             for (DefPoint dp : dps) {
 75 cananian 1.3                 Set<StaticValue<Quad>> ru=pmi.ruResult.get(sv.right()).get(dp);
 76 cananian 1.3                 // check that none are in svs
 77 cananian 1.3                 for (Iterator<StaticValue<Quad>> it3=ru.iterator();
 78 cananian 1.3                      it3.hasNext(); )
 79 cananian 1.3                     if (svsset.contains(it3.next()))
 80 cananian 1.3                         return null;//not mutually singular with some sv in svs
 81 cananian 1.3                 // also keep track of P union {dps}
 82 cananian 1.3                 if (dp.right() instanceof METHOD)
 83 cananian 1.3                     result.add(dp.left());
 84 cananian 1.1             }
 85 cananian 1.1         }
 86 cananian 1.3         // well, these are mutually singular.  Boo-yah!
 87 cananian 1.3         return Collections.unmodifiableSet(result);
 88 cananian 1.1     }
 89 cananian 1.1 
 90 cananian 1.1     private void computeSingularity(HMethod m) {
 91 cananian 1.1         assert !methodCache.containsKey(m);
 92 cananian 1.3         QuadFlowGraph qfg = new QuadFlowGraph
 93 cananian 1.3             ((harpoon.IR.Quads.Code) hcf.convert(m));
 94 cananian 1.3         Map<QNode,RDInfo> rdResult = new RDSolver().compute(qfg);
 95 cananian 1.3         Map<QNode,RUInfo> ruResult = new RUSolver(rdResult).compute(qfg);
 96 cananian 1.4         // trim these; XXX could be trimmed much further.
 97 cananian 1.4         // (for example, I think the only relevant keys are
 98 cananian 1.4         //  array/field stores and calls, and only the defpoints
 99 cananian 1.4         //  mentioned in the trimmed-down rdResult's RDInfos are
100 cananian 1.4         //  relevant keys in the ruResult's RUInfo.)
101 cananian 1.4         Map<Quad,RDInfo> _rdResult = new TreeMap<Quad,RDInfo>();
102 cananian 1.4         Map<Quad,RUInfo> _ruResult = new TreeMap<Quad,RUInfo>();
103 cananian 1.6         for (QNode qn : qfg.nodes()) {
104 cananian 1.4             if (qn.isPhiEntrance() || qn.isSigmaExit()) continue;
105 cananian 1.4             _rdResult.put(qn.baseQuad(), rdResult.get(qn));
106 cananian 1.4             _ruResult.put(qn.baseQuad(), ruResult.get(qn));
107 cananian 1.4         }
108 cananian 1.4         methodCache.put(m, new PerMethodInfo(_rdResult, _ruResult));
109 cananian 1.1         assert methodCache.containsKey(m);
110 cananian 1.1     }
111 cananian 1.1 
112 cananian 1.1     private final Map<HMethod, PerMethodInfo> methodCache =
113 cananian 1.1         new HashMap<HMethod,PerMethodInfo>();
114 cananian 1.1 
115 cananian 1.1     static class PerMethodInfo {
116 cananian 1.4         final Map<Quad,RDInfo> rdResult;
117 cananian 1.4         final Map<Quad,RUInfo> ruResult;
118 cananian 1.4         PerMethodInfo(Map<Quad,RDInfo> rdResult, Map<Quad,RUInfo> ruResult) {
119 cananian 1.4             this.rdResult = rdResult; this.ruResult = ruResult;
120 cananian 1.3         }
121 cananian 1.1     }
122 cananian 1.1 
123 cananian 1.3     static class DefPoint extends Default.PairList<Temp,Quad> {
124 cananian 1.3         DefPoint(Temp v, Quad def) { super(v, def); }
125 cananian 1.3     }
126 cananian 1.3     static abstract class Info<I extends Info<I,K,V>,K,V> {
127 cananian 1.3         final MapFactory<K,Set<V>> mf;
128 cananian 1.3         final Map<K,Set<V>> map;
129 cananian 1.3         Info(MapFactory<K,Set<V>> mf, Map<K,Set<V>> map) {
130 cananian 1.3             this.mf = mf;
131 cananian 1.3             this.map = map;
132 cananian 1.3         }
133 cananian 1.3         protected abstract I thisInfo();
134 cananian 1.3         protected abstract I newInfo(MapFactory<K,Set<V>> mf, Map<K,Set<V>> map);
135 cananian 1.3         Set<V> get(K k) {
136 cananian 1.3             if (map.containsKey(k)) return map.get(k);
137 cananian 1.3             return Collections.EMPTY_SET;
138 cananian 1.3         }
139 cananian 1.3         I put(K k, Set<V> s) {
140 cananian 1.3             if (s==null || s.size()>0) {
141 cananian 1.3                 if (map.containsKey(k) &&
142 cananian 1.3                     (s==null ? null==map.get(k) : s.equals(map.get(k))))
143 cananian 1.3                     return thisInfo(); // no change necessary.
144 cananian 1.3                 I result = newInfo(this.mf, mf.makeMap(this.map));
145 cananian 1.3                 result.map.put(k, s);
146 cananian 1.3                 return result;
147 cananian 1.3             } else return removeKey(k);
148 cananian 1.3         }
149 cananian 1.3         I removeKey(K k) {
150 cananian 1.3             if (!map.containsKey(k)) return thisInfo();
151 cananian 1.3             I result = newInfo(this.mf, mf.makeMap(this.map));
152 cananian 1.3             result.map.remove(k);
153 cananian 1.3             return result;
154 cananian 1.3         }
155 cananian 1.3         I add(SetFactory<V> sf, K k, V v) {
156 cananian 1.3             Set<V> s = get(k);
157 cananian 1.3             if (s.contains(v)) return thisInfo();
158 cananian 1.3             s = sf.makeSet(s);
159 cananian 1.3             s.add(v);
160 cananian 1.3             return put(k, s);
161 cananian 1.3         }
162 cananian 1.3         public int hashCode() { return map.hashCode(); }
163 cananian 1.3         public boolean equals(Object o) {
164 cananian 1.3             if (this==o) return true;
165 cananian 1.3             if (!(o instanceof Info)) return false;
166 cananian 1.3             return this.map.equals(((Info)o).map);
167 cananian 1.3         }
168 cananian 1.3     }
169 cananian 1.3     static class RDInfo extends Info<RDInfo,Temp,DefPoint> {
170 cananian 1.3         RDInfo(MapFactory<Temp,Set<DefPoint>> mf) {
171 cananian 1.3             this(mf, mf.makeMap());
172 cananian 1.3         }
173 cananian 1.3         private RDInfo(MapFactory<Temp,Set<DefPoint>> mf, 
174 cananian 1.3                        Map<Temp,Set<DefPoint>> map) {
175 cananian 1.3             super(mf, map);
176 cananian 1.3         }
177 cananian 1.3         protected RDInfo thisInfo() { return this; }
178 cananian 1.3         protected RDInfo newInfo(MapFactory<Temp,Set<DefPoint>> mf,
179 cananian 1.3                                  Map<Temp,Set<DefPoint>> map) {
180 cananian 1.3             return new RDInfo(mf, map);
181 cananian 1.3         }
182 cananian 1.3         static RDInfo join(MapFactory<Temp,Set<DefPoint>> mf,
183 cananian 1.3                            SetFactory<DefPoint> sf,
184 cananian 1.3                            RDInfo rd1, RDInfo rd2) {
185 cananian 1.3             RDInfo result = new RDInfo
186 cananian 1.3                 (mf, multiMapJoin(mf, sf, rd1.map, rd2.map));
187 cananian 1.3             if (result.equals(rd1)) return rd1; // reuse if possible
188 cananian 1.3             if (result.equals(rd2)) return rd2; // reuse if possible
189 cananian 1.3             return result;
190 cananian 1.3         }
191 cananian 1.3     }
192 cananian 1.3     static class RDSolver extends DataFlowSolver.Forward<QNode,QEdge,RDInfo> {
193 cananian 1.3         MapFactory<Temp,Set<DefPoint>> mf =
194 cananian 1.3             new AggregateMapFactory<Temp,Set<DefPoint>>();
195 cananian 1.3         SetFactory<DefPoint> sf =
196 cananian 1.3             new AggregateSetFactory<DefPoint>();
197 cananian 1.3         RDInfo EMPTY = new RDInfo(mf);
198 cananian 1.3 
199 cananian 1.3         // initialize to \q. \v. {} (except for method quad)
200 cananian 1.3         protected RDInfo init(QNode qn) {
201 cananian 1.3             Quad q = qn.baseQuad();
202 cananian 1.3             if (!(q instanceof METHOD)) return EMPTY;
203 cananian 1.3             METHOD m = (METHOD) q;
204 cananian 1.3             RDInfo result = new RDInfo(mf);
205 cananian 1.3             for (int i=0; i<m.paramsLength(); i++)
206 cananian 1.3                 result.put(m.params(i),
207 cananian 1.3                            Collections.singleton(new DefPoint(m.params(i),m)));
208 cananian 1.3             return result;
209 cananian 1.3         }
210 cananian 1.3         // join rule for RDInfo.
211 cananian 1.3         protected RDInfo join(RDInfo rd1, RDInfo rd2) {
212 cananian 1.3             return RDInfo.join(mf, sf, rd1, rd2);
213 cananian 1.3         }
214 cananian 1.3         protected RDInfo out(QNode qn, RDInfo in) {
215 cananian 1.3             Quad q = qn.baseQuad();
216 cananian 1.3             RDInfo out = in;
217 cananian 1.3             if (qn.isPhiEntrance() || qn.isSigmaExit()) {
218 cananian 1.3                 Iterator<Temp> useI = qn.useC().iterator();
219 cananian 1.3                 Iterator<Temp> defI = qn.defC().iterator();
220 cananian 1.3                 while (useI.hasNext() && defI.hasNext())
221 cananian 1.3                     out = doMove(out, defI.next(), useI.next());
222 cananian 1.3                 assert !useI.hasNext();
223 cananian 1.3                 assert !defI.hasNext();
224 cananian 1.3             } else if (q instanceof MOVE) {
225 cananian 1.3                 MOVE move = (MOVE) q;
226 cananian 1.3                 out = doMove(out, move.dst(), move.src());
227 cananian 1.3             } else if (q instanceof NEW) {
228 cananian 1.3                 NEW n = (NEW) q;
229 cananian 1.3                 out = out.put(n.dst(), Collections.singleton
230 cananian 1.3                               (new DefPoint(n.dst(), n)));
231 cananian 1.3             } else if (q instanceof ANEW) {
232 cananian 1.3                 ANEW n = (ANEW) q;
233 cananian 1.3                 out = out.put(n.dst(), Collections.singleton
234 cananian 1.3                               (new DefPoint(n.dst(), n)));
235 cananian 1.3             } else {
236 cananian 1.3                 for (Iterator<Temp> it=qn.defC().iterator(); it.hasNext(); )
237 cananian 1.3                     out = out.put(it.next(), null);
238 cananian 1.1             }
239 cananian 1.3             return out;
240 cananian 1.3         }
241 cananian 1.3         RDInfo doMove(RDInfo in, Temp dst, Temp src) {
242 cananian 1.3             return in.put(dst, in.get(src));
243 cananian 1.3         }
244 cananian 1.3     }
245 cananian 1.3     static class RUInfo extends Info<RUInfo,DefPoint,StaticValue<Quad>> {
246 cananian 1.3         RUInfo(MapFactory<DefPoint,Set<StaticValue<Quad>>> mf) {
247 cananian 1.3             this(mf, mf.makeMap());
248 cananian 1.3         }
249 cananian 1.3         private RUInfo(MapFactory<DefPoint,Set<StaticValue<Quad>>> mf, 
250 cananian 1.3                        Map<DefPoint,Set<StaticValue<Quad>>> map) {
251 cananian 1.3             super(mf, map);
252 cananian 1.3         }
253 cananian 1.3         protected RUInfo thisInfo() { return this; }
254 cananian 1.3         protected RUInfo newInfo(MapFactory<DefPoint,Set<StaticValue<Quad>>> mf,
255 cananian 1.3                                  Map<DefPoint,Set<StaticValue<Quad>>> map) {
256 cananian 1.3             return new RUInfo(mf, map);
257 cananian 1.3         }
258 cananian 1.3         static RUInfo join(MapFactory<DefPoint,Set<StaticValue<Quad>>> mf,
259 cananian 1.3                            SetFactory<StaticValue<Quad>> sf,
260 cananian 1.3                            RUInfo ru1, RUInfo ru2) {
261 cananian 1.3             RUInfo result = new RUInfo
262 cananian 1.3                 (mf, multiMapJoin(mf, sf, ru1.map, ru2.map));
263 cananian 1.3             if (result.equals(ru1)) return ru1; // reuse if possible
264 cananian 1.3             if (result.equals(ru2)) return ru2; // reuse if possible
265 cananian 1.3             return result;
266 cananian 1.3         }
267 cananian 1.3     }
268 cananian 1.3     static class RUSolver extends DataFlowSolver.Forward<QNode,QEdge,RUInfo> {
269 cananian 1.3         Map<QNode,RDInfo> rdResult;
270 cananian 1.3         MapFactory<DefPoint,Set<StaticValue<Quad>>> mf =
271 cananian 1.3             new AggregateMapFactory<DefPoint,Set<StaticValue<Quad>>>();
272 cananian 1.3         SetFactory<StaticValue<Quad>> sf =
273 cananian 1.3             new AggregateSetFactory<StaticValue<Quad>>();
274 cananian 1.3         RUInfo EMPTY = new RUInfo(mf);
275 cananian 1.3 
276 cananian 1.3         RUSolver(Map<QNode,RDInfo> rdResult) { this.rdResult=rdResult; }
277 cananian 1.3 
278 cananian 1.3         // initialize to \q. \sv. {}
279 cananian 1.3         protected RUInfo init(QNode qn) { return EMPTY; }
280 cananian 1.3         // join rule for RUInfo.
281 cananian 1.3         protected RUInfo join(RUInfo ru1, RUInfo ru2) {
282 cananian 1.3             return RUInfo.join(mf, sf, ru1, ru2);
283 cananian 1.3         }
284 cananian 1.3         RDInfo getRD(QNode qn) { assert false:"unimplemented";return null; }
285 cananian 1.3         protected RUInfo out(QNode qn, RUInfo in) {
286 cananian 1.3             Quad q = qn.baseQuad();
287 cananian 1.3             RUInfo out = in;
288 cananian 1.3             if (qn.isPhiEntrance() || qn.isSigmaExit() ||
289 cananian 1.3                 q instanceof MOVE) {
290 cananian 1.3                 // out = in.
291 cananian 1.3             } else {
292 cananian 1.3                 // use QNode's useC/defC for CALL/TYPESWITCH/SWITCH/CJMP
293 cananian 1.3                 RDInfo rd = rdResult.get(qn);
294 cananian 1.3                 // first, gen for uses.
295 cananian 1.6                 for (Temp u : qn.useC()) {
296 cananian 1.3                     Set<DefPoint> s = rd.get(u);
297 cananian 1.3                     if (s!=null)
298 cananian 1.6                         for (DefPoint dp : s) {
299 cananian 1.3                             out = out.add(sf, dp, new StaticValue<Quad>(u, q));
300 cananian 1.3                         }
301 cananian 1.3                 }
302 cananian 1.3                 // last, kill for defs.
303 cananian 1.3                 for (Iterator<Temp> it=qn.defC().iterator(); it.hasNext(); )
304 cananian 1.3                     out = out.removeKey(new DefPoint(it.next(), q));
305 cananian 1.1             }
306 cananian 1.3             return out;
307 cananian 1.3         }
308 cananian 1.3     }
309 cananian 1.3 
310 cananian 1.3     private static <V> Set<V> union(SetFactory<V> sf, Set<V> s1, Set<V> s2) {
311 cananian 1.3         // try to reuse sets.
312 cananian 1.3         if (s1.size()==0) return s2;
313 cananian 1.3         if (s2.size()==0) return s1;
314 cananian 1.3         // XXX these tests are slow =(
315 cananian 1.3         if (s1.containsAll(s2)) return s1;
316 cananian 1.3         if (s2.containsAll(s1)) return s2;
317 cananian 1.3         // okay, have to create new set.
318 cananian 1.3         Set<V> result = sf.makeSet(s1); result.addAll(s2);
319 cananian 1.3         return result;
320 cananian 1.3     }
321 cananian 1.3     private static <K,V> Map<K,Set<V>> multiMapJoin(MapFactory<K,Set<V>> mf,
322 cananian 1.3                                                     SetFactory<V> sf,
323 cananian 1.3                                                     Map<K,Set<V>> m1,
324 cananian 1.3                                                     Map<K,Set<V>> m2) {
325 cananian 1.3         Map<K,Set<V>> result = mf.makeMap(m1);
326 cananian 1.6         for (K key : m2.keySet()) {
327 cananian 1.3             Set<V> s1 = result.get(key);
328 cananian 1.3             Set<V> s2 = m2.get(key);
329 cananian 1.3             assert m2.containsKey(key);
330 cananian 1.3             if (!result.containsKey(key))
331 cananian 1.3                 result.put(key, s2);
332 cananian 1.3             else if (s1==null || s2==null)
333 cananian 1.3                 result.put(key, null); // bottom.
334 cananian 1.3             else
335 cananian 1.3                 result.put(key, union(sf, s1, s2));
336 cananian 1.1         }
337 cananian 1.3         if (result.equals(m1)) return m1; // reuse maps if possible
338 cananian 1.3         if (result.equals(m2)) return m2; // reuse maps if possible.
339 cananian 1.3         return result;
340 cananian 1.1     }
341 cananian 1.1 }