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