src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Cdiff src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java

Print this page

        

*** 30,51 **** import java.util.Collections; import java.util.EnumSet; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; ! import org.graalvm.compiler.debug.Debug; ! import org.graalvm.compiler.debug.DebugCounter; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; import org.graalvm.compiler.lir.LIRInstruction.OperandMode; import org.graalvm.compiler.lir.StandardOp.MoveOp; import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; import org.graalvm.compiler.lir.framemap.FrameMap; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; - import org.graalvm.util.Equivalence; import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.StackSlot; --- 30,51 ---- import java.util.Collections; import java.util.EnumSet; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; ! import org.graalvm.compiler.debug.CounterKey; ! import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; import org.graalvm.compiler.lir.LIRInstruction.OperandMode; import org.graalvm.compiler.lir.StandardOp.MoveOp; import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; import org.graalvm.compiler.lir.framemap.FrameMap; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; import org.graalvm.util.EconomicMap; + import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.StackSlot;
*** 55,65 **** /** * Removes move instructions, where the destination value is already in place. */ public final class RedundantMoveElimination extends PostAllocationOptimizationPhase { ! private static final DebugCounter deletedMoves = Debug.counter("RedundantMovesEliminated"); @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { Optimization redundantMoveElimination = new Optimization(lirGenRes.getFrameMap()); redundantMoveElimination.doOptimize(lirGenRes.getLIR()); --- 55,65 ---- /** * Removes move instructions, where the destination value is already in place. */ public final class RedundantMoveElimination extends PostAllocationOptimizationPhase { ! private static final CounterKey deletedMoves = DebugContext.counter("RedundantMovesEliminated"); @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) { Optimization redundantMoveElimination = new Optimization(lirGenRes.getFrameMap()); redundantMoveElimination.doOptimize(lirGenRes.getLIR());
*** 134,145 **** /** * The main method doing the elimination of redundant moves. */ @SuppressWarnings("try") private void doOptimize(LIR lir) { ! ! try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) { callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters(); initBlockData(lir); --- 134,145 ---- /** * The main method doing the elimination of redundant moves. */ @SuppressWarnings("try") private void doOptimize(LIR lir) { ! DebugContext debug = lir.getDebug(); ! try (Indent indent = debug.logAndIndent("eliminate redundant moves")) { callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters(); initBlockData(lir);
*** 166,176 **** * in {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}. */ private static final int COMPLEXITY_LIMIT = 30000; private void initBlockData(LIR lir) { ! AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); numRegs = 0; int maxStackLocations = COMPLEXITY_LIMIT / blocks.length; --- 166,176 ---- * in {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}. */ private static final int COMPLEXITY_LIMIT = 30000; private void initBlockData(LIR lir) { ! DebugContext debug = lir.getDebug(); AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); numRegs = 0; int maxStackLocations = COMPLEXITY_LIMIT / blocks.length;
*** 201,211 **** /* * Now we know the number of locations to optimize, so we can allocate the block states. */ int numLocations = numRegs + stackIndices.size(); ! Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size()); for (AbstractBlockBase<?> block : blocks) { BlockData data = new BlockData(numLocations); blockData.put(block, data); } } --- 201,211 ---- /* * Now we know the number of locations to optimize, so we can allocate the block states. */ int numLocations = numRegs + stackIndices.size(); ! debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size()); for (AbstractBlockBase<?> block : blocks) { BlockData data = new BlockData(numLocations); blockData.put(block, data); } }
*** 220,230 **** * @return Returns true on success and false if the control flow is too complex. */ @SuppressWarnings("try") private boolean solveDataFlow(LIR lir) { ! try (Indent indent = Debug.logAndIndent("solve data flow")) { AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); int numIter = 0; --- 220,231 ---- * @return Returns true on success and false if the control flow is too complex. */ @SuppressWarnings("try") private boolean solveDataFlow(LIR lir) { ! DebugContext debug = lir.getDebug(); ! try (Indent indent = debug.logAndIndent("solve data flow")) { AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); int numIter = 0;
*** 234,244 **** int currentValueNum = 1; boolean firstRound = true; boolean changed; do { changed = false; ! try (Indent indent2 = Debug.logAndIndent("new iteration")) { for (AbstractBlockBase<?> block : blocks) { BlockData data = blockData.get(block); /* --- 235,245 ---- int currentValueNum = 1; boolean firstRound = true; boolean changed; do { changed = false; ! try (Indent indent2 = debug.logAndIndent("new iteration")) { for (AbstractBlockBase<?> block : blocks) { BlockData data = blockData.get(block); /*
*** 260,270 **** * exception handler predecessor block (after the invoke, which * throws the exception), and in reality such moves are not in the * control flow in case of an exception. So we assume a save default * for exception handler blocks. */ ! Debug.log("kill all values at entry of block %d", block.getId()); clearValues(data.entryState, valueNum); } else { /* * Merge the states of predecessor blocks */ --- 261,271 ---- * exception handler predecessor block (after the invoke, which * throws the exception), and in reality such moves are not in the * control flow in case of an exception. So we assume a save default * for exception handler blocks. */ ! debug.log("kill all values at entry of block %d", block.getId()); clearValues(data.entryState, valueNum); } else { /* * Merge the states of predecessor blocks */
*** 276,297 **** // Advance by the value numbers which are "consumed" by // clearValues and mergeState valueNum += data.entryState.length; if (newState || firstRound) { ! try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) { /* * Derive the exit state from the entry state by iterating * through all instructions of the block. */ int[] iterState = data.exitState; copyState(iterState, data.entryState); ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block); for (LIRInstruction op : instructions) { ! valueNum = updateState(iterState, op, valueNum); } changed = true; } } if (firstRound) { --- 277,298 ---- // Advance by the value numbers which are "consumed" by // clearValues and mergeState valueNum += data.entryState.length; if (newState || firstRound) { ! try (Indent indent3 = debug.logAndIndent("update block %d", block.getId())) { /* * Derive the exit state from the entry state by iterating * through all instructions of the block. */ int[] iterState = data.exitState; copyState(iterState, data.entryState); ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block); for (LIRInstruction op : instructions) { ! valueNum = updateState(debug, iterState, op, valueNum); } changed = true; } } if (firstRound) {
*** 320,337 **** * Deletes all move instructions where the target location already contains the source * value. */ @SuppressWarnings("try") private void eliminateMoves(LIR lir) { ! try (Indent indent = Debug.logAndIndent("eliminate moves")) { AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); for (AbstractBlockBase<?> block : blocks) { ! try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) { ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block); BlockData data = blockData.get(block); boolean hasDead = false; --- 321,339 ---- * Deletes all move instructions where the target location already contains the source * value. */ @SuppressWarnings("try") private void eliminateMoves(LIR lir) { + DebugContext debug = lir.getDebug(); ! try (Indent indent = debug.logAndIndent("eliminate moves")) { AbstractBlockBase<?>[] blocks = lir.linearScanOrder(); for (AbstractBlockBase<?> block : blocks) { ! try (Indent indent2 = debug.logAndIndent("eliminate moves in block %d", block.getId())) { ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block); BlockData data = blockData.get(block); boolean hasDead = false;
*** 349,368 **** ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op); int sourceIdx = getStateIdx(moveOp.getInput()); int destIdx = getStateIdx(moveOp.getResult()); if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { assert iterState[sourceIdx] != INIT_VALUE; ! Debug.log("delete move %s", op); instructions.set(idx, null); hasDead = true; ! if (deletedMoves.isEnabled()) { ! deletedMoves.increment(); ! } } } // It doesn't harm if updateState is also called for a deleted move ! valueNum = updateState(iterState, op, valueNum); } if (hasDead) { instructions.removeAll(Collections.singleton(null)); } } --- 351,368 ---- ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op); int sourceIdx = getStateIdx(moveOp.getInput()); int destIdx = getStateIdx(moveOp.getResult()); if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { assert iterState[sourceIdx] != INIT_VALUE; ! debug.log("delete move %s", op); instructions.set(idx, null); hasDead = true; ! deletedMoves.increment(debug); } } // It doesn't harm if updateState is also called for a deleted move ! valueNum = updateState(debug, iterState, op, valueNum); } if (hasDead) { instructions.removeAll(Collections.singleton(null)); } }
*** 372,403 **** /** * Updates the state for one instruction. */ @SuppressWarnings("try") ! private int updateState(final int[] state, LIRInstruction op, int initValueNum) { ! try (Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) { if (isEligibleMove(op)) { /* * Handle the special case of a move instruction */ ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op); int sourceIdx = getStateIdx(moveOp.getInput()); int destIdx = getStateIdx(moveOp.getResult()); if (sourceIdx >= 0 && destIdx >= 0) { assert isObjectValue(state[sourceIdx]) || LIRKind.isValue(moveOp.getInput()) : "move op moves object but input is not defined as object " + moveOp; state[destIdx] = state[sourceIdx]; ! Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); return initValueNum; } } int valueNum = initValueNum; if (op.destroysCallerSavedRegisters()) { ! Debug.log("kill all caller save regs"); for (Register reg : callerSaveRegs) { if (reg.number < numRegs) { // Kind.Object is the save default state[reg.number] = encodeValueNum(valueNum++, true); --- 372,403 ---- /** * Updates the state for one instruction. */ @SuppressWarnings("try") ! private int updateState(DebugContext debug, final int[] state, LIRInstruction op, int initValueNum) { ! try (Indent indent = debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) { if (isEligibleMove(op)) { /* * Handle the special case of a move instruction */ ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op); int sourceIdx = getStateIdx(moveOp.getInput()); int destIdx = getStateIdx(moveOp.getResult()); if (sourceIdx >= 0 && destIdx >= 0) { assert isObjectValue(state[sourceIdx]) || LIRKind.isValue(moveOp.getInput()) : "move op moves object but input is not defined as object " + moveOp; state[destIdx] = state[sourceIdx]; ! debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); return initValueNum; } } int valueNum = initValueNum; if (op.destroysCallerSavedRegisters()) { ! debug.log("kill all caller save regs"); for (Register reg : callerSaveRegs) { if (reg.number < numRegs) { // Kind.Object is the save default state[reg.number] = encodeValueNum(valueNum++, true);
*** 422,432 **** if (stateIdx >= 0) { /* * Assign a unique number to the output or temp location. */ state[stateIdx] = encodeValueNum(opValueNum++, !LIRKind.isValue(operand)); ! Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); } } } OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum); --- 422,432 ---- if (stateIdx >= 0) { /* * Assign a unique number to the output or temp location. */ state[stateIdx] = encodeValueNum(opValueNum++, !LIRKind.isValue(operand)); ! debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); } } } OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
*** 445,455 **** * collection. GC will rewrite all object references which are live at this * point. So we can't rely on their values. It would be sufficient to just kill * all values which are referenced in the state (or all values which are not), * but for simplicity we kill all values. */ ! Debug.log("kill all object values"); clearValuesOfKindObject(state, valueNum); valueNum += state.length; } return valueNum; --- 445,455 ---- * collection. GC will rewrite all object references which are live at this * point. So we can't rely on their values. It would be sufficient to just kill * all values which are referenced in the state (or all values which are not), * but for simplicity we kill all values. */ ! debug.log("kill all object values"); clearValuesOfKindObject(state, valueNum); valueNum += state.length; } return valueNum;
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File