/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir; import java.util.Iterator; import org.jikesrvm.ArchitectureSpecificOpt; import org.jikesrvm.ArchitectureSpecificOpt.PhysicalDefUse; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.compilers.opt.ir.operand.HeapOperand; import org.jikesrvm.compilers.opt.ir.operand.Operand; import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; import static org.jikesrvm.compilers.opt.ir.Operators.PHI; import org.vmmagic.pragma.NoInline; /** * This class is not meant to be instantiated. * It simply serves as a place to collect the implementation of * primitive IR enumerations. * None of these functions are meant to be called directly from * anywhere except IR, Instruction, and BasicBlock. * General clients should use the higher level interfaces provided * by those classes */ public abstract class IREnumeration { /** * Forward intra basic block instruction enumerations from * from start...last inclusive. * * NB: start and last _must_ be in the same basic block * and must be in the proper relative order. * This code does _not_ check this invariant, and will * simply fail by eventually thowing a NoSuchElementException * if it is not met. Caller's must be sure the invariants are met. * * @param start the instruction to start with * @param end the instruction to end with * @return an enumeration of the instructions from start to end */ public static InstructionEnumeration forwardIntraBlockIE(final Instruction start, final Instruction end) { return new InstructionEnumeration() { private Instruction current = start; private final Instruction last = end; public boolean hasMoreElements() { return current != null; } public Instruction nextElement() { return next(); } public Instruction next() { Instruction res = current; if (current == last) { current = null; } else { try { current = current.getNext(); } catch (NullPointerException e) { fail("forwardIntraBlockIE"); } } return res; } }; } /** * Reverse intra basic block instruction enumerations from * from start...last inclusive. * * NB: start and last _must_ be in the same basic block * and must be in the proper relative order. * This code does _not_ check this invariant, and will * simply fail by eventually thowing a NoSuchElementException * if it is not met. Caller's must be sure the invariants are met. * * @param start the instruction to start with * @param end the instruction to end with * @return an enumeration of the instructions from start to end */ public static InstructionEnumeration reverseIntraBlockIE(final Instruction start, final Instruction end) { return new InstructionEnumeration() { private Instruction current = start; private final Instruction last = end; public boolean hasMoreElements() { return current != null; } public Instruction nextElement() { return next(); } public Instruction next() { Instruction res = current; if (current == last) { current = null; } else { try { current = current.getPrev(); } catch (NullPointerException e) { fail("reverseIntraBlockIE"); } } return res; } }; } /** * A forward enumeration of all the instructions in the IR. * * @param ir the IR to walk over * @return a forward enumeration of the insturctions in ir */ public static InstructionEnumeration forwardGlobalIE(final IR ir) { return new InstructionEnumeration() { private Instruction current = ir.firstInstructionInCodeOrder(); public boolean hasMoreElements() { return current != null; } public Instruction nextElement() { return next(); } public Instruction next() { try { Instruction res = current; current = current.nextInstructionInCodeOrder(); return res; } catch (NullPointerException e) { fail("forwardGlobalIR"); return null; // placate jikes } } }; } /** * A reverse enumeration of all the instructions in the IR. * * @param ir the IR to walk over * @return a forward enumeration of the insturctions in ir */ public static InstructionEnumeration reverseGlobalIE(final IR ir) { return new InstructionEnumeration() { private Instruction current = ir.lastInstructionInCodeOrder(); public boolean hasMoreElements() { return current != null; } public Instruction nextElement() { return next(); } public Instruction next() { try { Instruction res = current; current = current.prevInstructionInCodeOrder(); return res; } catch (NullPointerException e) { fail("forwardGlobalIR"); return null; // placate jikes } } }; } /** * A forward enumeration of all the basic blocks in the IR. * * @param ir the IR to walk over * @return a forward enumeration of the basic blocks in ir */ public static BasicBlockEnumeration forwardBE(final IR ir) { return new BasicBlockEnumeration() { private BasicBlock current = ir.firstBasicBlockInCodeOrder(); public boolean hasMoreElements() { return current != null; } public BasicBlock nextElement() { return next(); } public BasicBlock next() { try { BasicBlock res = current; current = current.nextBasicBlockInCodeOrder(); return res; } catch (NullPointerException e) { fail("forwardBE"); return null; // placate jikes } } }; } /** * A reverse enumeration of all the basic blocks in the IR. * * @param ir the IR to walk over * @return a reverse enumeration of the basic blocks in ir */ public static BasicBlockEnumeration reverseBE(final IR ir) { return new BasicBlockEnumeration() { private BasicBlock current = ir.lastBasicBlockInCodeOrder(); public boolean hasMoreElements() { return current != null; } public BasicBlock nextElement() { return next(); } public BasicBlock next() { try { BasicBlock res = current; current = current.prevBasicBlockInCodeOrder(); return res; } catch (NullPointerException e) { fail("forwardBE"); return null; // placate jikes } } }; } /** * This class implements an {@link InstructionEnumeration} over * all instructions for a basic block. This enumeration includes * explicit instructions in the IR and implicit phi instructions for * heap variables, which are stored only in this lookaside * structure. * @see org.jikesrvm.compilers.opt.ssa.SSADictionary */ public static final class AllInstructionsEnum implements InstructionEnumeration { /** * An enumeration of the explicit instructions in the IR for a * basic block */ private final InstructionEnumeration explicitInstructions; /** * An enumeration of the implicit instructions in the IR for a * basic block. These instructions appear only in the SSA * dictionary lookaside structure. */ private final Iterator<Instruction> implicitInstructions; /** * The label instruction for the basic block - the label is * special as we want it to appear in the enumeration before the * implicit SSA instructions */ private Instruction labelInstruction; /** * Construct an enumeration for all instructions, both implicit and * explicit in the IR, for a given basic block * * @param block the basic block whose instructions this enumerates */ public AllInstructionsEnum(IR ir, BasicBlock block) { explicitInstructions = block.forwardInstrEnumerator(); if (ir.inSSAForm()) { implicitInstructions = ir.HIRInfo.dictionary.getHeapPhiInstructions(block); } else { implicitInstructions = null; } labelInstruction = explicitInstructions.next(); } /** * Are there more elements in the enumeration? * * @return true or false */ public boolean hasMoreElements() { return (((implicitInstructions != null) && implicitInstructions.hasNext()) || explicitInstructions.hasMoreElements()); } /** * Get the next instruction in the enumeration * * @return the next instruction */ public Instruction next() { if (labelInstruction != null) { Instruction temp = labelInstruction; labelInstruction = null; return temp; } else if ((implicitInstructions != null) && implicitInstructions.hasNext()) { return implicitInstructions.next(); } else { return explicitInstructions.next(); } } /** * Get the next instruction in the enumeration * * @return the next instruction */ public Instruction nextElement() { return next(); } } /** * This class implements an {@link OperandEnumeration}. It used * for holding the definitions of a particular instruction and being * used as an enumeration for iterating over. It differs from other * {@link OperandEnumeration} as it iterates over both implicit * and explicit operands. * @see org.jikesrvm.compilers.opt.ssa.SSADictionary */ public static final class AllDefsEnum implements OperandEnumeration { /** * Enumeration of non-heap operands defined by the instruction */ private final OperandEnumeration instructionOperands; /** * Array of heap operands defined by the instruction */ private final HeapOperand<?>[] heapOperands; /** * Current heap operand we're upto for the enumeration */ private int curHeapOperand; /** * Implicit definitions from the operator */ private final ArchitectureSpecificOpt.PhysicalDefUse.PDUEnumeration implicitDefs; /** * Defining instruction */ private final Instruction instr; /** * Construct/initialize object * * @param ir Containing IR * @param instr Instruction to get definitions for */ public AllDefsEnum(IR ir, Instruction instr) { this.instr = instr; instructionOperands = instr.getDefs(); if (instr.operator().getNumberOfImplicitDefs() > 0) { implicitDefs = ArchitectureSpecificOpt.PhysicalDefUse.enumerate(instr.operator().implicitDefs, ir); } else { implicitDefs = null; } if (ir.inSSAForm() && (instr.operator != PHI)) { // Phi instructions store the heap SSA in the actual // instruction heapOperands = ir.HIRInfo.dictionary.getHeapDefs(instr); } else { heapOperands = null; } } /** * Are there any more elements in the enumeration */ public boolean hasMoreElements() { return ((instructionOperands.hasMoreElements()) || ((heapOperands != null) && (curHeapOperand < heapOperands.length)) || ((implicitDefs != null) && (implicitDefs.hasMoreElements()))); } /** * Next element in the enumeration */ public Operand next() { if (instructionOperands.hasMoreElements()) { return instructionOperands.next(); } else { if ((implicitDefs != null) && implicitDefs.hasMoreElements()) { RegisterOperand rop = new RegisterOperand(implicitDefs.nextElement(), TypeReference.Int); rop.instruction = instr; return rop; } else { if (curHeapOperand >= heapOperands.length) { fail("Regular and heap operands exhausted"); } HeapOperand<?> result = heapOperands[curHeapOperand]; curHeapOperand++; return result; } } } /** * Next element in the enumeration */ public Operand nextElement() { return next(); } } /** * This class implements an {@link OperandEnumeration}. It used * for holding the uses of a particular instruction and being used * as an enumeration for iterating over. It differs from other * {@link OperandEnumeration} as it iterates over both implicit * and explicit operands. * @see org.jikesrvm.compilers.opt.ssa.SSADictionary */ public static final class AllUsesEnum implements OperandEnumeration { /** * Enumeration of non-heap operands defined by the instruction */ private final OperandEnumeration instructionOperands; /** * Array of heap operands defined by the instruction */ private final HeapOperand<?>[] heapOperands; /** * Current heap operand we're upto for the enumeration */ private int curHeapOperand; /** * Implicit uses from the operator */ private final PhysicalDefUse.PDUEnumeration implicitUses; /** * Defining instruction */ private final Instruction instr; /** * Construct/initialize object * * @param ir Containing IR * @param instr Instruction to get uses for */ public AllUsesEnum(IR ir, Instruction instr) { this.instr = instr; instructionOperands = instr.getUses(); if (instr.operator().getNumberOfImplicitUses() > 0) { implicitUses = PhysicalDefUse.enumerate(instr.operator().implicitUses, ir); } else { implicitUses = null; } if (ir.inSSAForm() && (instr.operator != PHI)) { // Phi instructions store the heap SSA in the actual // instruction heapOperands = ir.HIRInfo.dictionary.getHeapUses(instr); } else { heapOperands = null; } } /** * Are there any more elements in the enumeration */ public boolean hasMoreElements() { return ((instructionOperands.hasMoreElements()) || ((heapOperands != null) && (curHeapOperand < heapOperands.length)) || ((implicitUses != null) && (implicitUses.hasMoreElements()))); } /** * Next element in the enumeration */ public Operand next() { if (instructionOperands.hasMoreElements()) { return instructionOperands.next(); } else { if ((implicitUses != null) && implicitUses.hasMoreElements()) { RegisterOperand rop = new RegisterOperand(implicitUses.nextElement(), TypeReference.Int); rop.instruction = instr; return rop; } else { if (curHeapOperand >= heapOperands.length) { fail("Regular and heap operands exhausted"); } HeapOperand<?> result = heapOperands[curHeapOperand]; curHeapOperand++; return result; } } } /** * Next element in the enumeration */ public Operand nextElement() { return next(); } } @NoInline private static void fail(String msg) throws java.util.NoSuchElementException { throw new java.util.NoSuchElementException(msg); } }