use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.
the class LinearScanLifetimeAnalysisPhase method buildIntervals.
@SuppressWarnings("try")
protected void buildIntervals(boolean detailedAsserts) {
try (Indent indent = debug.logAndIndent("build intervals")) {
InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, true);
}
};
InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
RegisterPriority p = registerPriorityOfInputOperand(flags);
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
RegisterPriority p = registerPriorityOfInputOperand(flags);
addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getValueKind(), detailedAsserts);
}
};
// create a list with all caller-save registers (cpu, fpu, xmm)
RegisterArray callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
// iterate all blocks in reverse order
for (int i = allocator.blockCount() - 1; i >= 0; i--) {
AbstractBlockBase<?> block = allocator.blockAt(i);
try (Indent indent2 = debug.logAndIndent("handle block %d", block.getId())) {
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
final int blockFrom = allocator.getFirstLirInstructionId(block);
int blockTo = allocator.getLastLirInstructionId(block);
assert blockFrom == instructions.get(0).id();
assert blockTo == instructions.get(instructions.size() - 1).id();
// Update intervals for operands live at the end of this block;
BitSet live = allocator.getBlockData(block).liveOut;
for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
assert live.get(operandNum) : "should not stop here otherwise";
AllocatableValue operand = allocator.intervalFor(operandNum).operand;
if (debug.isLogEnabled()) {
debug.log("live in %d: %s", operandNum, operand);
}
addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal, detailedAsserts);
/*
* Add special use positions for loop-end blocks when the interval is used
* anywhere inside this loop. It's possible that the block was part of a
* non-natural loop, so it might have an invalid loop index.
*/
if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd, detailedAsserts);
}
}
/*
* Iterate all instructions of the block in reverse order. definitions of
* intervals are processed before uses.
*/
for (int j = instructions.size() - 1; j >= 0; j--) {
final LIRInstruction op = instructions.get(j);
final int opId = op.id();
try (Indent indent3 = debug.logAndIndent("handle inst %d: %s", opId, op)) {
// caller-save registers
if (op.destroysCallerSavedRegisters()) {
for (Register r : callerSaveRegs) {
if (allocator.attributes(r).isAllocatable()) {
addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal, detailedAsserts);
}
}
if (debug.isLogEnabled()) {
debug.log("operation destroys all caller-save registers");
}
}
op.visitEachOutput(outputConsumer);
op.visitEachTemp(tempConsumer);
op.visitEachAlive(aliveConsumer);
op.visitEachInput(inputConsumer);
/*
* Add uses of live locals from interpreter's point of view for proper
* debug information generation. Treat these operands as temp values (if
* the live range is extended to a call site, the value would be in a
* register at the call otherwise).
*/
op.visitEachState(stateProc);
// special steps for some instructions (especially moves)
handleMethodArguments(op);
}
}
// end of instruction iteration
}
}
/*
* Add the range [0, 1] to all fixed intervals. the register allocator need not handle
* unhandled fixed intervals.
*/
for (Interval interval : allocator.intervals()) {
if (interval != null && isRegister(interval.operand)) {
interval.addRange(0, 1);
}
}
}
}
use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.
the class MoveResolver method breakCycle.
protected void breakCycle(int spillCandidate) {
// (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
assert spillCandidate != -1 : "no interval in register for spilling found";
// create a new spill interval and assign a stack slot to it
Interval fromInterval = mappingFrom.get(spillCandidate);
// do not allocate a new spill slot for temporary interval, but
// use spill slot assigned to fromInterval. Otherwise moves from
// one stack slot to another can happen (not allowed by LIRAssembler
AllocatableValue spillSlot = fromInterval.spillSlot();
if (spillSlot == null) {
spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
fromInterval.setSpillSlot(spillSlot);
cycleBreakingSlotsAllocated.increment(allocator.getDebug());
}
spillInterval(spillCandidate, fromInterval, spillSlot);
}
use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.
the class MoveResolver method insertMove.
private LIRInstruction insertMove(Constant fromOpr, Interval toInterval) {
assert insertIdx != -1 : "must setup insert position first";
AllocatableValue toOpr = toInterval.operand;
LIRInstruction move;
if (LIRValueUtil.isStackSlotValue(toInterval.location())) {
move = getAllocator().getSpillMoveFactory().createStackLoad(toOpr, fromOpr);
} else {
move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
}
insertionBuffer.append(insertIdx, move);
DebugContext debug = allocator.getDebug();
if (debug.isLogEnabled()) {
debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
}
return move;
}
use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.
the class OptimizingLinearScanWalker method optimize.
@SuppressWarnings("try")
private boolean optimize(int currentPos, AbstractBlockBase<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
// BEGIN initialize and sanity checks
assert currentBlock != null : "block must not be null";
assert currentInterval != null : "interval must not be null";
assert currentBlock.getPredecessorCount() == 1 : "more than one predecessors -> optimization not possible";
if (!currentInterval.isSplitChild()) {
// interval is not a split child -> no need for optimization
return false;
}
if (currentInterval.from() == currentPos) {
// the interval starts at the current position so no need for splitting
return false;
}
// get current location
AllocatableValue currentLocation = currentInterval.location();
assert currentLocation != null : "active intervals must have a location assigned!";
// get predecessor stuff
AbstractBlockBase<?> predecessorBlock = currentBlock.getPredecessors()[0];
int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
AllocatableValue predecessorLocation = predecessorInterval.location();
assert predecessorLocation != null : "handled intervals must have a location assigned!";
if (currentLocation.equals(predecessorLocation)) {
// locations are already equal -> nothing to optimize
return false;
}
if (!isStackSlotValue(predecessorLocation) && !isRegister(predecessorLocation)) {
assert predecessorInterval.canMaterialize();
// value is materialized -> no need for optimization
return false;
}
assert isStackSlotValue(currentLocation) || isRegister(currentLocation) : "current location not a register or stack slot " + currentLocation;
DebugContext debug = allocator.getDebug();
try (Indent indent = debug.logAndIndent("location differs: %s vs. %s", predecessorLocation, currentLocation)) {
// split current interval at current position
debug.log("splitting at position %d", currentPos);
assert allocator.isBlockBegin(currentPos) && ((currentPos & 1) == 0) : "split pos must be even when on block boundary";
Interval splitPart = currentInterval.split(currentPos, allocator);
activeLists.remove(binding, currentInterval);
assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
// the currentSplitChild is needed later when moves are inserted for reloading
assert splitPart.currentSplitChild() == currentInterval : "overwriting wrong currentSplitChild";
splitPart.makeCurrentSplitChild();
if (debug.isLogEnabled()) {
debug.log("left interval : %s", currentInterval.logString(allocator));
debug.log("right interval : %s", splitPart.logString(allocator));
}
if (Options.LSRAOptSplitOnly.getValue(allocator.getOptions())) {
// just add the split interval to the unhandled list
unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
} else {
if (isRegister(predecessorLocation)) {
splitRegisterInterval(splitPart, asRegister(predecessorLocation));
} else {
assert isStackSlotValue(predecessorLocation);
debug.log("assigning interval %s to %s", splitPart, predecessorLocation);
splitPart.assignLocation(predecessorLocation);
// activate interval
activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, splitPart);
splitPart.state = State.Active;
splitStackInterval(splitPart);
}
}
}
return true;
}
use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.
the class TraceGlobalMoveResolver method breakCycle.
@SuppressWarnings("try")
private void breakCycle(int spillCandidate) {
// (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
assert spillCandidate != -1 : "no interval in register for spilling found";
// create a new spill interval and assign a stack slot to it
Value from = mappingFrom.get(spillCandidate);
try (Indent indent = debug.logAndIndent("BreakCycle: %s", from)) {
AllocatableValue spillSlot = null;
if (TraceRegisterAllocationPhase.Options.TraceRAreuseStackSlotsForMoveResolutionCycleBreaking.getValue(options) && !isStackSlotValue(from)) {
// don't use the stack slot if from is already the stack slot
Value fromStack = mappingFromStack.get(spillCandidate);
if (fromStack != null) {
spillSlot = (AllocatableValue) fromStack;
cycleBreakingSlotsReused.increment(debug);
debug.log("reuse slot for spilling: %s", spillSlot);
}
}
if (spillSlot == null) {
spillSlot = frameMapBuilder.allocateSpillSlot(from.getValueKind());
cycleBreakingSlotsAllocated.increment(debug);
debug.log("created new slot for spilling: %s", spillSlot);
// insert a move from register to stack and update the mapping
LIRInstruction move = insertMove(from, spillSlot);
move.setComment(res, "TraceGlobalMoveResolver: breakCycle");
}
block(spillSlot);
mappingFrom.set(spillCandidate, spillSlot);
unblock(from);
}
}
Aggregations