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.dfsolver;
014
015import java.util.Comparator;
016import java.util.Enumeration;
017import java.util.HashSet;
018import java.util.Iterator;
019import java.util.TreeSet;
020
021import org.jikesrvm.compilers.opt.util.FilterEnumerator;
022import org.jikesrvm.compilers.opt.util.Graph;
023import org.jikesrvm.compilers.opt.util.GraphNode;
024import org.jikesrvm.compilers.opt.util.GraphUtilities;
025import org.jikesrvm.compilers.opt.util.ReverseDFSenumerateByFinish;
026
027/**
028 * Represents a system of Data Flow equations
029 *
030 * <p> Implementation Note:
031 *      The set of equations is internally represented as a graph
032 *      (actually a SpaceEffGraph).  Each dataflow equation is a node in the
033 *      graph.  If a dataflow equation produces a lattice cell value
034 *      that is used by another equation, the graph has a directed edge
035 *      from the producer to the consumer.  Fixed-point iteration proceeds
036 *      in a topological order according to these edges.
037 */
038public abstract class DF_System {
039  private static final boolean DEBUG = false;
040
041  private final boolean EAGER;
042
043  /**
044   * The equations that comprise this dataflow system.
045   */
046  private final Graph equations = new DF_Graph();
047
048  /**
049   * Set of equations pending evaluation
050   */
051  protected final TreeSet<DF_Equation> workList = new TreeSet<DF_Equation>(dfComparator);
052
053  /**
054   * Set of equations considered "new"
055   */
056  private final HashSet<DF_Equation> newEquations = new HashSet<DF_Equation>();
057
058  /**
059   * The lattice cells of the system: Mapping from Object to DF_LatticeCell
060   */
061  protected final DF_Solution cells = new DF_Solution();
062
063  public DF_System() {
064    EAGER = false;
065  }
066
067  public DF_System(boolean eager) {
068    EAGER = eager;
069  }
070
071  /**
072   * Solve the set of dataflow equations.
073   * <p> PRECONDITION: equations are set up
074   */
075  public void solve() {
076    // addGraphEdges();
077    numberEquationsTopological();
078    initializeLatticeCells();
079    initializeWorkList();
080    while (!workList.isEmpty()) {
081      DF_Equation eq = workList.first();
082      workList.remove(eq);
083      boolean change = eq.evaluate();
084      if (DEBUG) {
085        System.out.println("After evaluation " + eq);
086      }
087      if (change) {
088        updateWorkList(eq);
089      }
090    }
091  }
092
093  /**
094   * Return the solution of the dataflow equation system.
095   * This is only valid after calling solve()
096   *
097   * @return the solution
098   */
099  public DF_Solution getSolution() {
100    return cells;
101  }
102
103  /**
104   * Return a string representation of the system
105   * @return a string representation of the system
106   */
107  @Override
108  public String toString() {
109    StringBuilder result = new StringBuilder("EQUATIONS:\n");
110    Enumeration<GraphNode> v = equations.enumerateNodes();
111    for (int i = 0; i < equations.numberOfNodes(); i++) {
112      result.append(i);
113      result.append(" : ");
114      result.append(v.nextElement());
115      result.append('\n');
116    }
117    return result.toString();
118  }
119
120  /**
121   * Return an Enumeration over the equations in this system.
122   * @return an Enumeration over the equations in this system
123   */
124  public Enumeration<DF_Equation> getEquations() {
125    return new FilterEnumerator<GraphNode, DF_Equation>(equations.enumerateNodes(),
126        new FilterEnumerator.Filter<GraphNode, DF_Equation>() {
127          @Override
128          public boolean isElement(GraphNode x) {
129            return x instanceof DF_Equation;
130          }
131        });
132  }
133
134  /**
135   * Get the number of equations in this system
136   * @return the number of equations in this system
137   */
138  public int getNumberOfEquations() {
139    return equations.numberOfNodes();
140  }
141
142  /**
143   * Add an equation to the work list.
144   * @param eq the equation to add
145   */
146  public void addToWorkList(DF_Equation eq) {
147    workList.add(eq);
148  }
149
150  /**
151   * Add all new equations to the work list.
152   */
153  public void addNewEquationsToWorkList() {
154    if (DEBUG) {
155      System.out.println("new equations:");
156    }
157    for (DF_Equation eq : newEquations) {
158      if (DEBUG) {
159        System.out.println(eq.toString());
160      }
161      addToWorkList(eq);
162    }
163    newEquations.clear();
164    if (DEBUG) {
165      System.out.println("end of new equations");
166    }
167  }
168
169  /**
170   * Add all equations to the work list.
171   */
172  public void addAllEquationsToWorkList() {
173    for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) {
174      DF_Equation eq = e.nextElement();
175      addToWorkList(eq);
176    }
177  }
178
179  /**
180   * Call this method when the contents of a lattice cell
181   * changes.  This routine adds all equations using this cell
182   * to the set of new equations.
183   * @param cell the lattice cell that has changed
184   */
185  public void changedCell(DF_LatticeCell cell) {
186    Iterator<DF_Equation> e = cell.getUses();
187    while (e.hasNext()) {
188      newEquations.add(e.next());
189    }
190  }
191
192  /**
193   * Finds the cell matching this key. If none found, creates one.
194   *
195   * @param key the key for the lattice cell
196   * @return a suitable cell
197   */
198  protected DF_LatticeCell findOrCreateCell(Object key) {
199    DF_LatticeCell result = cells.get(key);
200    if (result == null) {
201      result = makeCell(key);
202      cells.put(key, result);
203    }
204    return result;
205  }
206
207  /**
208   * Add an equation with one operand on the right-hand side.
209   *
210   * @param lhs the lattice cell set by this equation
211   * @param operator the equation operator
212   * @param op1 first operand on the rhs
213   */
214  protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1) {
215    // add to the list of equations
216    DF_Equation eq = new DF_Equation(lhs, operator, op1);
217    equations.addGraphNode(eq);
218    equations.addGraphNode(lhs);
219    equations.addGraphNode(op1);
220    newEquations.add(eq);
221    // add lattice cells for the operands to the working solution
222    //       cells.put(lhs.getKey(),lhs);
223    //       cells.put(op1.getKey(),op1);
224    op1.addUse(eq);
225    lhs.addDef(eq);
226    if (EAGER && eq.evaluate()) changedCell(lhs);
227  }
228
229  /**
230   * Add an equation with two operands on the right-hand side.
231   *
232   * @param lhs the lattice cell set by this equation
233   * @param operator the equation operator
234   * @param op1 first operand on the rhs
235   * @param op2 second operand on the rhs
236   */
237  void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2) {
238    // add to the list of equations
239    DF_Equation eq = new DF_Equation(lhs, operator, op1, op2);
240    equations.addGraphNode(eq);
241    equations.addGraphNode(lhs);
242    equations.addGraphNode(op1);
243    equations.addGraphNode(op2);
244    newEquations.add(eq);
245    // add lattice cells for the operands to the working solution
246    //       cells.put(lhs.getKey(),lhs);
247    //       cells.put(op1.getKey(),op1);
248    op1.addUse(eq);
249    //       cells.put(op2.getKey(),op2);
250    op2.addUse(eq);
251    lhs.addDef(eq);
252    if (EAGER && eq.evaluate()) changedCell(lhs);
253  }
254
255  /**
256   * Add an equation with three operands on the right-hand side.
257   *
258   * @param lhs the lattice cell set by this equation
259   * @param operator the equation operator
260   * @param op1 first operand on the rhs
261   * @param op2 second operand on the rhs
262   * @param op3 third operand on the rhs
263   */
264  void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2,
265                   DF_LatticeCell op3) {
266    // add to the list of equations
267    DF_Equation eq = new DF_Equation(lhs, operator, op1, op2, op3);
268    equations.addGraphNode(eq);
269    equations.addGraphNode(lhs);
270    equations.addGraphNode(op1);
271    equations.addGraphNode(op2);
272    equations.addGraphNode(op3);
273    newEquations.add(eq);
274    // add lattice cells for the operands to the working solution
275    //       cells.put(lhs.getKey(),lhs);
276    //       cells.put(op1.getKey(),op1);
277    op1.addUse(eq);
278    //       cells.put(op2.getKey(),op2);
279    op2.addUse(eq);
280    //       cells.put(op3.getKey(),op3);
281    op3.addUse(eq);
282    lhs.addDef(eq);
283    if (EAGER && eq.evaluate()) changedCell(lhs);
284  }
285
286  /**
287   * Add an equation to the system with an arbitrary number of operands on
288   * the right-hand side.
289   *
290   * @param lhs lattice cell set by this equation
291   * @param operator the equation operator
292   * @param rhs the operands on the rhs
293   */
294  protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell[] rhs) {
295    // add to the list of equations
296    DF_Equation eq = new DF_Equation(lhs, operator, rhs);
297    equations.addGraphNode(eq);
298    equations.addGraphNode(lhs);
299    newEquations.add(eq);
300    // add the operands to the working solution
301    //       cells.put(lhs.getKey(),lhs);
302    for (DF_LatticeCell rh : rhs) {
303      //        cells.put(rhs[i].getKey(),rhs[i]);
304      rh.addUse(eq);
305      equations.addGraphNode(rh);
306    }
307    lhs.addDef(eq);
308    if (EAGER && eq.evaluate()) changedCell(lhs);
309  }
310
311  /**
312   * Add an existing equation to the system
313   *
314   * @param eq the equation
315   */
316  void addEquation(DF_Equation eq) {
317    equations.addGraphNode(eq);
318    newEquations.add(eq);
319
320    DF_LatticeCell lhs = eq.getLHS();
321    if (!(lhs.getDefs().hasNext() || lhs.getUses().hasNext())) {
322      lhs.addDef(eq);
323      equations.addGraphNode(lhs);
324    } else {
325      lhs.addDef(eq);
326    }
327
328    DF_LatticeCell[] operands = eq.getOperands();
329    for (int i = 1; i < operands.length; i++) {
330      DF_LatticeCell op = operands[i];
331      if (!(op.getDefs().hasNext() || op.getUses().hasNext())) {
332        op.addUse(eq);
333        equations.addGraphNode(op);
334      } else {
335        op.addUse(eq);
336      }
337    }
338
339    if (EAGER && eq.evaluate()) changedCell(lhs);
340  }
341
342  /**
343   * Return the DF_LatticeCell corresponding to a key.
344   *
345   * @param key the key
346   * @return the LatticeCell if found. null otherwise
347   */
348  public DF_LatticeCell getCell(Object key) {
349    return cells.get(key);
350  }
351
352  /**
353   * Add all equations which contain a given cell to the work list.
354   * @param cell the cell in question
355   */
356  public void addCellAppearancesToWorkList(DF_LatticeCell cell) {
357    for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) {
358      DF_Equation eq = e.nextElement();
359      if (eq.hasCell(cell)) {
360        addToWorkList(eq);
361      }
362    }
363  }
364
365  private static final Comparator<DF_Equation> dfComparator = new Comparator<DF_Equation>() {
366    @Override
367    public int compare(DF_Equation o1, DF_Equation o2) {
368      DF_Equation eq1 = o1;
369      DF_Equation eq2 = o2;
370      return (eq1.topologicalNumber - eq2.topologicalNumber);
371    }
372  };
373
374  /**
375   * Initialize all lattice cells in the system.
376   */
377  protected abstract void initializeLatticeCells();
378
379  /**
380   * Initialize the work list for iteration.j
381   */
382  protected abstract void initializeWorkList();
383
384  /**
385   * Create a new lattice cell, referenced by a given key
386   * @param key key to look up the new cell with
387   * @return the newly created lattice cell
388   */
389  protected abstract DF_LatticeCell makeCell(Object key);
390
391  /**
392   * Update the worklist, assuming that a particular equation
393   * has been re-evaluated
394   *
395   * @param eq the equation that has been re-evaluated.
396   */
397  protected void updateWorkList(DF_Equation eq) {
398    // find each equation which uses this lattice cell, and
399    // add it to the work list
400    Iterator<DF_Equation> e = eq.getLHS().getUses();
401    while (e.hasNext()) {
402      workList.add(e.next());
403    }
404  }
405
406  /**
407   *  Number the equations in topological order.
408   *
409   *  <p> PRECONDITION: Already called addGraphEdges()
410   *
411   *  <p>Algorithm:
412   *   <ul>
413   *   <li>     1. create a DAG of SCCs
414   *   <li>     2. number this DAG topologically
415   *   <li>     3. walk through the DAG and number nodes as they are
416   *               encountered
417   *    </ul>
418   */
419  private void numberEquationsTopological() {
420    Enumeration<GraphNode> topOrder = GraphUtilities.
421        enumerateTopSort(equations);
422    Enumeration<GraphNode> rev = new ReverseDFSenumerateByFinish(equations, topOrder);
423    int number = 0;
424    while (rev.hasMoreElements()) {
425      GraphNode elt = rev.nextElement();
426      if (elt instanceof DF_Equation) {
427        DF_Equation eq = (DF_Equation) elt;
428        eq.setTopologicalNumber(number++);
429      }
430    }
431  }
432
433  /**
434   * Debugging aid: print statistics about the dataflow system.
435   */
436  void showGraphStats() {
437    System.out.println("graph has " + equations.numberOfNodes() + " nodes");
438    int count = 0;
439    for (Enumeration<GraphNode> e = equations.enumerateNodes(); e.hasMoreElements();) {
440      GraphNode eq = e.nextElement();
441      Enumeration<GraphNode> outs = eq.outNodes();
442      while (outs.hasMoreElements()) {
443        count++;
444        outs.nextElement();
445      }
446    }
447    System.out.println("graph has " + count + " edges");
448  }
449}