/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * 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/cpl1.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.ArchitectureSpecific; import org.jikesrvm.ArchitectureSpecific.OPT_PhysicalDefUse; import org.jikesrvm.classloader.VM_TypeReference; import static org.jikesrvm.compilers.opt.ir.OPT_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 OPT_IR, OPT_Instruction, and OPT_BasicBlock. * General clients should use the higher level interfaces provided * by those classes */ public abstract class OPT_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 OPT_InstructionEnumeration forwardIntraBlockIE(final OPT_Instruction start, final OPT_Instruction end) { return new OPT_InstructionEnumeration() { private OPT_Instruction current = start; private final OPT_Instruction last = end; public boolean hasMoreElements() { return current != null; } public OPT_Instruction nextElement() { return next(); } public OPT_Instruction next() { OPT_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 OPT_InstructionEnumeration reverseIntraBlockIE(final OPT_Instruction start, final OPT_Instruction end) { return new OPT_InstructionEnumeration() { private OPT_Instruction current = start; private final OPT_Instruction last = end; public boolean hasMoreElements() { return current != null; } public OPT_Instruction nextElement() { return next(); } public OPT_Instruction next() { OPT_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 OPT_InstructionEnumeration forwardGlobalIE(final OPT_IR ir) { return new OPT_InstructionEnumeration() { private OPT_Instruction current = ir.firstInstructionInCodeOrder(); public boolean hasMoreElements() { return current != null; } public OPT_Instruction nextElement() { return next(); } public OPT_Instruction next() { try { OPT_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 OPT_InstructionEnumeration reverseGlobalIE(final OPT_IR ir) { return new OPT_InstructionEnumeration() { private OPT_Instruction current = ir.lastInstructionInCodeOrder(); public boolean hasMoreElements() { return current != null; } public OPT_Instruction nextElement() { return next(); } public OPT_Instruction next() { try { OPT_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 OPT_BasicBlockEnumeration forwardBE(final OPT_IR ir) { return new OPT_BasicBlockEnumeration() { private OPT_BasicBlock current = ir.firstBasicBlockInCodeOrder(); public boolean hasMoreElements() { return current != null; } public OPT_BasicBlock nextElement() { return next(); } public OPT_BasicBlock next() { try { OPT_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 OPT_BasicBlockEnumeration reverseBE(final OPT_IR ir) { return new OPT_BasicBlockEnumeration() { private OPT_BasicBlock current = ir.lastBasicBlockInCodeOrder(); public boolean hasMoreElements() { return current != null; } public OPT_BasicBlock nextElement() { return next(); } public OPT_BasicBlock next() { try { OPT_BasicBlock res = current; current = current.prevBasicBlockInCodeOrder(); return res; } catch (NullPointerException e) { fail("forwardBE"); return null; // placate jikes } } }; } /** * This class implements an {@link OPT_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.OPT_SSADictionary */ public static final class AllInstructionsEnum implements OPT_InstructionEnumeration { /** * An enumeration of the explicit instructions in the IR for a * basic block */ private final OPT_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<OPT_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 OPT_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(OPT_IR ir, OPT_BasicBlock block) { explicitInstructions = block.forwardInstrEnumerator(); if (ir.inSSAForm()) { implicitInstructions = ir.HIRInfo.SSADictionary.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 OPT_Instruction next() { if (labelInstruction != null) { OPT_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 OPT_Instruction nextElement() { return next(); } } /** * This class implements an {@link OPT_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 OPT_OperandEnumeration} as it iterates over both implicit * and explicit operands. * @see org.jikesrvm.compilers.opt.OPT_SSADictionary */ public static final class AllDefsEnum implements OPT_OperandEnumeration { /** * Enumeration of non-heap operands defined by the instruction */ private final OPT_OperandEnumeration instructionOperands; /** * Array of heap operands defined by the instruction */ private final OPT_HeapOperand<?>[] heapOperands; /** * Current heap operand we're upto for the enumeration */ private int curHeapOperand; /** * Implicit definitions from the operator */ private final ArchitectureSpecific.OPT_PhysicalDefUse.PDUEnumeration implicitDefs; /** * Defining instruction */ private final OPT_Instruction instr; /** * Construct/initialize object * * @param ir Containing IR * @param instr Instruction to get definitions for */ public AllDefsEnum(OPT_IR ir, OPT_Instruction instr) { this.instr = instr; instructionOperands = instr.getDefs(); if (instr.operator().getNumberOfImplicitDefs() > 0) { implicitDefs = ArchitectureSpecific.OPT_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.SSADictionary.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 OPT_Operand next() { if (instructionOperands.hasMoreElements()) { return instructionOperands.next(); } else { if ((implicitDefs != null) && implicitDefs.hasMoreElements()) { OPT_RegisterOperand rop = new OPT_RegisterOperand(implicitDefs.nextElement(), VM_TypeReference.Int); rop.instruction = instr; return rop; } else { if (curHeapOperand >= heapOperands.length) { fail("Regular and heap operands exhausted"); } OPT_HeapOperand<?> result = heapOperands[curHeapOperand]; curHeapOperand++; return result; } } } /** * Next element in the enumeration */ public OPT_Operand nextElement() { return next(); } } /** * This class implements an {@link OPT_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 OPT_OperandEnumeration} as it iterates over both implicit * and explicit operands. * @see org.jikesrvm.compilers.opt.OPT_SSADictionary */ public static final class AllUsesEnum implements OPT_OperandEnumeration { /** * Enumeration of non-heap operands defined by the instruction */ private final OPT_OperandEnumeration instructionOperands; /** * Array of heap operands defined by the instruction */ private final OPT_HeapOperand<?>[] heapOperands; /** * Current heap operand we're upto for the enumeration */ private int curHeapOperand; /** * Implicit uses from the operator */ private final OPT_PhysicalDefUse.PDUEnumeration implicitUses; /** * Defining instruction */ private final OPT_Instruction instr; /** * Construct/initialize object * * @param ir Containing IR * @param instr Instruction to get uses for */ public AllUsesEnum(OPT_IR ir, OPT_Instruction instr) { this.instr = instr; instructionOperands = instr.getUses(); if (instr.operator().getNumberOfImplicitUses() > 0) { implicitUses = OPT_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.SSADictionary.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 OPT_Operand next() { if (instructionOperands.hasMoreElements()) { return instructionOperands.next(); } else { if ((implicitUses != null) && implicitUses.hasMoreElements()) { OPT_RegisterOperand rop = new OPT_RegisterOperand(implicitUses.nextElement(), VM_TypeReference.Int); rop.instruction = instr; return rop; } else { if (curHeapOperand >= heapOperands.length) { fail("Regular and heap operands exhausted"); } OPT_HeapOperand<?> result = heapOperands[curHeapOperand]; curHeapOperand++; return result; } } } /** * Next element in the enumeration */ public OPT_Operand nextElement() { return next(); } } @NoInline private static void fail(String msg) throws java.util.NoSuchElementException { throw new java.util.NoSuchElementException(msg); } }