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.ir;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.PHI;
016
017import java.util.Enumeration;
018import java.util.Iterator;
019
020import org.jikesrvm.classloader.TypeReference;
021import org.jikesrvm.compilers.opt.ir.operand.HeapOperand;
022import org.jikesrvm.compilers.opt.ir.operand.Operand;
023import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
024import org.vmmagic.pragma.NoInline;
025
026/**
027 * This class is not meant to be instantiated.<p>
028 * It simply serves as a place to collect the implementation of
029 * primitive IR enumerations.<p>
030 * None of these functions are meant to be called directly from
031 * anywhere except IR, Instruction, and BasicBlock.<p>
032 * General clients should use the higher level interfaces provided
033 * by those classes.
034 */
035public abstract class IREnumeration {
036
037  /**
038   * Forward intra basic block instruction enumerations from
039   * from start...last inclusive.<p>
040   *
041   * NB: start and last _must_ be in the same basic block
042   *     and must be in the proper relative order.
043   *     This code does _not_ check this invariant, and will
044   *     simply fail by eventually thowing a NoSuchElementException
045   *     if it is not met. Caller's must be sure the invariants are met.
046   *
047   * @param start the instruction to start with
048   * @param end   the instruction to end with
049   * @return an enumeration of the instructions from start to end
050   */
051  public static Enumeration<Instruction> forwardIntraBlockIE(final Instruction start, final Instruction end) {
052    return new Enumeration<Instruction>() {
053      private Instruction current = start;
054      private final Instruction last = end;
055
056      @Override
057      public boolean hasMoreElements() {
058        return current != null;
059      }
060
061      @Override
062      public Instruction nextElement() {
063        Instruction res = current;
064        if (current == last) {
065          current = null;
066        } else {
067          try {
068            current = current.getNext();
069          } catch (NullPointerException e) {
070            fail("forwardIntraBlockIE");
071          }
072        }
073        return res;
074      }
075    };
076  }
077
078  /**
079   * Reverse intra basic block instruction enumerations from
080   * from start...last inclusive.<p>
081   *
082   * NB: start and last _must_ be in the same basic block
083   *     and must be in the proper relative order.
084   *     This code does _not_ check this invariant, and will
085   *     simply fail by eventually thowing a NoSuchElementException
086   *     if it is not met. Caller's must be sure the invariants are met.
087   *
088   * @param start the instruction to start with
089   * @param end   the instruction to end with
090   * @return an enumeration of the instructions from start to end
091   */
092  public static Enumeration<Instruction> reverseIntraBlockIE(final Instruction start, final Instruction end) {
093    return new Enumeration<Instruction>() {
094      private Instruction current = start;
095      private final Instruction last = end;
096
097      @Override
098      public boolean hasMoreElements() {
099        return current != null;
100      }
101
102      @Override
103      public Instruction nextElement() {
104        Instruction res = current;
105        if (current == last) {
106          current = null;
107        } else {
108          try {
109            current = current.getPrev();
110          } catch (NullPointerException e) {
111            fail("reverseIntraBlockIE");
112          }
113        }
114        return res;
115      }
116    };
117  }
118
119  /**
120   * A forward enumeration of all the instructions in the IR.
121   *
122   * @param ir the IR to walk over
123   * @return a forward enumeration of the insturctions in ir
124   */
125  public static Enumeration<Instruction> forwardGlobalIE(final IR ir) {
126    return new Enumeration<Instruction>() {
127      private Instruction current = ir.firstInstructionInCodeOrder();
128
129      @Override
130      public boolean hasMoreElements() {
131        return current != null;
132      }
133
134      @Override
135      public Instruction nextElement() {
136        try {
137          Instruction res = current;
138          current = current.nextInstructionInCodeOrder();
139          return res;
140        } catch (NullPointerException e) {
141          fail("forwardGlobalIR");
142          return null;
143        }
144      }
145    };
146  }
147
148  /**
149   * A reverse enumeration of all the instructions in the IR.
150   *
151   * @param ir the IR to walk over
152   * @return a forward enumeration of the insturctions in ir
153   */
154  public static Enumeration<Instruction> reverseGlobalIE(final IR ir) {
155    return new Enumeration<Instruction>() {
156      private Instruction current = ir.lastInstructionInCodeOrder();
157
158      @Override
159      public boolean hasMoreElements() {
160        return current != null;
161      }
162
163      @Override
164      public Instruction nextElement() {
165        try {
166          Instruction res = current;
167          current = current.prevInstructionInCodeOrder();
168          return res;
169        } catch (NullPointerException e) {
170          fail("forwardGlobalIR");
171          return null;
172        }
173      }
174    };
175  }
176
177  /**
178   * A forward enumeration of all the basic blocks in the IR.
179   *
180   * @param ir the IR to walk over
181   * @return a forward enumeration of the basic blocks in ir
182   */
183  public static Enumeration<BasicBlock> forwardBE(final IR ir) {
184    return new Enumeration<BasicBlock>() {
185      private BasicBlock current = ir.firstBasicBlockInCodeOrder();
186
187      @Override
188      public boolean hasMoreElements() {
189        return current != null;
190      }
191
192      @Override
193      public BasicBlock nextElement() {
194        try {
195          BasicBlock res = current;
196          current = current.nextBasicBlockInCodeOrder();
197          return res;
198        } catch (NullPointerException e) {
199          fail("forwardBE");
200          return null;
201        }
202      }
203    };
204  }
205
206  /**
207   * A reverse enumeration of all the basic blocks in the IR.
208   *
209   * @param ir the IR to walk over
210   * @return a reverse enumeration of the basic blocks in ir
211   */
212  public static Enumeration<BasicBlock> reverseBE(final IR ir) {
213    return new Enumeration<BasicBlock>() {
214      private BasicBlock current = ir.lastBasicBlockInCodeOrder();
215
216      @Override
217      public boolean hasMoreElements() {
218        return current != null;
219      }
220
221      @Override
222      public BasicBlock nextElement() {
223        try {
224          BasicBlock res = current;
225          current = current.prevBasicBlockInCodeOrder();
226          return res;
227        } catch (NullPointerException e) {
228          fail("forwardBE");
229          return null;
230        }
231      }
232    };
233  }
234
235  /**
236   * This class implements an enumeration of instructions over
237   * all instructions for a basic block. This enumeration includes
238   * explicit instructions in the IR and implicit phi instructions for
239   * heap variables, which are stored only in this lookaside
240   * structure.
241   * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
242   */
243  public static final class AllInstructionsEnum implements Enumeration<Instruction> {
244    /**
245     * An enumeration of the explicit instructions in the IR for a
246     * basic block
247     */
248    private final Enumeration<Instruction> explicitInstructions;
249
250    /**
251     * An enumeration of the implicit instructions in the IR for a
252     * basic block.  These instructions appear only in the SSA
253     * dictionary lookaside structure.
254     */
255    private final Iterator<Instruction> implicitInstructions;
256
257    /**
258     * The label instruction for the basic block - the label is
259     * special as we want it to appear in the enumeration before the
260     * implicit SSA instructions
261     */
262    private Instruction labelInstruction;
263
264    /**
265     * Construct an enumeration for all instructions, both implicit and
266     * explicit in the IR, for a given basic block
267     *
268     * @param ir the containing IR
269     * @param block the basic block whose instructions this enumerates
270     */
271    public AllInstructionsEnum(IR ir, BasicBlock block) {
272      explicitInstructions = block.forwardInstrEnumerator();
273      if (ir.inSSAForm()) {
274        implicitInstructions = ir.HIRInfo.dictionary.getHeapPhiInstructions(block);
275      } else {
276        implicitInstructions = null;
277      }
278      labelInstruction = explicitInstructions.nextElement();
279    }
280
281    /**
282     * Are there more elements in the enumeration?
283     *
284     * @return {@code true} or {@code false}
285     */
286    @Override
287    public boolean hasMoreElements() {
288      return (((implicitInstructions != null) && implicitInstructions.hasNext()) ||
289              explicitInstructions.hasMoreElements());
290    }
291
292    @Override
293    public Instruction nextElement() {
294      if (labelInstruction != null) {
295        Instruction temp = labelInstruction;
296        labelInstruction = null;
297        return temp;
298      } else if ((implicitInstructions != null) && implicitInstructions.hasNext()) {
299        return implicitInstructions.next();
300      } else {
301        return explicitInstructions.nextElement();
302      }
303    }
304  }
305
306  /**
307   * This class implements an {@link Enumeration} of {@link Operand}s. It used
308   * for holding the definitions of a particular instruction and being
309   * used as an enumeration for iterating over. It differs from other
310   * enumerations of Operand as it iterates over both implicit
311   * and explicit operands.
312   * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
313   */
314  public static final class AllDefsEnum implements Enumeration<Operand> {
315    /**
316     * Enumeration of non-heap operands defined by the instruction
317     */
318    private final Enumeration<Operand> instructionOperands;
319    /**
320     * Array of heap operands defined by the instruction
321     */
322    private final HeapOperand<?>[] heapOperands;
323    /**
324     * Current heap operand we're upto for the enumeration
325     */
326    private int curHeapOperand;
327    /**
328     * Implicit definitions from the operator
329     */
330    private final Enumeration<Register> implicitDefs;
331    /**
332     * Defining instruction
333     */
334    private final Instruction instr;
335
336    /**
337     * Construct/initialize object
338     *
339     * @param ir    Containing IR
340     * @param instr Instruction to get definitions for
341     */
342    public AllDefsEnum(IR ir, Instruction instr) {
343      this.instr = instr;
344      instructionOperands = instr.getDefs();
345      if (instr.operator().getNumberOfImplicitDefs() > 0) {
346        implicitDefs = GenericPhysicalDefUse.enumerate(instr.operator().implicitDefs, ir);
347      } else {
348        implicitDefs = null;
349      }
350      if (ir.inSSAForm() && (instr.operator() != PHI)) {
351        // Phi instructions store the heap SSA in the actual
352        // instruction
353        heapOperands = ir.HIRInfo.dictionary.getHeapDefs(instr);
354      } else {
355        heapOperands = null;
356      }
357    }
358
359    /**
360     * Are there any more elements in the enumeration
361     */
362    @Override
363    public boolean hasMoreElements() {
364      return ((instructionOperands.hasMoreElements()) ||
365              ((heapOperands != null) && (curHeapOperand < heapOperands.length)) ||
366              ((implicitDefs != null) && (implicitDefs.hasMoreElements())));
367    }
368
369    @Override
370    public Operand nextElement() {
371      if (instructionOperands.hasMoreElements()) {
372        return instructionOperands.nextElement();
373      } else {
374        if ((implicitDefs != null) && implicitDefs.hasMoreElements()) {
375          RegisterOperand rop = new RegisterOperand(implicitDefs.nextElement(), TypeReference.Int);
376          rop.instruction = instr;
377          return rop;
378        } else {
379          if (curHeapOperand >= heapOperands.length) {
380            fail("Regular and heap operands exhausted");
381          }
382          HeapOperand<?> result = heapOperands[curHeapOperand];
383          curHeapOperand++;
384          return result;
385        }
386      }
387    }
388  }
389
390  /**
391   * This class implements an {@link Enumeration} of {@link Operand}. It used
392   * for holding the uses of a particular instruction and being used
393   * as an enumeration for iterating over. It differs from other
394   * enumerations of Operand as it iterates over both implicit
395   * and explicit operands.
396   * @see org.jikesrvm.compilers.opt.ssa.SSADictionary
397   */
398  public static final class AllUsesEnum implements Enumeration<Operand> {
399    /**
400     * Enumeration of non-heap operands defined by the instruction
401     */
402    private final Enumeration<Operand> instructionOperands;
403    /**
404     * Array of heap operands defined by the instruction
405     */
406    private final HeapOperand<?>[] heapOperands;
407    /**
408     * Current heap operand we're upto for the enumeration
409     */
410    private int curHeapOperand;
411    /**
412     * Implicit uses from the operator
413     */
414    private final Enumeration<Register> implicitUses;
415    /**
416     * Defining instruction
417     */
418    private final Instruction instr;
419
420    /**
421     * Construct/initialize object
422     *
423     * @param ir    Containing IR
424     * @param instr Instruction to get uses for
425     */
426    public AllUsesEnum(IR ir, Instruction instr) {
427      this.instr = instr;
428      instructionOperands = instr.getUses();
429      if (instr.operator().getNumberOfImplicitUses() > 0) {
430        implicitUses = GenericPhysicalDefUse.enumerate(instr.operator().implicitUses, ir);
431      } else {
432        implicitUses = null;
433      }
434      if (ir.inSSAForm() && (instr.operator() != PHI)) {
435        // Phi instructions store the heap SSA in the actual
436        // instruction
437        heapOperands = ir.HIRInfo.dictionary.getHeapUses(instr);
438      } else {
439        heapOperands = null;
440      }
441    }
442
443    /**
444     * Are there any more elements in the enumeration
445     */
446    @Override
447    public boolean hasMoreElements() {
448      return ((instructionOperands.hasMoreElements()) ||
449              ((heapOperands != null) && (curHeapOperand < heapOperands.length)) ||
450              ((implicitUses != null) && (implicitUses.hasMoreElements())));
451    }
452
453    @Override
454    public Operand nextElement() {
455      if (instructionOperands.hasMoreElements()) {
456        return instructionOperands.nextElement();
457      } else {
458        if ((implicitUses != null) && implicitUses.hasMoreElements()) {
459          RegisterOperand rop = new RegisterOperand(implicitUses.nextElement(), TypeReference.Int);
460          rop.instruction = instr;
461          return rop;
462        } else {
463          if (curHeapOperand >= heapOperands.length) {
464            fail("Regular and heap operands exhausted");
465          }
466          HeapOperand<?> result = heapOperands[curHeapOperand];
467          curHeapOperand++;
468          return result;
469        }
470      }
471    }
472  }
473
474  @NoInline
475  private static void fail(String msg) throws java.util.NoSuchElementException {
476    throw new java.util.NoSuchElementException(msg);
477  }
478}