001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.ssa;
014
015import java.lang.reflect.Constructor;
016import java.util.Arrays;
017
018import org.jikesrvm.compilers.opt.OptOptions;
019import org.jikesrvm.compilers.opt.OptimizingCompilerException;
020import org.jikesrvm.compilers.opt.dfsolver.DF_AbstractCell;
021import org.jikesrvm.compilers.opt.dfsolver.DF_Solution;
022import org.jikesrvm.compilers.opt.driver.CompilerPhase;
023import org.jikesrvm.compilers.opt.ir.IR;
024
025/**
026 * Perform index propagation (see Fink, Knobe & Sarkar, SAS 2000)
027 *
028 * <p> This analysis computes for each Array SSA variable A,
029 * the set of value numbers V(k) such that location
030 * A[k] is "available" at def A, and thus at all uses of A
031 *
032 * <p> We formulate this as a data flow problem as described in the paper.
033 *
034 * <p> This class relies on Array SSA form, global value numbering, and
035 * the dataflow equation solver framework.
036 *
037 * <p> TODO: This implementation is not terribly efficient.  Speed it up.
038 */
039public final class IndexPropagation extends CompilerPhase {
040
041  /**
042   * Constructor for this compiler phase
043   */
044  private static final Constructor<CompilerPhase> constructor =
045      getCompilerPhaseConstructor(IndexPropagation.class);
046
047  /**
048   * Get a constructor object for this compiler phase
049   * @return compiler phase constructor
050   */
051  @Override
052  public Constructor<CompilerPhase> getClassConstructor() {
053    return constructor;
054  }
055
056  /**
057   * @return <code>true</code> iff SSA is constructed on the HIR
058   */
059  @Override
060  public boolean shouldPerform(OptOptions options) {
061    return options.SSA;
062  }
063
064  /**
065   * Return the name of this compiler phase.
066   * @return "Index Propagation"
067   */
068  @Override
069  public String getName() {
070    return "Index Propagation";
071  }
072
073  /**
074   * Print verbose debugging messages?
075   */
076  private static final boolean DEBUG = false;
077
078  /**
079   * Perform the analysis.
080   * <p> Pre-condition: The IR is in Array SSA form and global value numbers
081   *    have been computed.
082   *
083   * @param ir the IR to optimize
084   */
085  @Override
086  public void perform(IR ir) {
087    if (ir.desiredSSAOptions.getAbort()) return;
088    IndexPropagationSystem system = new IndexPropagationSystem(ir);
089    if (DEBUG) {
090      System.out.print("Solving...");
091    }
092    system.solve();
093    if (DEBUG) {
094      System.out.println("done");
095    }
096    DF_Solution solution = system.getSolution();
097    if (DEBUG) {
098      System.out.println("Index Propagation Solution: " + solution);
099    }
100    ir.HIRInfo.indexPropagationSolution = solution;
101  }
102
103  /**
104   * An ObjectCell is a lattice cell for the index propagation
105   * problem, used in redundant load elimination for fields.
106   * <p> An ObjectCell represents a set of value numbers,
107   * indicating that
108   * the elements indexed by these value numbers are available for
109   * a certain field type.
110   *
111   * <p> Note: this implementation does not scale, and is not terribly
112   * efficient.
113   */
114  static final class ObjectCell extends DF_AbstractCell {
115    /**
116     * a bound on the size of a lattice cell.
117     */
118    private static final int CAPACITY = 10;
119    /**
120     * a set of value numbers comparising this lattice cell.
121     */
122    private int[] numbers = null;
123    /**
124     * The number of value numbers in this cell.
125     */
126    private int size = 0;
127    /**
128     * The heap variable this lattice cell tracks information for.
129     */
130    private final HeapVariable<?> key;
131    /**
132     * Does this lattice cell represent TOP?
133     */
134    private boolean TOP = true;
135
136    /**
137     * Create a lattice cell corresponding to a heap variable.
138     * @param   key the heap variable associated with this cell.
139     */
140    ObjectCell(HeapVariable<?> key) {
141      this.key = key;
142    }
143
144    HeapVariable<?> getKey() {
145      return key;
146    }
147
148    /**
149     * Does this cell represent the TOP element in the dataflow lattice?
150     * @return true or false.
151     */
152    boolean isTOP() {
153      return TOP;
154    }
155
156    /**
157     * Does this cell represent the BOTTOM element in the dataflow lattice?
158     * @return true or false.
159     */
160    boolean isBOTTOM() {
161      return !TOP && (size == 0);
162    }
163
164    /**
165     * Mark this cell as representing (or not) the TOP element in the
166     * dataflow lattice.
167     * @param b should this cell contain TOP?
168     */
169    void setTOP(boolean b) {
170      TOP = b;
171      numbers = null;
172    }
173
174    /**
175     * Set the value of this cell to BOTTOM.
176     */
177    void setBOTTOM() {
178      clear();
179    }
180
181    /**
182     * Does this cell contain the value number v?
183     *
184     * @param v value number in question
185     * @return true or false
186     */
187    boolean contains(int v) {
188
189      if (isTOP()) return true;
190      if (v == GlobalValueNumberState.UNKNOWN) return false;
191
192      for (int i = 0; i < size; i++) {
193        if (numbers[i] == v) {
194          return true;
195        }
196      }
197      return false;
198    }
199
200    /**
201     * Add a value number to this cell.
202     *
203     * @param v value number
204     */
205    void add(int v) {
206      if (isTOP()) return;
207
208      if ((size < CAPACITY) && !contains(v)) {
209        if (size == 0) {
210          numbers = new int[CAPACITY];
211        }
212        numbers[size] = v;
213        size++;
214      }
215    }
216
217    /**
218     * Remove a value number from this cell.
219     *
220     * @param v value number
221     */
222    void remove(int v) {
223      if (isTOP()) {
224        throw new OptimizingCompilerException("Unexpected lattice operation");
225      }
226      int[] old = numbers;
227      int[] numbers = new int[CAPACITY];
228      int index = 0;
229      for (int i = 0; i < size; i++) {
230        if (old[i] == v) {
231          size--;
232        } else {
233          numbers[index++] = old[i];
234        }
235      }
236    }
237
238    /**
239     * Clear all value numbers from this cell.
240     */
241    void clear() {
242      setTOP(false);
243      size = 0;
244      numbers = null;
245    }
246
247    /**
248     * Return a deep copy of the value numbers in this cell.
249     * @return a deep copy of the value numbers in this cell, null to
250     * represent empty set.
251     */
252    int[] copyValueNumbers() {
253      if (isTOP()) {
254        throw new OptimizingCompilerException("Unexpected lattice operation");
255      }
256      if (size == 0) return null;
257
258      int[] result = new int[size];
259      for (int i = 0; i < size; i++) {
260        result[i] = numbers[i];
261      }
262      return result;
263    }
264
265    /**
266     * Return a string representation of this cell
267     * @return a string representation of this cell
268     */
269    @Override
270    public String toString() {
271      StringBuilder s = new StringBuilder(key.toString());
272
273      if (isTOP()) return s.append("{TOP}").toString();
274      if (isBOTTOM()) return s.append("{BOTTOM}").toString();
275
276      s.append("{");
277      for (int i = 0; i < size; i++) {
278        s.append(" ").append(numbers[i]);
279      }
280      s.append("}");
281      return s.toString();
282    }
283
284    /**
285     * Do two sets of value numbers differ?
286     * <p> SIDE EFFECT: sorts the sets
287     *
288     * @param set1 first set to compare
289     * @param set2 second set to compare
290     * @return true iff the two sets are different
291     */
292    public static boolean setsDiffer(int[] set1, int[] set2) {
293      if ((set1 != null) && (set2 != null)) {
294        Arrays.sort(set1);
295        Arrays.sort(set2);
296        return !Arrays.equals(set1, set2);
297      } else {
298        return set1 == set2;
299      }
300    }
301  }
302
303  /**
304   * An ArrayCell is a lattice cell for the index propagation
305   * problem, used in redundant load elimination for one-dimensional arrays.
306   * <p> An ArrayCell represents a set of value number pairs,
307   * indicating that
308   * the elements indexed by these value numbers are available for
309   * a certain array type.
310   *
311   * <p> For example, suppose {@code p} is an {@code int[]}, with value number
312   * {@code v(p)}.
313   * Then the value number pair {@code <p,5>} for heap variable {@code I[} means
314   * that {@code p[5]} is available.
315   *
316   * <p> Note: this implementation does not scale, and is not terribly
317   * efficient.
318   */
319  static final class ArrayCell extends DF_AbstractCell {
320    /**
321     * a bound on the size of a lattice cell.
322     */
323    private static final int CAPACITY = 10;
324    /**
325     * a set of value number pairs comparising this lattice cell.
326     */
327    private ValueNumberPair[] numbers = null;
328    /**
329     * The number of value number pairs in this cell.
330     */
331    private int size = 0;
332    /**
333     * The heap variable this lattice cell tracks information for.
334     */
335    private final HeapVariable<?> key;
336    /**
337     * Does this lattice cell represent TOP?
338     */
339    private boolean TOP = true;
340
341    /**
342     * Create a lattice cell corresponding to a heap variable.
343     * @param   key the heap variable associated with this cell.
344     */
345    ArrayCell(HeapVariable<?> key) {
346      this.key = key;
347    }
348
349    HeapVariable<?> getKey() {
350      return key;
351    }
352
353    /**
354     * Does this cell represent the TOP element in the dataflow lattice?
355     * @return true or false.
356     */
357    boolean isTOP() {
358      return TOP;
359    }
360
361    /**
362     * Does this cell represent the BOTTOM element in the dataflow lattice?
363     * @return true or false.
364     */
365    boolean isBOTTOM() {
366      return !TOP && (size == 0);
367    }
368
369    /**
370     * Mark this cell as representing (or not) the TOP element in the
371     * dataflow lattice.
372     * @param b should this cell contain TOP?
373     */
374    void setTOP(boolean b) {
375      TOP = b;
376      numbers = null;
377    }
378
379    /**
380     * Set the value of this cell to BOTTOM.
381     */
382    void setBOTTOM() {
383      clear();
384    }
385
386    /**
387     * Does this cell contain the value number pair v1, v2?
388     *
389     * @param v1 first value number
390     * @param v2 second value number
391     * @return true or false
392     */
393    boolean contains(int v1, int v2) {
394      if (isTOP()) return true;
395      if (v1 == GlobalValueNumberState.UNKNOWN) return false;
396      if (v2 == GlobalValueNumberState.UNKNOWN) return false;
397      if (size == 0) return false;
398
399      ValueNumberPair p = new ValueNumberPair(v1, v2);
400      for (int i = 0; i < size; i++) {
401        if (numbers[i].equals(p)) {
402          return true;
403        }
404      }
405      return false;
406    }
407
408    /**
409     * Add a value number pair to this cell.
410     *
411     * @param v1 first value number
412     * @param v2 second value number
413     */
414    void add(int v1, int v2) {
415      if (isTOP()) return;
416
417      if ((size < CAPACITY) && !contains(v1, v2)) {
418        if (size == 0) {
419          numbers = new ValueNumberPair[CAPACITY];
420        }
421        ValueNumberPair p = new ValueNumberPair(v1, v2);
422        numbers[size] = p;
423        size++;
424      }
425    }
426
427    /**
428     * Remove a value number pair from this cell.
429     *
430     * @param v1 first value number
431     * @param v2 second value number
432     */
433    void remove(int v1, int v2) {
434      if (isTOP()) {
435        throw new OptimizingCompilerException("Unexpected lattice operation");
436      }
437      ValueNumberPair[] old = numbers;
438      ValueNumberPair[] numbers = new ValueNumberPair[CAPACITY];
439      int index = 0;
440      ValueNumberPair p = new ValueNumberPair(v1, v2);
441      for (int i = 0; i < size; i++) {
442        if (old[i].equals(p)) {
443          size--;
444        } else {
445          numbers[index++] = old[i];
446        }
447      }
448    }
449
450    /**
451     * Clear all value numbers from this cell.
452     */
453    void clear() {
454      setTOP(false);
455      size = 0;
456      numbers = null;
457    }
458
459    /**
460     * Return a deep copy of the value numbers in this cell
461     * @return a deep copy of the value numbers in this cell
462     */
463    ValueNumberPair[] copyValueNumbers() {
464      if (isTOP()) {
465        throw new OptimizingCompilerException("Unexpected lattice operation");
466      }
467
468      if (size == 0) return null;
469
470      ValueNumberPair[] result = new ValueNumberPair[size];
471      for (int i = 0; i < size; i++) {
472        result[i] = new ValueNumberPair(numbers[i]);
473      }
474      return result;
475    }
476
477    /**
478     * Return a string representation of this cell
479     * @return a string representation of this cell
480     */
481    @Override
482    public String toString() {
483      StringBuilder s = new StringBuilder(key.toString());
484
485      if (isTOP()) return s.append("{TOP}").toString();
486      if (isBOTTOM()) return s.append("{BOTTOM}").toString();
487
488      s.append("{");
489      for (int i = 0; i < size; i++) {
490        s.append(" ").append(numbers[i]);
491      }
492      s.append("}");
493      return s.toString();
494    }
495
496    /**
497     * Do two sets of value number pairs differ?
498     * <p> SIDE EFFECT: sorts the sets
499     *
500     * @param set1 first set to compare
501     * @param set2 second set to compare
502     * @return true iff the two sets are different
503     */
504    public static boolean setsDiffer(ValueNumberPair[] set1, ValueNumberPair[] set2) {
505      if ((set1 != null) && (set2 != null)) {
506        Arrays.sort(set1);
507        Arrays.sort(set2);
508        return !Arrays.equals(set1, set2);
509      } else {
510        return set1 == set2;
511      }
512    }
513  }
514}