src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
*** old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java Mon Mar 20 17:39:56 2017
--- new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java Mon Mar 20 17:39:56 2017
*** 20,44 ****
--- 20,43 ----
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.lir.alloc.trace.bu;
+ import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+ import static jdk.vm.ci.code.ValueUtil.asRegister;
+ import static jdk.vm.ci.code.ValueUtil.isIllegal;
+ import static jdk.vm.ci.code.ValueUtil.isRegister;
import static org.graalvm.compiler.core.common.GraalOptions.DetailedAsserts;
import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isIllegal;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
import org.graalvm.compiler.core.common.alloc.Trace;
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
*** 53,76 ****
--- 52,75 ----
import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
import org.graalvm.compiler.lir.LIRValueUtil;
import org.graalvm.compiler.lir.RedundantMoveElimination;
import org.graalvm.compiler.lir.StandardOp;
import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+ import org.graalvm.compiler.lir.StandardOp.JumpOp;
import org.graalvm.compiler.lir.StandardOp.LabelOp;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.VirtualStackSlot;
import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
+ import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase;
import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolver;
import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
import org.graalvm.compiler.lir.ssa.SSAUtil;
import org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor;
import org.graalvm.compiler.lir.ssi.SSIUtil;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterArray;
import jdk.vm.ci.code.RegisterAttributes;
import jdk.vm.ci.code.RegisterValue;
*** 113,139 ****
--- 112,141 ----
private final ArrayList<LIRInstruction> insertInstructionsBefore;
private final ArrayList<LIRInstruction> insertInstructionsAfter;
private final boolean neverSpillConstants;
+ private final GlobalLivenessInfo livenessInfo;
+
public BottomUpAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig,
! AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant, GlobalLivenessInfo livenessInfo) {
this.target = target;
this.lirGenRes = lirGenRes;
this.spillMoveFactory = spillMoveFactory;
this.registerAllocationConfig = registerAllocationConfig;
this.callerSaveRegs = registerAllocationConfig.getRegisterConfig().getCallerSaveRegisters();
this.registerAttributes = registerAllocationConfig.getRegisterConfig().getAttributesMap();
this.allocatedBlocks = new BitSet(lirGenRes.getLIR().getControlFlowGraph().getBlocks().length);
this.resultTraces = resultTraces;
this.moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, target.arch);
this.neverSpillConstants = neverSpillConstant;
+ this.livenessInfo = livenessInfo;
this.insertInstructionsBefore = new ArrayList<>(4);
this.insertInstructionsAfter = new ArrayList<>(4);
! if (TraceRegisterAllocationPhase.Options.TraceRACacheStackSlots.getValue(lirGenRes.getLIR().getOptions())) {
this.stackSlots = cachedStackSlots;
} else {
this.stackSlots = new AllocatableValue[lirGenRes.getLIR().numVariables()];
}
*** 166,185 ****
--- 168,177 ----
stackSlots[variableIndex] = slot;
TraceRegisterAllocationPhase.allocatedStackSlots.increment();
return slot;
}
private final PhiValueVisitor resolveLoopBackEdgeVisitor = (Value in, Value out) -> {
resolveBackEdge(in, out);
};
private void resolveBackEdge(Value in, Value out) {
if (!isIllegal(in) && !TraceGlobalMoveResolver.isMoveToSelf(out, in)) {
TraceGlobalMoveResolutionPhase.addMapping(moveResolver, out, in);
}
}
@Override
protected void run(@SuppressWarnings("hiding") TargetDescription target, @SuppressWarnings("hiding") LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
allocate(trace);
}
*** 215,225 ****
--- 207,217 ----
if (fromBlock.getSuccessorCount() <= 1) {
if (Debug.isLogEnabled()) {
Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
}
! ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(fromBlock);
LIRInstruction instr = instructions.get(instructions.size() - 1);
if (instr instanceof StandardOp.JumpOp) {
// insert moves before branch
moveResolver.setInsertPosition(instructions, instructions.size() - 1);
} else {
*** 229,239 ****
--- 221,231 ----
} else {
if (Debug.isLogEnabled()) {
Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
}
! if (DetailedAsserts.getValue(getLIR().getOptions())) {
assert lir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
/*
* Because the number of predecessor edges matches the number of successor edges,
* blocks which are reached by switch statements may have be more than one
*** 325,334 ****
--- 317,327 ----
LIRInstruction move = spillMoveFactory.createMove(dst, src);
insertInstructionsAfter.add(move);
Debug.log("insert after %s", move);
} else {
Debug.log("Block end op. No from %s to %s necessary.", src, dst);
+ requireResolution = true;
}
}
private void insertInstructions() {
// TODO (je) this is can probably be improved
*** 350,446 ****
--- 343,518 ----
}
@SuppressWarnings("try")
private void allocateTrace(Trace trace) {
try (Scope s = Debug.scope("BottomUpAllocator", trace.getBlocks()); Indent indent = Debug.logAndIndent("%s (Trace%d)", trace, trace.getId())) {
! AbstractBlockBase<?> successorBlock = null;
for (int i = trace.getBlocks().length - 1; i >= 0; i--) {
! AbstractBlockBase<?> block = trace.getBlocks()[i];
! AbstractBlockBase<?>[] blocks = trace.getBlocks();
+ int lastBlockIdx = blocks.length - 1;
! AbstractBlockBase<?> successorBlock = blocks[lastBlockIdx];
+ // handle last block
+ allocateBlock(successorBlock);
+ // handle remaining blocks
+ for (int i = lastBlockIdx - 1; i >= 0; i--) {
+ AbstractBlockBase<?> block = blocks[i];
// handle PHIs
if (successorBlock != null) {
! resolvePhis(successorBlock, block);
+ resolvePhis(block, successorBlock);
! boolean needResolution = allocateBlock(block);
+
+ if (needResolution) {
+ // resolve local data flow
+ resolveIntraTraceEdge(block, successorBlock);
}
allocateBlock(block);
successorBlock = block;
}
! resolveLocalDataFlow(trace);
! resolveLoopBackEdge(trace);
} catch (Throwable e) {
throw Debug.handle(e);
}
}
+ private final ArrayList<LIRInstruction> phiResolutionMoves = new ArrayList<>();
+
/**
! * Resolve phi values, i.e., set the current location of values in the predecessors block
* (which is not yet allocated) to the location of the variable defined by the phi in the
* successor (which is already allocated). For constant inputs we insert moves.
*/
! private void resolvePhis(AbstractBlockBase<?> successorBlock, AbstractBlockBase<?> block) {
// Note that we are only visiting PHI values, not transient SSI values.
! phiVisitor.loads.clear();
! SSAUtil.forEachPhiValuePair(getLIR(), successorBlock, block, phiVisitor);
if (phiVisitor.loads.size() > 0) {
ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
instructions.addAll(instructions.size() - 1, phiVisitor.loads);
}
}
private final PhiVisitor phiVisitor = new PhiVisitor();
! private void resolvePhis(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+ if (SSAUtil.isMerge(to)) {
! JumpOp jump = SSAUtil.phiOut(getLIR(), from);
! LabelOp label = SSAUtil.phiIn(getLIR(), to);
private final class PhiVisitor implements PhiValueVisitor {
+ assert phiResolutionMoves.isEmpty();
private final ArrayList<LIRInstruction> loads = new ArrayList<>();
+ for (int i = 0; i < label.getPhiSize(); i++) {
+ visitPhiValuePair(jump.getOutgoingValue(i), label.getIncomingValue(i));
+ }
+ if (!phiResolutionMoves.isEmpty()) {
+ ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(from);
+ instructions.addAll(instructions.size() - 1, phiResolutionMoves);
+ phiResolutionMoves.clear();
+ }
+ }
+ }
@Override
public void visit(Value phiIn, Value phiOut) {
+ private void visitPhiValuePair(Value phiOut, Value phiIn) {
assert isStackSlotValue(phiIn) || isRegister(phiIn) : "PHI defined values is not a register or stack slot: " + phiIn;
AllocatableValue in = asAllocatableValue(phiIn);
AllocatableValue dest = isRegister(in) ? getCurrentValue(asRegister(in)) : in;
! final LIRInstruction load;
! final LIRInstruction move;
if (isConstantValue(phiOut)) {
// insert move from constant
! load = spillMoveFactory.createLoad(dest, LIRValueUtil.asConstant(phiOut));
! move = spillMoveFactory.createLoad(dest, LIRValueUtil.asConstant(phiOut));
} else {
assert isVariable(phiOut) : "Not a variable or constant: " + phiOut;
// insert move from variable
! load = spillMoveFactory.createMove(dest, asVariable(phiOut));
! move = spillMoveFactory.createMove(dest, asVariable(phiOut));
+ }
+ Debug.log("Inserting load %s", move);
+ phiResolutionMoves.add(move);
+ }
+
+ private boolean requireResolution;
+
+ /**
+ * Intra-trace edges, i.e., edge where both, the source and the target block are in the same
+ * trace, are either
+ * <ul>
+ * <li><em>immediate forward edges</em>, i.e., an edge from {@code i}th block of the trace
+ * to the {@code (i+1)}th block, or
+ * <li>a <em>loop back-edge</em> from the last block of the trace to the loop header.
+ * </ul>
+ * This property is guaranteed due to splitting of <em>critical edge</em>.
+ *
+ * Since forward edges are handled locally during bottom-up allocation we only need to check
+ * for the second case.
+ */
+ private void resolveLoopBackEdge(Trace trace) {
+ AbstractBlockBase<?>[] blocks = trace.getBlocks();
+ AbstractBlockBase<?> endBlock = blocks[blocks.length - 1];
+ if (endBlock.isLoopEnd()) {
+ assert endBlock.getSuccessorCount() == 1;
+ AbstractBlockBase<?> targetBlock = endBlock.getSuccessors()[0];
+ assert targetBlock.isLoopHeader() : String.format("Successor %s or loop end %s is not a loop header?", targetBlock, endBlock);
+ if (resultTraces.getTraceForBlock(targetBlock).equals(trace)) {
+ resolveLoopBackEdge(endBlock, targetBlock);
}
Debug.log("Inserting load %s", load);
loads.add(load);
return;
}
}
! private void resolveLocalDataFlow(Trace trace) {
for (AbstractBlockBase<?> block : trace.getBlocks()) {
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
if (resultTraces.getTraceForBlock(pred).equals(trace)) {
resolveFindInsertPos(pred, block);
SSIUtil.forEachValuePair(getLIR(), block, pred, resolveLoopBackEdgeVisitor);
! private void resolveLoopBackEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+ assert resultTraces.getTraceForBlock(from).equals(resultTraces.getTraceForBlock(to)) : "Not on the same trace? " + from + " -> " + to;
+ resolveFindInsertPos(from, to);
+ LIR lir = getLIR();
+
+ if (SSAUtil.isMerge(to)) {
+ JumpOp blockEnd = SSAUtil.phiOut(lir, from);
+ LabelOp label = SSAUtil.phiIn(lir, to);
+
+ for (int i = 0; i < label.getPhiSize(); i++) {
+ Value incomingValue = label.getIncomingValue(i);
+ Value outgoingValue = blockEnd.getOutgoingValue(i);
+ resolveValuePair(incomingValue, outgoingValue);
+ }
+ }
+ resolveTraceEdge(from, to);
moveResolver.resolveAndAppendMoves();
}
+
+ private void resolveIntraTraceEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+ assert resultTraces.getTraceForBlock(from).equals(resultTraces.getTraceForBlock(to)) : "Not on the same trace? " + from + " -> " + to;
+ resolveFindInsertPos(from, to);
+ resolveTraceEdge(from, to);
+ moveResolver.resolveAndAppendMoves();
+ }
+
+ private void resolveTraceEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) {
+ Value[] out = livenessInfo.getOutLocation(from);
+ Value[] in = livenessInfo.getInLocation(to);
+
+ assert out != null;
+ assert in != null;
+ assert out.length == in.length;
+
+ for (int i = 0; i < out.length; i++) {
+ Value incomingValue = in[i];
+ Value outgoingValue = out[i];
+ resolveValuePair(incomingValue, outgoingValue);
+ }
}
+
+ private void resolveValuePair(Value incomingValue, Value outgoingValue) {
+ if (!isIllegal(incomingValue) && !TraceGlobalMoveResolver.isMoveToSelf(outgoingValue, incomingValue)) {
+ TraceGlobalMoveResolutionPhase.addMapping(moveResolver, outgoingValue, incomingValue);
}
}
+ /**
+ * @return {@code true} if the block requires data-flow resolution.
+ */
@SuppressWarnings("try")
! private void allocateBlock(AbstractBlockBase<?> block) {
! private boolean allocateBlock(AbstractBlockBase<?> block) {
+ // might be set in insertSpillMoveAfter
+ requireResolution = false;
+
try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
currentInstructions = getLIR().getLIRforBlock(block);
for (currentInstructionIndex = currentInstructions.size() - 1; currentInstructionIndex >= 0; currentInstructionIndex--) {
LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
if (inst != null) {
inst.setId(currentOpId);
! allocateInstruction(inst, block);
}
}
allocatedBlocks.set(block.getId());
}
+ return requireResolution;
}
@SuppressWarnings("try")
! private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block) {
assert op != null && op.id() == currentOpId;
try (Indent indent = Debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
try (Indent indent1 = Debug.logAndIndent("output pos")) {
// spill caller saved registers
if (op.destroysCallerSavedRegisters()) {
*** 459,468 ****
--- 531,543 ----
// op.forEachState(allocRegisterProcedure);
// should have
op.forEachTemp(allocStackOrRegisterProcedure);
op.forEachOutput(allocStackOrRegisterProcedure);
+ if (op instanceof LabelOp) {
+ processIncoming(block, op);
+ }
}
try (Indent indent1 = Debug.logAndIndent("input pos")) {
currentOpId++;
*** 470,496 ****
--- 545,593 ----
op.forEachInput(allocFixedRegisterProcedure);
// variable
op.forEachInput(allocRegisterProcedure);
op.forEachAlive(allocStackOrRegisterProcedure);
+ if (op instanceof BlockEndOp) {
+ processOutgoing(block, op);
+ }
op.forEachState(allocStackOrRegisterProcedure);
op.forEachInput(allocStackOrRegisterProcedure);
}
// insert spill/load instructions
insertInstructions();
currentOpId++;
}
}
+ private void processIncoming(AbstractBlockBase<?> block, LIRInstruction instruction) {
+ int[] vars = livenessInfo.getBlockIn(block);
+ Value[] locs = new Value[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ int varNum = vars[i];
+ if (varNum >= 0) {
+ locs[i] = allocStackOrRegister(instruction, livenessInfo.getVariable(varNum), OperandMode.DEF, LabelOp.incomingFlags);
+ }
+ }
+ livenessInfo.setInLocations(block, locs);
+ }
+
+ private void processOutgoing(AbstractBlockBase<?> block, LIRInstruction instruction) {
+ int[] vars = livenessInfo.getBlockOut(block);
+ Value[] locs = new Value[vars.length];
+ for (int i = 0; i < vars.length; i++) {
+ locs[i] = allocStackOrRegister(instruction, livenessInfo.getVariable(vars[i]), OperandMode.ALIVE, JumpOp.outgoingFlags);
+ }
+ livenessInfo.setOutLocations(block, locs);
+ }
+
private void spillCallerSavedRegisters() {
for (Register reg : callerSaveRegs) {
if (attributes(reg).isAllocatable()) {
evacuateRegisterAndSpill(reg);
assert checkRegisterUsage(reg);
evacuateRegisterAndSpill(reg);
// setCurrentValue(reg, reg.asValue());
setLastRegisterUsage(reg, currentOpId);
}
}
if (Debug.isLogEnabled()) {
Debug.log("operation destroys all caller-save registers");
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File