use of org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority in project graal by oracle.
the class LinearScanWalker method allocLockedRegister.
// Split an Interval and spill it to memory so that cur can be placed in a register
@SuppressWarnings("try")
void allocLockedRegister(Interval interval) {
DebugContext debug = allocator.getDebug();
try (Indent indent = debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", interval)) {
// the register must be free at least until this position
int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister);
int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister);
int regNeededUntil = Math.min(firstUsage, interval.from() + 1);
int intervalTo = interval.to();
assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use";
Register reg;
Register ignore;
/*
* In the common case we don't spill registers that have _any_ use position that is
* closer than the next use of the current interval, but if we can't spill the current
* interval we weaken this strategy and also allow spilling of intervals that have a
* non-mandatory requirements (no MustHaveRegister use position).
*/
for (RegisterPriority registerPriority = RegisterPriority.LiveAtLoopEnd; true; registerPriority = RegisterPriority.MustHaveRegister) {
// collect current usage of registers
initUseLists(false);
spillExcludeActiveFixed();
// spillBlockUnhandledFixed(cur);
assert unhandledLists.get(RegisterBinding.Fixed).isEndMarker() : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0";
spillBlockInactiveFixed(interval);
spillCollectActiveAny(registerPriority);
spillCollectInactiveAny(interval);
if (debug.isLogEnabled()) {
printRegisterState();
}
reg = null;
ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
for (Register availableReg : availableRegs) {
int number = availableReg.number;
if (availableReg.equals(ignore)) {
// this register must be ignored
} else if (usePos[number] > regNeededUntil) {
if (reg == null || (usePos[number] > usePos[reg.number])) {
reg = availableReg;
}
}
}
int regUsePos = (reg == null ? 0 : usePos[reg.number]);
if (regUsePos <= firstShouldHaveUsage) {
if (debug.isLogEnabled()) {
debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
}
if (firstUsage <= interval.from() + 1) {
if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
/*
* Tool of last resort: we can not spill the current interval so we try
* to spill an active interval that has a usage but do not require a
* register.
*/
debug.log("retry with register priority must have register");
continue;
}
String description = generateOutOfRegErrorMsg(interval, firstUsage, availableRegs);
/*
* assign a reasonable register and do a bailout in product mode to avoid
* errors
*/
allocator.assignSpillSlot(interval);
debug.dump(DebugContext.INFO_LEVEL, allocator.getLIR(), description);
allocator.printIntervals(description);
throw new OutOfRegistersException("LinearScan: no register found", description);
}
splitAndSpillInterval(interval);
return;
}
break;
}
boolean needSplit = blockPos[reg.number] <= intervalTo;
int splitPos = blockPos[reg.number];
if (debug.isLogEnabled()) {
debug.log("decided to use register %d", reg.number);
}
assert splitPos > 0 : "invalid splitPos";
assert needSplit || splitPos > interval.from() : "splitting interval at from";
interval.assignLocation(reg.asValue(interval.kind()));
if (needSplit) {
// register not available for full interval : so split it
splitWhenPartialRegisterAvailable(interval, splitPos);
}
// perform splitting and spilling for all affected intervals
splitAndSpillIntersectingIntervals(reg);
return;
}
}
use of org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority 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);
}
}
}
}
Aggregations