/* * 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; import java.lang.reflect.Constructor; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.ir.AStore; import org.jikesrvm.compilers.opt.ir.BBend; import org.jikesrvm.compilers.opt.ir.GuardResultCarrier; import org.jikesrvm.compilers.opt.ir.Label; import org.jikesrvm.compilers.opt.ir.LocationCarrier; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockOperand; import org.jikesrvm.compilers.opt.ir.OPT_ExceptionHandlerBasicBlock; import org.jikesrvm.compilers.opt.ir.OPT_HeapOperand; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_OperandEnumeration; import org.jikesrvm.compilers.opt.ir.OPT_Operator; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2INT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ADDR_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ARCH_INDEPENDENT_END_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ARRAYLENGTH_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_ADDR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_INT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_NOT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOUNDS_CHECK_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BYTE_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BYTE_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_NOTNULL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_UNRESOLVED_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.CHECKCAST_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2INT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_AS_LONG_BITS_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2INT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_AS_INT_BITS_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GETFIELD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GETSTATIC_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CLASS_OBJECT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_CLASS_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_DOES_IMPLEMENT_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_OBJ_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_SUPERCLASS_IDS_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TYPE_FROM_TIB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_COMBINE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GUARD_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_NOTNULL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_UNRESOLVED_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INSTANCEOF_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRSigExt_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2ADDRZerExt_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2BYTE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2LONG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2SHORT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_2USHORT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_AND_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_BITS_AS_FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_NOT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_OR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_USHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_XOR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.INT_ZERO_CHECK_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2ADDR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2FLOAT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_2INT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_AND_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_BITS_AS_DOUBLE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_CMP_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_DIV_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_MUL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NEG_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_NOT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_OR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_REM_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_USHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_XOR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_ZERO_CHECK_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.MUST_IMPLEMENT_INTERFACE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.NULL_CHECK_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.OBJARRAY_STORE_CHECK_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PI_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PUTFIELD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PUTSTATIC_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ADD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_AND_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_COND_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_MOVE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_NOT_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_OR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHL_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_SUB_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_USHR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.REF_XOR_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SHORT_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.SHORT_ASTORE_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.TRAP_IF_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.UBYTE_ALOAD_opcode; import static org.jikesrvm.compilers.opt.ir.OPT_Operators.USHORT_ALOAD_opcode; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperandEnumeration; import org.jikesrvm.compilers.opt.ir.Phi; import org.jikesrvm.compilers.opt.ir.PutField; import org.jikesrvm.compilers.opt.ir.PutStatic; import org.jikesrvm.compilers.opt.ir.ResultCarrier; /** * This class does the job. It is a subphase of OPT_GCP. */ public class OPT_LICM extends OPT_CompilerPhase { /** Generate debug output? */ private static final boolean DEBUG = false; /** Generate verbose debug output? */ private static boolean verbose = false; /** * Constructor for this compiler phase */ private static final Constructor<OPT_CompilerPhase> constructor = getCompilerPhaseConstructor(OPT_LICM.class); /** * Get a constructor object for this compiler phase * @return compiler phase constructor */ public Constructor<OPT_CompilerPhase> getClassConstructor() { return constructor; } /** * Execute loop invariant code motion on the given IR. * @param ir */ public void perform(OPT_IR ir) { this.ir = ir; if (DEBUG && ir.hasReachableExceptionHandlers()) { VM.sysWrite("] " + ir.method + "\n"); (new OPT_LiveAnalysis(false, false, true, false)).perform(ir); OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); if (b instanceof OPT_ExceptionHandlerBasicBlock) { VM.sysWrite("] " + b + ": " + ((OPT_ExceptionHandlerBasicBlock) b).getLiveSet() + "\n"); } } } if (ir.hasReachableExceptionHandlers() || OPT_GCP.tooBig(ir)) { resetLandingPads(); return; } verbose = ir.options.VERBOSE_GCP; if (verbose && ir.options.hasMETHOD_TO_PRINT()) { verbose = ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString()); if (!verbose) { resetLandingPads(); return; } } if (verbose) VM.sysWrite("] " + ir.method + "\n"); initialize(ir); if (verbose) OPT_SSA.printInstructions(ir); OPT_Instruction inst = ir.firstInstructionInCodeOrder(); while (inst != null) { OPT_Instruction next = inst.nextInstructionInCodeOrder(); if (DEBUG) System.out.println("scheduleEarly: " + inst); scheduleEarly(inst); inst = next; } inst = ir.lastInstructionInCodeOrder(); while (inst != null) { OPT_Instruction next = inst.prevInstructionInCodeOrder(); scheduleLate(inst); inst = next; } resetLandingPads(); if (DEBUG) OPT_SSA.printInstructions(ir); ir.actualSSAOptions.setScalarValid(false); } /** * Returns the name of the phase */ public String getName() { return "LICM"; } /** * Should this phase be executed? * @param options */ public boolean shouldPerform(OPT_Options options) { return options.GCP || options.VERBOSE_GCP; } //------------------------- Implementation ------------------------- /** * Is it save to move the given instruction, depending on we are * in heapSSA form or not? * @param inst * @param ir */ public static boolean shouldMove(OPT_Instruction inst, OPT_IR ir) { if ((inst.isAllocation()) || inst.isDynamicLinkingPoint() || inst.operator.opcode >= ARCH_INDEPENDENT_END_opcode) { return false; } if (ir.IRStage != OPT_IR.HIR && ((inst.isPEI()) || inst.isThrow() || inst.isImplicitLoad() || inst.isImplicitStore())) { return false; } switch (inst.operator.opcode) { case INT_MOVE_opcode: case LONG_MOVE_opcode: case INT_COND_MOVE_opcode: case LONG_COND_MOVE_opcode: case FLOAT_COND_MOVE_opcode: case DOUBLE_COND_MOVE_opcode: case REF_COND_MOVE_opcode: case PUTSTATIC_opcode: case PUTFIELD_opcode: case GETSTATIC_opcode: case GETFIELD_opcode: case INT_ALOAD_opcode: case LONG_ALOAD_opcode: case FLOAT_ALOAD_opcode: case DOUBLE_ALOAD_opcode: case REF_ALOAD_opcode: case BYTE_ALOAD_opcode: case UBYTE_ALOAD_opcode: case SHORT_ALOAD_opcode: case USHORT_ALOAD_opcode: case INT_ASTORE_opcode: case LONG_ASTORE_opcode: case FLOAT_ASTORE_opcode: case DOUBLE_ASTORE_opcode: case REF_ASTORE_opcode: case BYTE_ASTORE_opcode: case SHORT_ASTORE_opcode: case GET_CLASS_OBJECT_opcode: case CHECKCAST_opcode: case CHECKCAST_NOTNULL_opcode: case CHECKCAST_UNRESOLVED_opcode: case MUST_IMPLEMENT_INTERFACE_opcode: case INSTANCEOF_opcode: case INSTANCEOF_NOTNULL_opcode: case INSTANCEOF_UNRESOLVED_opcode: case PI_opcode: case FLOAT_MOVE_opcode: case DOUBLE_MOVE_opcode: case REF_MOVE_opcode: case GUARD_MOVE_opcode: case GUARD_COMBINE_opcode: case TRAP_IF_opcode: case REF_ADD_opcode: case INT_ADD_opcode: case LONG_ADD_opcode: case FLOAT_ADD_opcode: case DOUBLE_ADD_opcode: case REF_SUB_opcode: case INT_SUB_opcode: case LONG_SUB_opcode: case FLOAT_SUB_opcode: case DOUBLE_SUB_opcode: case INT_MUL_opcode: case LONG_MUL_opcode: case FLOAT_MUL_opcode: case DOUBLE_MUL_opcode: case INT_DIV_opcode: case LONG_DIV_opcode: case FLOAT_DIV_opcode: case DOUBLE_DIV_opcode: case INT_REM_opcode: case LONG_REM_opcode: case FLOAT_REM_opcode: case DOUBLE_REM_opcode: case INT_NEG_opcode: case LONG_NEG_opcode: case FLOAT_NEG_opcode: case DOUBLE_NEG_opcode: case REF_SHL_opcode: case INT_SHL_opcode: case LONG_SHL_opcode: case REF_SHR_opcode: case INT_SHR_opcode: case LONG_SHR_opcode: case REF_USHR_opcode: case INT_USHR_opcode: case LONG_USHR_opcode: case REF_AND_opcode: case INT_AND_opcode: case LONG_AND_opcode: case REF_OR_opcode: case INT_OR_opcode: case LONG_OR_opcode: case REF_XOR_opcode: case INT_XOR_opcode: case REF_NOT_opcode: case INT_NOT_opcode: case LONG_NOT_opcode: case LONG_XOR_opcode: case INT_2LONG_opcode: case INT_2FLOAT_opcode: case INT_2DOUBLE_opcode: case INT_2ADDRSigExt_opcode: case INT_2ADDRZerExt_opcode: case LONG_2ADDR_opcode: case ADDR_2INT_opcode: case ADDR_2LONG_opcode: case LONG_2INT_opcode: case LONG_2FLOAT_opcode: case LONG_2DOUBLE_opcode: case FLOAT_2INT_opcode: case FLOAT_2LONG_opcode: case FLOAT_2DOUBLE_opcode: case DOUBLE_2INT_opcode: case DOUBLE_2LONG_opcode: case DOUBLE_2FLOAT_opcode: case INT_2BYTE_opcode: case INT_2USHORT_opcode: case INT_2SHORT_opcode: case LONG_CMP_opcode: case FLOAT_CMPL_opcode: case FLOAT_CMPG_opcode: case DOUBLE_CMPL_opcode: case DOUBLE_CMPG_opcode: case NULL_CHECK_opcode: case BOUNDS_CHECK_opcode: case INT_ZERO_CHECK_opcode: case LONG_ZERO_CHECK_opcode: case OBJARRAY_STORE_CHECK_opcode: case OBJARRAY_STORE_CHECK_NOTNULL_opcode: case BOOLEAN_NOT_opcode: case BOOLEAN_CMP_INT_opcode: case BOOLEAN_CMP_ADDR_opcode: case FLOAT_AS_INT_BITS_opcode: case INT_BITS_AS_FLOAT_opcode: case DOUBLE_AS_LONG_BITS_opcode: case LONG_BITS_AS_DOUBLE_opcode: case ARRAYLENGTH_opcode: case GET_OBJ_TIB_opcode: case GET_CLASS_TIB_opcode: case GET_TYPE_FROM_TIB_opcode: case GET_SUPERCLASS_IDS_FROM_TIB_opcode: case GET_DOES_IMPLEMENT_FROM_TIB_opcode: case GET_ARRAY_ELEMENT_TIB_FROM_TIB_opcode: return !(OPT_GCP.usesOrDefsPhysicalRegisterOrAddressType(inst)); } return false; } /** * Schedule this instruction as early as possible * @param inst */ private OPT_Instruction scheduleEarly(OPT_Instruction inst) { OPT_Instruction _earlyPos; if (getState(inst) >= early) return getEarlyPos(inst); setState(inst, early); setEarlyPos(inst, inst); // already on outer level? //if (ir.HIRInfo.LoopStructureTree.getLoopNestDepth(getBlock(inst)) == 0) // return inst; if (ir.options.FREQ_FOCUS_EFFORT && getOrigBlock(inst).getInfrequent()) { return inst; } // explicitly INCLUDE instructions if (!shouldMove(inst, ir)) { return inst; } // dependencies via scalar operands _earlyPos = scheduleScalarDefsEarly(inst.getUses(), ir.firstInstructionInCodeOrder(), inst); if (VM.VerifyAssertions) VM._assert(_earlyPos != null); // memory dependencies if (ir.IRStage == OPT_IR.HIR) { _earlyPos = scheduleHeapDefsEarly(ssad.getHeapUses(inst), _earlyPos, inst); if (VM.VerifyAssertions) VM._assert(_earlyPos != null); } /* don't put memory stores or PEIs on speculative path */ if ((inst.isPEI() && !ir.options.LICM_IGNORE_PEI) || inst.isImplicitStore()) { while (!postDominates(getBlock(inst), getBlock(_earlyPos))) { _earlyPos = dominanceSuccessor(_earlyPos, inst); } } setEarlyPos(inst, _earlyPos); if (DEBUG && getBlock(_earlyPos) != getBlock(inst)) { VM.sysWrite("new earlyBlock: " + getBlock(_earlyPos) + " for " + getBlock(inst) + ": " + inst + "\n"); } setBlock(inst, getBlock(_earlyPos)); return _earlyPos; } /** * Schedule as late as possible. * @param inst */ OPT_BasicBlock scheduleLate(OPT_Instruction inst) { if (DEBUG) VM.sysWrite("Schedule Late: " + inst + "\n"); OPT_BasicBlock lateBlock = null; int _state = getState(inst); if (_state == late || _state == done) return getBlock(inst); setState(inst, late); if (ir.options.FREQ_FOCUS_EFFORT) { OPT_BasicBlock _origBlock = getOrigBlock(inst); if (_origBlock.getInfrequent()) { return _origBlock; } } // explicitly INCLUDE instructions if (!shouldMove(inst, ir)) { return getOrigBlock(inst); } // dependencies via scalar operands lateBlock = scheduleScalarUsesLate(inst, lateBlock); if (DEBUG) VM.sysWrite("lateBlock1: " + lateBlock + " for " + inst + "\n"); // dependencies via heap operands if (ir.IRStage == OPT_IR.HIR) { lateBlock = scheduleHeapUsesLate(inst, lateBlock); if (DEBUG) VM.sysWrite("lateBlock2: " + lateBlock + " for " + inst + "\n"); } // if there are no uses, this instruction is dead. if (lateBlock == null) { if (verbose) VM.sysWrite("deleting " + inst + "\n"); inst.remove(); } else { if (DEBUG && lateBlock != getOrigBlock(inst)) { VM.sysWrite("new lateBlock: " + lateBlock + " for " + getOrigBlock(inst) + ": " + inst + "\n"); } OPT_BasicBlock to = upto(getEarlyPos(inst), lateBlock, inst); if (to == null) { lateBlock = getOrigBlock(inst); } else { if (VM.VerifyAssertions) VM._assert(getState(inst) != done); lateBlock = to; if (getOrigBlock(inst) != to) move(inst, to); } } setState(inst, done); setBlock(inst, lateBlock); return lateBlock; } /** * return `a's successor on the path from `a' to `b' in the dominator * tree. `a' must dominate `b' and `a' and `b' must belong to * different blocks. */ private OPT_Instruction dominanceSuccessor(OPT_Instruction a, OPT_Instruction b) { OPT_BasicBlock aBlock = getBlock(a); OPT_BasicBlock bBlock = getBlock(b); if (VM.VerifyAssertions) { VM._assert(aBlock != bBlock && dominator.dominates(aBlock, bBlock)); } OPT_BasicBlock last = null; while (bBlock != aBlock) { last = bBlock; bBlock = dominator.getParent(bBlock); } return last.firstInstruction(); } /** * compare a and b according to their depth in the dominator tree * and return the one with the greatest depth. */ private OPT_Instruction maxDominatorDepth(OPT_Instruction a, OPT_Instruction b) { OPT_BasicBlock aBlock = getBlock(a); OPT_BasicBlock bBlock = getBlock(b); int aDomDepth = dominator.depth(aBlock); int bDomDepth = dominator.depth(bBlock); if (aDomDepth > bDomDepth) return a; if (aDomDepth < bDomDepth) return b; if (VM.VerifyAssertions) VM._assert(aBlock == bBlock); // if an instruction depends on a branch, it can not be placed in // this block. Make sure we record this fact. We use this // information in upto() return a.isBranch() ? a : b; } private OPT_BasicBlock commonDominator(OPT_BasicBlock a, OPT_BasicBlock b) { //VM.sysWrite ("CD: "+a+", "+b); if (a == null) return b; if (b == null) return a; while (a != b) { int aDomDepth = dominator.depth(a); int bDomDepth = dominator.depth(b); if (aDomDepth >= bDomDepth) a = dominator.getParent(a); if (bDomDepth >= aDomDepth) b = dominator.getParent(b); } //VM.sysWrite (" = "+a+"\n"); return a; } /** * Schedule me as early as possible, * but behind the definitions in e and behind earlyPos */ private OPT_Instruction scheduleScalarDefsEarly(OPT_OperandEnumeration e, OPT_Instruction earlyPos, OPT_Instruction inst) { while (e.hasMoreElements()) { OPT_Operand op = e.next(); OPT_Instruction def = definingInstruction(op); scheduleEarly(def); if (def.isBranch()) def = dominanceSuccessor(def, inst); earlyPos = maxDominatorDepth(def, earlyPos); } return earlyPos; } /** * Schedule me as early as possible, * but behind the definitions of op[i] and behind earlyPos */ OPT_Instruction scheduleHeapDefsEarly(OPT_HeapOperand<?>[] op, OPT_Instruction earlyPos, OPT_Instruction me) { if (op == null) return earlyPos; for (OPT_HeapOperand<?> anOp : op) { OPT_Instruction def = definingInstruction(anOp); // if (me.isImplicitLoad() || me.isImplicitStore()) // def = _getRealDef(def, me) // ; // else if (me.isPEI()) // def = _getRealExceptionDef(def) // ; if (VM.VerifyAssertions) VM._assert(def != null); earlyPos = maxDominatorDepth(scheduleEarly(def), earlyPos); } return earlyPos; } OPT_BasicBlock useBlock(OPT_Instruction use, OPT_Operand op) { //VM.sysWrite ("UseBlock: "+use+"\n"); OPT_BasicBlock res = scheduleLate(use); if (res != null && Phi.conforms(use)) { int i; for (i = Phi.getNumberOfValues(use) - 1; i >= 0; --i) { if (Phi.getValue(use, i) == op) { res = Phi.getPred(use, i).block; break; } } if (VM.VerifyAssertions) VM._assert(i >= 0); } return res; } /** * Schedule me as late as possible, * but in front of my uses and before latePos */ private OPT_BasicBlock scheduleScalarUsesLate(OPT_Instruction inst, OPT_BasicBlock lateBlock) { OPT_Operand resOp = getResult(inst); if (resOp == null || !(resOp instanceof OPT_RegisterOperand)) { return lateBlock; } OPT_Register res = ((OPT_RegisterOperand) resOp).getRegister(); OPT_RegisterOperandEnumeration e = OPT_DefUse.uses(res); while (e.hasMoreElements()) { OPT_Operand op = e.next(); OPT_Instruction use = op.instruction; OPT_BasicBlock _block = useBlock(use, op); lateBlock = commonDominator(_block, lateBlock); } return lateBlock; } /** * Schedule me as early as possible, * but behind the definitions of op[i] and behind earlyPos */ OPT_BasicBlock scheduleHeapUsesLate(OPT_Instruction inst, OPT_BasicBlock lateBlock) { //VM.sysWrite (" scheduleHeapUsesLate\n"); OPT_Operand[] defs = ssad.getHeapDefs(inst); if (defs == null) return lateBlock; //VM.sysWrite (" defs: "+defs.length+"\n"); for (OPT_Operand def : defs) { @SuppressWarnings("unchecked") // Cast to generic OPT_HeapOperand OPT_HeapOperand<Object> dhop = (OPT_HeapOperand) def; OPT_HeapVariable<Object> H = dhop.value; if (DEBUG) VM.sysWrite("H: " + H + "\n"); Iterator<OPT_HeapOperand<Object>> it = ssad.iterateHeapUses(H); //VM.sysWrite (" H: "+H+" ("+ssad.getNumberOfUses (H)+")\n"); while (it.hasNext()) { OPT_HeapOperand<Object> uhop = it.next(); //VM.sysWrite (" uhop: "+uhop+"\n"); OPT_Instruction use = uhop.instruction; //VM.sysWrite ("use: "+use+"\n"); OPT_BasicBlock _block = useBlock(use, uhop); lateBlock = commonDominator(_block, lateBlock); } } return lateBlock; } /** * Return the instruction that defines the operand. * @param op */ OPT_Instruction definingInstruction(OPT_Operand op) { if (op instanceof OPT_HeapOperand) { @SuppressWarnings("unchecked") // Cast to generic OPT_HeapOperand OPT_HeapOperand<Object> hop = (OPT_HeapOperand) op; OPT_HeapVariable<Object> H = hop.value; OPT_HeapOperand<Object> defiOp = ssad.getUniqueDef(H); // Variable may be defined by caller, so depends on method entry if (defiOp == null || defiOp.instruction == null) { return ir.firstInstructionInCodeOrder(); } else { //VM.sysWrite ("def of "+op+" is "+defiOp.instruction+"\n"); return defiOp.instruction; } } else if (op instanceof OPT_RegisterOperand) { OPT_Register reg = ((OPT_RegisterOperand) op).getRegister(); OPT_RegisterOperandEnumeration defs = OPT_DefUse.defs(reg); if (!defs.hasMoreElements()) { // params have no def return ir.firstInstructionInCodeOrder(); } else { OPT_Instruction def = defs.next().instruction; // we are in SSA, so there is at most one definition. if (VM.VerifyAssertions) VM._assert(!defs.hasMoreElements()); //if (defs.hasMoreElements()) { // VM.sysWrite("GCP: multiple defs: " + reg + "\n"); // return null; //} return def; } } else { // some constant return ir.firstInstructionInCodeOrder(); } } /** * Get the result operand of the instruction * @param inst */ OPT_Operand getResult(OPT_Instruction inst) { if (ResultCarrier.conforms(inst)) { return ResultCarrier.getResult(inst); } if (GuardResultCarrier.conforms(inst)) { return GuardResultCarrier.getGuardResult(inst); } if (Phi.conforms(inst)) { return Phi.getResult(inst); } return null; } /** * Visit the blocks between the late and the early position along * their path in the dominator tree. * Return the block with the smallest execution costs. */ OPT_BasicBlock upto(OPT_Instruction earlyPos, OPT_BasicBlock lateBlock, OPT_Instruction inst) { OPT_BasicBlock _origBlock = getOrigBlock(inst); OPT_BasicBlock actBlock = lateBlock; OPT_BasicBlock bestBlock = lateBlock; OPT_BasicBlock earlyBlock = getBlock(earlyPos); if (VM.VerifyAssertions) { if (!dominator.dominates(earlyBlock.getNumber(), _origBlock.getNumber()) || !dominator.dominates(earlyBlock.getNumber(), lateBlock.getNumber())) { OPT_SSA.printInstructions(ir); VM.sysWrite("> " + earlyBlock.getNumber() + ", " + _origBlock.getNumber() + ", " + lateBlock.getNumber() + "\n"); VM.sysWrite("" + inst + "\n"); } VM._assert(dominator.dominates(earlyBlock.getNumber(), _origBlock.getNumber())); VM._assert(dominator.dominates(earlyBlock.getNumber(), lateBlock.getNumber())); } for (; ;) { /* is the actual block better (less frequent) than the so far best block? */ if (frequency(actBlock) < frequency(bestBlock)) { if (DEBUG) { VM.sysWrite("going from " + frequency(_origBlock) + " to " + frequency(actBlock) + "\n"); } bestBlock = actBlock; } /* all candidates checked? */ if (actBlock == earlyBlock) { break; } /* walk up the dominator tree for next candidate*/ actBlock = dominator.getParent(actBlock); } if (bestBlock == _origBlock) return null; if (DEBUG) VM.sysWrite("best Block: " + bestBlock + "\n"); return bestBlock; } /** * How expensive is it to place an instruction in this block? */ final float frequency(OPT_BasicBlock b) { return b.getExecutionFrequency(); } /** * move `inst' behind `pred' */ void move(OPT_Instruction inst, OPT_BasicBlock to) { OPT_BasicBlock _origBlock = getOrigBlock(inst); OPT_Instruction cand = null; /* find a position within bestBlock */ if (dominator.dominates(_origBlock.getNumber(), to.getNumber())) { // moved down, so insert in from OPT_Instruction last = null; OPT_InstructionEnumeration e = to.forwardInstrEnumerator(); while (e.hasMoreElements()) { cand = e.next(); if (DEBUG) VM.sysWrite(cand.toString() + "\n"); // skip labels, phis, and yieldpoints if (!Label.conforms(cand) && !cand.isYieldPoint() && !Phi.conforms(cand)) { break; } last = cand; } cand = last; } else { // moved up, so insert at end of block OPT_InstructionEnumeration e = to.reverseInstrEnumerator(); while (e.hasMoreElements()) { cand = e.next(); if (DEBUG) VM.sysWrite(cand.toString() + "\n"); // skip branches and newly placed insts if (!BBend.conforms(cand) && !cand.isBranch() && !relocated.contains(cand)) { break; } } if (DEBUG) VM.sysWrite("Adding to relocated: " + inst + "\n"); relocated.add(inst); } if (DEBUG && moved.add(inst.operator)) { VM.sysWrite("m(" + (ir.IRStage == OPT_IR.LIR ? "l" : "h") + ") " + inst.operator + "\n"); } if (verbose) { VM.sysWrite(ir.IRStage == OPT_IR.LIR ? "%" : "#"); VM.sysWrite(" moving " + inst + " from " + _origBlock + " to " + to + "\n" + "behind " + cand + "\n"); } inst.remove(); cand.insertAfter(inst); } //------------------------------------------------------------ // some helper methods //------------------------------------------------------------ /** * does a post dominate b? * @param a * @param b */ boolean postDominates(OPT_BasicBlock a, OPT_BasicBlock b) { boolean res; if (a == b) { return true; } //VM.sysWrite ("does " + a + " postdominate " + b + "?: "); OPT_DominatorInfo info = (OPT_DominatorInfo) b.scratchObject; res = info.isDominatedBy(a); //VM.sysWrite (res ? "yes\n" : "no\n"); return res; } /** * Get the basic block of an instruction * @param inst */ OPT_BasicBlock getBlock(OPT_Instruction inst) { return block[inst.scratch]; } /** * Set the basic block for an instruction * @param inst * @param b */ void setBlock(OPT_Instruction inst, OPT_BasicBlock b) { block[inst.scratch] = b; } /** * Get the early position of an instruction * @param inst */ OPT_Instruction getEarlyPos(OPT_Instruction inst) { return earlyPos[inst.scratch]; } /** * Set the early position for an instruction * @param inst * @param pos */ void setEarlyPos(OPT_Instruction inst, OPT_Instruction pos) { earlyPos[inst.scratch] = pos; } /** * Get the block, where the instruction was originally located * @param inst */ OPT_BasicBlock getOrigBlock(OPT_Instruction inst) { return origBlock[inst.scratch]; } /** * Set the block, where the instruction is originally located. * @param inst * @param b */ void setOrigBlock(OPT_Instruction inst, OPT_BasicBlock b) { origBlock[inst.scratch] = b; } /** * In what state (initial, early, late, done) is this instruction * @param inst */ int getState(OPT_Instruction inst) { return state[inst.scratch]; } /** * Set the state (initial, early, late, done) of the instruction * @param inst * @param s */ void setState(OPT_Instruction inst, int s) { state[inst.scratch] = s; } //------------------------------------------------------------ // initialization //------------------------------------------------------------ /** * initialize the state of the algorithm */ void initialize(OPT_IR ir) { this.ir = ir; relocated = new HashSet<OPT_Instruction>(); if (ir.IRStage == OPT_IR.HIR) { // OPT_SimpleEscape analyzer = new OPT_SimpleEscape(); // escapeSummary = analyzer.simpleEscapeAnalysis(ir); - unused } // Note: the following unfactors the CFG new OPT_DominatorsPhase(true).perform(ir); OPT_Dominators.computeApproxPostdominators(ir); dominator = ir.HIRInfo.dominatorTree; if (DEBUG) VM.sysWrite("" + dominator.toString() + "\n"); int instructions = ir.numberInstructions(); ssad = ir.HIRInfo.SSADictionary; OPT_DefUse.computeDU(ir); ssad.recomputeArrayDU(); // also number implicit heap phis OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); Iterator<OPT_Instruction> pe = ssad.getHeapPhiInstructions(b); while (pe.hasNext()) { OPT_Instruction inst = pe.next(); inst.scratch = instructions++; inst.scratchObject = null; } } state = new int[instructions]; origBlock = new OPT_BasicBlock[instructions]; block = new OPT_BasicBlock[instructions]; earlyPos = new OPT_Instruction[instructions]; e = ir.getBasicBlocks(); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); Enumeration<OPT_Instruction> ie = ssad.getAllInstructions(b); while (ie.hasMoreElements()) { OPT_Instruction inst = ie.nextElement(); setBlock(inst, b); setOrigBlock(inst, b); setState(inst, initial); } } if (ir.IRStage == OPT_IR.HIR) { e = ir.getBasicBlocks(); while (e.hasMoreElements()) { OPT_BasicBlock b = e.next(); if (ir.options.FREQ_FOCUS_EFFORT && b.getInfrequent()) continue; Enumeration<OPT_Instruction> ie = ssad.getAllInstructions(b); while (ie.hasMoreElements()) { OPT_Instruction inst = ie.nextElement(); while (simplify(inst, b)) ; } } ssad.recomputeArrayDU(); } } //------------------------------------------------------------ // private state //------------------------------------------------------------ private static final int initial = 0; private static final int early = 1; private static final int late = 2; private static final int done = 3; private HashSet<OPT_Instruction> relocated; private int[] state; private OPT_BasicBlock[] block; private OPT_BasicBlock[] origBlock; private OPT_Instruction[] earlyPos; private OPT_SSADictionary ssad; private OPT_DominatorTree dominator; private OPT_IR ir; // private OPT_FI_EscapeSummary escapeSummary; - unused private final HashSet<OPT_Operator> moved = DEBUG ? new HashSet<OPT_Operator>() : null; private boolean simplify(OPT_Instruction inst, OPT_BasicBlock block) { if (!Phi.conforms(inst)) return false; // no phi //if (Phi.getNumberOfValues (inst) != 2) return false; // want exactly 2 inputs //VM.sysWrite ("Simplify "+inst+"\n"); OPT_Operand resOp = Phi.getResult(inst); if (!(resOp instanceof OPT_HeapOperand)) { //VM.sysWrite (" no heap op result\n"); return false; // scalar phi } int xidx = -1; OPT_Instruction x = null; for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { OPT_Instruction in = definingInstruction(Phi.getValue(inst, i)); if (getOrigBlock(in) != getOrigBlock(inst) && dominator.dominates(getOrigBlock(in), getOrigBlock(inst))) { if (xidx != -1) return false; xidx = i; x = in; } else if (!dominator.dominates(getOrigBlock(inst), getOrigBlock(in))) { return false; } } if (x == null) return false; replaceUses(inst, (OPT_HeapOperand<?>) Phi.getValue(inst, xidx), Phi.getPred(inst, xidx), true); @SuppressWarnings("unchecked") // Cast to generic OPT_HeapOperand OPT_HeapOperand<Object> hop = (OPT_HeapOperand) resOp; if (hop.value.isExceptionHeapType()) return false; /* check that inside the loop, the heap variable is only used/defed by simple, non-volatile loads or only by stores if so, replace uses of inst (a memory phi) with its dominating input */ int type = checkLoop(inst, hop, xidx, block); if (type == CL_LOADS_ONLY || type == CL_STORES_ONLY || type == CL_NONE) { replaceUses(inst, (OPT_HeapOperand<?>) Phi.getValue(inst, xidx), Phi.getPred(inst, xidx), false); } return false; } static final int CL_NONE = 0; static final int CL_LOADS_ONLY = 1; static final int CL_STORES_ONLY = 2; static final int CL_LOADS_AND_STORES = 3; static final int CL_COMPLEX = 4; /** * check that inside the loop, the heap variable is only used/defed * by simple, non-volatile loads/stores * * returns one of: * CL_LOADS_ONLY, CL_STORES_ONLY, CL_LOADS_AND_STORES, CL_COMPLEX */ @SuppressWarnings("unused") // useful for debugging private int _checkLoop(OPT_Instruction inst, OPT_HeapOperand<?> hop, int xidx) { for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { if (i == xidx) continue; OPT_Instruction y = definingInstruction(Phi.getValue(inst, i)); while (y != inst) { //VM.sysWrite (" y: "+y+"\n"); if (y.isImplicitStore() || y.isPEI() || !LocationCarrier.conforms(y)) { return CL_COMPLEX; } // check for access to volatile field OPT_LocationOperand loc = LocationCarrier.getLocation(y); if (loc == null || loc.mayBeVolatile()) { //VM.sysWrite (" no loc or volatile field\n"); return CL_COMPLEX; } for (OPT_HeapOperand<?> op : ssad.getHeapUses(y)) { if (op.value.isExceptionHeapType()) continue; if (op.getHeapType() != hop.getHeapType()) return CL_COMPLEX; y = definingInstruction(op); } } } return CL_LOADS_ONLY; } /** * check that inside the loop, the heap variable is only used/defed * by simple, non-volatile loads/stores * * returns one of: * CL_LOADS_ONLY, CL_STORES_ONLY, CL_LOADS_AND_STORES, CL_COMPLEX */ private int checkLoop(OPT_Instruction inst, OPT_HeapOperand<Object> hop, int xidx, OPT_BasicBlock block) { HashSet<OPT_Instruction> seen = new HashSet<OPT_Instruction>(); OPT_Queue<OPT_Instruction> workList = new OPT_Queue<OPT_Instruction>(); int _state = CL_NONE; int instUses = 0; seen.add(inst); for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { if (i == xidx) continue; OPT_Instruction y = definingInstruction(Phi.getValue(inst, i)); if (y == inst) instUses++; if (!(seen.contains(y))) { seen.add(y); workList.insert(y); } } while (!(workList.isEmpty())) { OPT_Instruction y = workList.remove(); if (Phi.conforms(y)) { for (int i = Phi.getNumberOfValues(y) - 1; i >= 0; --i) { OPT_Instruction z = definingInstruction(Phi.getValue(y, i)); if (z == inst) instUses++; if (!(seen.contains(z))) { seen.add(z); workList.insert(z); } } } else if ((y.isPEI()) || !LocationCarrier.conforms(y) || y.operator.isAcquire() || y.operator.isRelease()) { return CL_COMPLEX; } else { // check for access to volatile field OPT_LocationOperand loc = LocationCarrier.getLocation(y); if (loc == null || loc.mayBeVolatile()) { //VM.sysWrite (" no loc or volatile field\n"); return CL_COMPLEX; } if (y.isImplicitStore()) { // only accept loop-invariant stores // conservatively estimate loop-invariance by header domination if (!inVariantLocation(y, block)) return CL_COMPLEX; _state |= CL_STORES_ONLY; } else { _state |= CL_LOADS_ONLY; } for (OPT_HeapOperand<?> op : ssad.getHeapUses(y)) { if (op.value.isExceptionHeapType()) continue; if (op.getHeapType() != hop.getHeapType()) return CL_COMPLEX; y = definingInstruction(op); if (y == inst) instUses++; if (!(seen.contains(y))) { seen.add(y); workList.insert(y); } } } } if (_state == CL_STORES_ONLY && ssad.getNumberOfUses(hop.value) != instUses) { return CL_COMPLEX; } return _state; } private boolean inVariantLocation(OPT_Instruction inst, OPT_BasicBlock block) { if (PutStatic.conforms(inst)) return true; if (PutField.conforms(inst)) { return useDominates(PutField.getRef(inst), block); } if (AStore.conforms(inst)) { return ((useDominates(AStore.getArray(inst), block)) && useDominates(AStore.getIndex(inst), block)); } if (VM.VerifyAssertions) { VM._assert(false, "inst: " + inst); } return false; } private boolean useDominates(OPT_Operand op, OPT_BasicBlock block) { if (!(op instanceof OPT_RegisterOperand)) return true; OPT_Instruction inst = definingInstruction(op); OPT_BasicBlock b = getOrigBlock(inst); return b != block && dominator.dominates(b, block); } /** * In the consumers of `inst', replace uses of `inst's result * with uses of `replacement' */ private boolean replaceUses(OPT_Instruction inst, OPT_HeapOperand<?> replacement, OPT_BasicBlockOperand replacementBlock, boolean onlyPEIs) { if (VM.VerifyAssertions) VM._assert(Phi.conforms(inst)); boolean changed = false; @SuppressWarnings("unchecked") // Cast to generic OPT_HeapOperand OPT_HeapOperand<Object> hop = (OPT_HeapOperand) Phi.getResult(inst); OPT_HeapVariable<Object> H = hop.value; Iterator<OPT_HeapOperand<Object>> it = ssad.iterateHeapUses(H); while (it.hasNext()) { hop = it.next(); OPT_Instruction user = hop.instruction; if (onlyPEIs && !user.isPEI()) continue; if (Phi.conforms(user)) { for (int i = 0; i < Phi.getNumberOfValues(user); i++) { if (Phi.getValue(user, i) == hop) { Phi.setValue(user, i, replacement.copy()); Phi.setPred(user, i, (OPT_BasicBlockOperand) replacementBlock.copy()); } } changed |= replacement.value != H; } else { OPT_HeapOperand<?>[] uses = ssad.getHeapUses(user); for (int i = uses.length - 1; i >= 0; --i) { if (uses[i].value == H) { changed |= replacement.value != H; uses[i] = replacement.copy(); uses[i].setInstruction(user); } } } if (DEBUG && changed) { VM.sysWrite(" changing dependency of " + user + "\n" + "from " + H + " to " + replacement + "\n"); } } if (!onlyPEIs) { for (int i = Phi.getNumberOfValues(inst) - 1; i >= 0; --i) { Phi.setValue(inst, i, replacement.copy()); } } return changed; } private void resetLandingPads() { OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); while (e.hasMoreElements()) e.next().clearLandingPad(); } }