1 kkz      1.1.2.1  // ReachingDefsImpl.java, created Wed Feb  9 16:35:43 2000 by kkz
  2 cananian 1.1.2.17 // Copyright (C) 2000 Karen K. Zee <kkz@alum.mit.edu>
  3 kkz      1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 kkz      1.1.2.1  package harpoon.Analysis;
  5 kkz      1.1.2.1  
  6 kkz      1.1.2.1  import harpoon.ClassFile.HCode;
  7 kkz      1.1.2.1  import harpoon.ClassFile.HCodeElement;
  8 kkz      1.1.2.1  import harpoon.IR.Properties.CFGrapher;
  9 kkz      1.1.2.1  import harpoon.Temp.Temp;
 10 cananian 1.5      import net.cscott.jutil.BitSetFactory;
 11 cananian 1.1.2.5  import harpoon.Util.Util;
 12 kkz      1.1.2.1  import harpoon.Util.Worklist;
 13 cananian 1.1.2.19 import harpoon.Util.Collections.WorkSet;
 14 pnkfelix 1.1.2.9  import harpoon.IR.Properties.UseDefer;
 15 salcianu 1.1.2.7  import harpoon.IR.Quads.TYPECAST;
 16 cananian 1.5      import net.cscott.jutil.Default;
 17 kkz      1.1.2.1  
 18 cananian 1.5      import java.util.ArrayList;
 19 kkz      1.1.2.1  import java.util.Collections;
 20 salcianu 1.1.2.7  import java.util.Collection;
 21 kkz      1.1.2.1  import java.util.HashMap;
 22 kkz      1.1.2.1  import java.util.HashSet;
 23 kkz      1.1.2.1  import java.util.Iterator;
 24 cananian 1.5      import java.util.List;
 25 kkz      1.1.2.1  import java.util.Map;
 26 kkz      1.1.2.1  import java.util.Set;
 27 kkz      1.1.2.1  /**
 28 kkz      1.1.2.1   * <code>ReachingDefsImpl</code> defines an implementation
 29 kkz      1.1.2.1   * for analyzing reaching definitions. Since results are
 30 kkz      1.1.2.1   * cached, a new <code>ReachingDefsImpl</code> should be
 31 kkz      1.1.2.1   * created if the code has been modified.
 32 kkz      1.1.2.1   * 
 33 cananian 1.1.2.17  * @author  Karen K. Zee <kkz@alum.mit.edu>
 34 cananian 1.6       * @version $Id: ReachingDefsImpl.java,v 1.6 2004/02/08 03:19:12 cananian Exp $
 35 kkz      1.1.2.1   */
 36 cananian 1.3.2.2  public class ReachingDefsImpl<HCE extends HCodeElement> extends ReachingDefs<HCE> {
 37 cananian 1.3.2.2      final private CFGrapher<HCE> cfger;
 38 cananian 1.3.2.2      final protected BasicBlock.Factory<HCE> bbf;
 39 cananian 1.3.2.2      final protected Map<Temp,BitSetFactory<HCE>> Temp_to_BitSetFactories =
 40 cananian 1.3.2.2          new HashMap<Temp,BitSetFactory<HCE>>();
 41 cananian 1.5          final protected Map<BasicBlock<HCE>,Map<Temp,List<Set<HCE>>>> cache =
 42 cananian 1.5              new HashMap<BasicBlock<HCE>,Map<Temp,List<Set<HCE>>>>(); // maps BasicBlocks to in/out Sets 
 43 pnkfelix 1.1.2.11     final protected boolean check_typecast; // demand the special treatment of TYPECAST
 44 cananian 1.3.2.2      final protected UseDefer<HCE> ud;
 45 kkz      1.1.2.1      /** Creates a <code>ReachingDefsImpl</code> object for the
 46 pnkfelix 1.1.2.9          provided <code>HCode</code> for an IR implementing
 47 cananian 1.1.2.15         <code>UseDefable</code> using the provided <code>CFGrapher</code>.
 48 pnkfelix 1.1.2.9          This may take a while since the analysis is done at this time. 
 49 kkz      1.1.2.1      */
 50 cananian 1.3.2.2      public ReachingDefsImpl(HCode<HCE> hc, CFGrapher<HCE> cfger) {
 51 cananian 1.5              this(hc, cfger, (UseDefer<HCE>) UseDefer.DEFAULT);
 52 pnkfelix 1.1.2.9      }
 53 pnkfelix 1.1.2.9      /** Creates a <code>ReachingDefsImpl</code> object for the
 54 pnkfelix 1.1.2.9          provided <code>HCode</code> using the provided 
 55 pnkfelix 1.1.2.9          <code>CFGrapher</code> and <code>UseDefer</code>. This may
 56 pnkfelix 1.1.2.9          take a while since the analysis is done at this time.
 57 pnkfelix 1.1.2.9      */
 58 cananian 1.3.2.2      public ReachingDefsImpl(HCode<HCE> hc, CFGrapher<HCE> cfger, UseDefer<HCE> ud) {
 59 kkz      1.1.2.1          super(hc);
 60 kkz      1.1.2.1          this.cfger = cfger;
 61 cananian 1.3.2.2          this.bbf = new BasicBlock.Factory<HCE>(hc, cfger);
 62 pnkfelix 1.1.2.9          this.ud = ud;
 63 salcianu 1.1.2.7          // sometimes, TYPECAST need to be treated specially
 64 salcianu 1.1.2.7          check_typecast = 
 65 salcianu 1.1.2.7              hc.getName().equals(harpoon.IR.Quads.QuadNoSSA.codename);
 66 kkz      1.1.2.1          analyze();
 67 kkz      1.1.2.1      }
 68 kkz      1.1.2.1      /** Creates a <code>ReachingDefsImpl</code> object for the
 69 kkz      1.1.2.6          provided <code>HCode</code> using <code>CFGrapher.DEFAULT</code>.
 70 kkz      1.1.2.6          This may take a while since the analysis is done at this time.
 71 kkz      1.1.2.1      */
 72 cananian 1.3.2.2      public ReachingDefsImpl(HCode<HCE> hc) {
 73 cananian 1.5              this(hc, (CFGrapher<HCE>) CFGrapher.DEFAULT);
 74 kkz      1.1.2.1      }
 75 kkz      1.1.2.1      /** Returns the Set of <code>HCodeElement</code>s providing definitions
 76 kkz      1.1.2.1       *  of <code>Temp</code> <code>t</code> which reach 
 77 kkz      1.1.2.18      *  <code>HCodeElement</code> <code>hce</code>. Returns the empty
 78 kkz      1.1.2.18      *  Set if the given <code>HCodeElement</code> is unreachable. */
 79 cananian 1.3.2.2      public Set<HCE> reachingDefs(HCE hce, Temp t) {
 80 kkz      1.1.2.1          // find out which BasicBlock this HCodeElement is from
 81 cananian 1.3.2.2          BasicBlock<HCE> b = bbf.getBlock(hce);
 82 kkz      1.1.2.18         if (b == null) {
 83 kkz      1.1.2.18             // dead code, no definitions reach
 84 kkz      1.1.2.18             return java.util.Collections.EMPTY_SET;
 85 kkz      1.1.2.18         }
 86 kkz      1.1.2.1          // get the map for the BasicBlock
 87 cananian 1.5              Map<Temp,List<Set<HCE>>> m = cache.get(b);
 88 kkz      1.1.2.1          // get the BitSetFactory
 89 cananian 1.3.2.2          BitSetFactory<HCE> bsf = Temp_to_BitSetFactories.get(t);
 90 cananian 1.3.2.1          assert m.get(t) != null : t.toString();
 91 kkz      1.1.2.2          // make a copy of the in Set for the Temp
 92 cananian 1.5              Set<HCE> results = bsf.makeSet(m.get(t).get(IN));
 93 kkz      1.1.2.2          // propagate in Set through the HCodeElements 
 94 kkz      1.1.2.2          // of the BasicBlock in correct order
 95 cananian 1.6              for(HCE curr : b.statements()) {
 96 kkz      1.1.2.2              if (curr == hce) return results;
 97 cananian 1.3.2.2              Collection<Temp> defC = null;
 98 salcianu 1.1.2.7              // special treatment of TYPECAST
 99 salcianu 1.1.2.7              if(check_typecast && (curr instanceof TYPECAST))
100 salcianu 1.1.2.7                  defC = Collections.singleton(((TYPECAST)curr).objectref());
101 salcianu 1.1.2.7              else
102 pnkfelix 1.1.2.9                  defC = ud.defC(curr);
103 salcianu 1.1.2.7              if (defC.contains(t)) 
104 kkz      1.1.2.1                  results = bsf.makeSet(Collections.singleton(curr));
105 kkz      1.1.2.1          }
106 cananian 1.3.2.1          assert false;
107 kkz      1.1.2.2          return null; // should never happen
108 kkz      1.1.2.1      }
109 kkz      1.1.2.1      // do analysis
110 kkz      1.1.2.1      private void analyze() {
111 kkz      1.1.2.1          final Map Temp_to_DefPts = getDefPts();
112 kkz      1.1.2.1          getBitSets(Temp_to_DefPts);
113 kkz      1.1.2.1          
114 kkz      1.1.2.1          // build Gen and Kill sets
115 kkz      1.1.2.1          buildGenKillSets(Temp_to_DefPts);
116 kkz      1.1.2.2  
117 kkz      1.1.2.1          // solve for fixed point
118 kkz      1.1.2.1          solve();
119 kkz      1.1.2.1          // store only essential information
120 cananian 1.6              for(BasicBlock<HCE> b : cache.keySet()) {
121 cananian 1.5                  Map<Temp,List<Set<HCE>>> m = cache.get(b);
122 cananian 1.6                  for(Temp t : m.keySet()) {
123 cananian 1.5                      List<Set<HCE>> results = m.get(t);
124 cananian 1.5                      m.put(t, Collections.singletonList( results.get(IN) ));
125 kkz      1.1.2.1              }
126 kkz      1.1.2.1          }
127 kkz      1.1.2.1      }
128 kkz      1.1.2.2      // create a mapping of Temps to a Set of possible definition points
129 cananian 1.3.2.2      private Map<Temp,Set<HCE>> getDefPts() {
130 cananian 1.3.2.2          Map<Temp,Set<HCE>> m = new HashMap<Temp,Set<HCE>>();
131 cananian 1.6              for(HCE hce : cfger.getElements(hc)) {
132 pnkfelix 1.1.2.9              StringBuffer strbuf = new StringBuffer();
133 salcianu 1.1.2.7              Temp[] tArray = null;
134 pnkfelix 1.1.2.9              report("Getting defs in: "+hce+" (defC:"+new java.util.ArrayList
135 pnkfelix 1.1.2.9                     (ud.defC(hce))+")");
136 salcianu 1.1.2.7              // special treatment of TYPECAST
137 kkz      1.1.2.8              if(check_typecast && (hce instanceof TYPECAST)) {
138 pnkfelix 1.1.2.9                  strbuf.append("TYPECAST: ");
139 salcianu 1.1.2.7                  tArray = new Temp[]{((TYPECAST)hce).objectref()};
140 pnkfelix 1.1.2.9              } else {
141 pnkfelix 1.1.2.9                  tArray = ud.def(hce);
142 pnkfelix 1.1.2.9                  if (tArray.length > 0)
143 pnkfelix 1.1.2.9                      strbuf.append("DEFINES: ");
144 pnkfelix 1.1.2.9              }
145 kkz      1.1.2.2              for(int i=0; i < tArray.length; i++) {
146 kkz      1.1.2.2                  Temp t = tArray[i];
147 pnkfelix 1.1.2.9                  strbuf.append(t+" ");
148 cananian 1.3.2.2                  Set<HCE> defPts = m.get(t);
149 kkz      1.1.2.2                  if (defPts == null) {
150 kkz      1.1.2.2                      // have not yet encountered this Temp
151 cananian 1.3.2.2                      defPts = new HashSet<HCE>();
152 kkz      1.1.2.6                      // add to map
153 kkz      1.1.2.2                      m.put(t, defPts);
154 kkz      1.1.2.2                  }
155 kkz      1.1.2.6                  // add this definition point
156 kkz      1.1.2.6                  defPts.add(hce);
157 kkz      1.1.2.2              }
158 pnkfelix 1.1.2.9              /* for debugging purposes only */
159 cananian 1.3.2.2              Collection<Temp> col = ud.useC(hce);
160 pnkfelix 1.1.2.9              if (!col.isEmpty()) strbuf.append("\nUSES: ");
161 cananian 1.3.2.2              for(Iterator<Temp> it2 = col.iterator(); it2.hasNext(); )
162 pnkfelix 1.1.2.9                  strbuf.append(it2.next().toString() + " ");
163 pnkfelix 1.1.2.9              if (strbuf.length() > 0)
164 pnkfelix 1.1.2.9                  report(strbuf.toString());
165 pnkfelix 1.1.2.9  
166 kkz      1.1.2.2          }
167 pnkfelix 1.1.2.9          StringBuffer strbuf2 = new StringBuffer("Have entry for Temp(s): ");
168 cananian 1.3.2.2          for(Iterator<Temp> keys = m.keySet().iterator(); keys.hasNext(); )
169 pnkfelix 1.1.2.9              strbuf2.append(keys.next()+" ");
170 pnkfelix 1.1.2.9          report(strbuf2.toString());
171 kkz      1.1.2.2          return m;
172 kkz      1.1.2.2      }
173 kkz      1.1.2.2      // create a mapping of Temps to BitSetFactories
174 kkz      1.1.2.2      // using a mapping of Temps to Sets of definitions points
175 cananian 1.3.2.2      private void getBitSets(Map<Temp,Set<HCE>> input) {
176 cananian 1.6              for(Temp t : input.keySet()) {
177 cananian 1.3.2.2              BitSetFactory<HCE> bsf = new BitSetFactory<HCE>(input.get(t));
178 kkz      1.1.2.2              Temp_to_BitSetFactories.put(t, bsf);
179 kkz      1.1.2.2          }
180 kkz      1.1.2.2      }
181 kkz      1.1.2.2      private final int IN = 0;
182 kkz      1.1.2.2      private final int OUT = 1;
183 kkz      1.1.2.2      private final int GEN = 2;
184 kkz      1.1.2.2      private final int KILL = 3;
185 kkz      1.1.2.1      // return a mapping of BasicBlocks to a mapping of Temps to
186 kkz      1.1.2.1      // an array of bitsets where the indices are organized as follows:
187 kkz      1.1.2.1      // 0 - gen Set
188 kkz      1.1.2.1      // 1 - kill Set
189 kkz      1.1.2.1      // 2 - in Set
190 kkz      1.1.2.1      // 3 - out Set
191 cananian 1.3.2.2      private void buildGenKillSets(Map<Temp,Set<HCE>> DefPts) {
192 kkz      1.1.2.6          // calculate Gen and Kill sets for each basic block 
193 cananian 1.6              for(BasicBlock<HCE> b : bbf.blockSet()) {
194 cananian 1.5                  Map<Temp,List<Set<HCE>>> Temp_to_BitSets =
195 cananian 1.5                      new HashMap<Temp,List<Set<HCE>>>();
196 kkz      1.1.2.6              // iterate through the instructions in the basic block
197 cananian 1.6                  for(HCE hce : b.statements()) {
198 salcianu 1.1.2.7                  Temp[] tArray = null;
199 salcianu 1.1.2.7                  // special treatment of TYPECAST
200 salcianu 1.1.2.7                  if(check_typecast && (hce instanceof TYPECAST))
201 salcianu 1.1.2.7                      tArray = new Temp[]{((TYPECAST)hce).objectref()};
202 salcianu 1.1.2.7                  else
203 pnkfelix 1.1.2.9                      tArray = ud.def(hce);
204 kkz      1.1.2.1                  for(int i=0; i < tArray.length; i++) {
205 kkz      1.1.2.1                      Temp t = tArray[i];
206 cananian 1.3.2.2                      BitSetFactory<HCE> bsf 
207 cananian 1.3.2.2                          = Temp_to_BitSetFactories.get(t);
208 cananian 1.5                          List<Set<HCE>> bitSets = new ArrayList<Set<HCE>>
209 cananian 1.5                              // 0 is Gen, 1 is Kill
210 cananian 1.5                              (Collections.<Set<HCE>>nCopies(4, null));
211 cananian 1.5                          bitSets.set(GEN, bsf.makeSet(Collections.singleton(hce)));
212 cananian 1.3.2.2                      Set<HCE> kill = new HashSet<HCE>(DefPts.get(t));
213 kkz      1.1.2.1                      kill.remove(hce);
214 cananian 1.5                          bitSets.set(KILL, bsf.makeSet(kill));
215 kkz      1.1.2.1                      Temp_to_BitSets.put(t, bitSets);
216 kkz      1.1.2.1                  }
217 cananian 1.6                      for(Temp t : DefPts.keySet()) {
218 cananian 1.5                          List<Set<HCE>> bitSets = Temp_to_BitSets.get(t);
219 cananian 1.3.2.2                      BitSetFactory<HCE> bsf = Temp_to_BitSetFactories.get(t);
220 kkz      1.1.2.1                      if (bitSets == null) {
221 cananian 1.5                              bitSets = new ArrayList<Set<HCE>>
222 cananian 1.5                                  (Collections.<Set<HCE>>nCopies(4, null));
223 kkz      1.1.2.1                          Temp_to_BitSets.put(t, bitSets);
224 cananian 1.5                              bitSets.set(GEN, bsf.makeSet(Default.<HCE>EMPTY_SET()));
225 cananian 1.5                              bitSets.set(KILL, bsf.makeSet(Default.<HCE>EMPTY_SET()));
226 kkz      1.1.2.1                      }
227 cananian 1.5                          bitSets.set(IN, bsf.makeSet(Default.<HCE>EMPTY_SET()));//in
228 cananian 1.5                          bitSets.set(OUT, bsf.makeSet(Default.<HCE>EMPTY_SET()));//out
229 kkz      1.1.2.1                  }
230 kkz      1.1.2.1              }
231 kkz      1.1.2.2              cache.put(b, Temp_to_BitSets);
232 kkz      1.1.2.1          }
233 kkz      1.1.2.1      }
234 kkz      1.1.2.1      // uses Worklist algorithm to solve for reaching definitions
235 kkz      1.1.2.1      // given a map of BasicBlocks to Maps of Temps to arrays of bit Sets
236 kkz      1.1.2.1      private void solve() {
237 pnkfelix 1.1.2.12         int revisits = 0;
238 pnkfelix 1.1.2.12         Set blockSet = bbf.blockSet();
239 cananian 1.3.2.2          WorkSet<BasicBlock<HCE>> worklist;
240 pnkfelix 1.1.2.12         if (true) {
241 cananian 1.3.2.2              worklist = new WorkSet<BasicBlock<HCE>>(blockSet.size());
242 cananian 1.3.2.2              Iterator<BasicBlock<HCE>> iter = bbf.postorderBlocksIter();
243 pnkfelix 1.1.2.12             while(iter.hasNext()) {
244 pnkfelix 1.1.2.12                 worklist.push(iter.next());
245 pnkfelix 1.1.2.12             }
246 pnkfelix 1.1.2.12         } else {
247 cananian 1.5                  worklist = new WorkSet<BasicBlock<HCE>>((Set<BasicBlock<HCE>>)blockSet);
248 pnkfelix 1.1.2.12         }
249 pnkfelix 1.1.2.12 
250 kkz      1.1.2.1          while(!worklist.isEmpty()) {
251 cananian 1.3.2.2              BasicBlock<HCE> b = worklist.pull();
252 pnkfelix 1.1.2.13             revisits++;
253 kkz      1.1.2.2              // get all the bitSets for this BasicBlock
254 cananian 1.5                  Map<Temp,List<Set<HCE>>> bitSets = cache.get(b);
255 cananian 1.6                  for(Temp t : bitSets.keySet()) {
256 cananian 1.5                      List<Set<HCE>> bitSet = bitSets.get(t);
257 cananian 1.3.2.2                  BitSetFactory bsf = Temp_to_BitSetFactories.get(t);
258 cananian 1.5                      Set<HCE> oldIn, oldOut;
259 cananian 1.5                      oldIn = bsf.makeSet(bitSet.get(IN)); // clone old in Set
260 cananian 1.5                      bitSet.get(IN).clear();
261 cananian 1.6                      for(BasicBlock<HCE> pred : b.prevSet()) {
262 cananian 1.5                          List<Set<HCE>> pBitSet = cache.get(pred).get(t);
263 cananian 1.5                          bitSet.get(IN).addAll(pBitSet.get(OUT)); // union
264 kkz      1.1.2.1                  }
265 cananian 1.5                      oldOut = bitSet.get(OUT); // keep old out Set
266 cananian 1.5                      bitSet.set(OUT, bsf.makeSet(bitSet.get(IN)));
267 cananian 1.5                      bitSet.get(OUT).removeAll(bitSet.get(KILL));
268 cananian 1.5                      bitSet.get(OUT).addAll(bitSet.get(GEN));
269 cananian 1.5                      if (oldIn.equals(bitSet.get(IN)) && oldOut.equals(bitSet.get(OUT)))
270 kkz      1.1.2.1                      continue;
271 cananian 1.6                      for(BasicBlock<HCE> block : b.nextSet()){
272 pnkfelix 1.1.2.14                     worklist.addLast(block);
273 pnkfelix 1.1.2.12                 }
274 kkz      1.1.2.1              }
275 kkz      1.1.2.1          }
276 pnkfelix 1.1.2.13         if (TIME) System.out.print("(r:"+revisits+"/"+blockSet.size()+")");
277 pnkfelix 1.1.2.12 
278 kkz      1.1.2.1      }
279 kkz      1.1.2.2      // debugging utility
280 kkz      1.1.2.3      private final boolean DEBUG = false;
281 kkz      1.1.2.2      private void report(String str) {
282 kkz      1.1.2.2          if (DEBUG) System.out.println(str);
283 kkz      1.1.2.1      }
284 kkz      1.1.2.1  }