src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.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/lsra/LinearScanWalker.java Fri Jul 7 09:30:42 2017
--- new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java Fri Jul 7 09:30:42 2017
*** 34,44 ****
--- 34,44 ----
import java.util.List;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig.AllocatableRegisters;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.core.common.util.Util;
! import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.Indent;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
*** 321,335 ****
--- 321,336 ----
return optimalSplitPos;
}
int findOptimalSplitPos(Interval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) {
+ DebugContext debug = allocator.getDebug();
int optimalSplitPos = -1;
if (minSplitPos == maxSplitPos) {
// trivial case, no optimization of split position possible
! if (Debug.isLogEnabled()) {
! Debug.log("min-pos and max-pos are equal, no optimization possible");
! if (debug.isLogEnabled()) {
! debug.log("min-pos and max-pos are equal, no optimization possible");
}
optimalSplitPos = minSplitPos;
} else {
assert minSplitPos < maxSplitPos : "must be true then";
*** 348,387 ****
--- 349,388 ----
AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
if (minBlock == maxBlock) {
// split position cannot be moved to block boundary : so split as late as possible
! if (Debug.isLogEnabled()) {
! Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
! if (debug.isLogEnabled()) {
! debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
}
optimalSplitPos = maxSplitPos;
} else {
if (interval.hasHoleBetween(maxSplitPos - 1, maxSplitPos) && !allocator.isBlockBegin(maxSplitPos)) {
// Do not move split position if the interval has a hole before maxSplitPos.
// Intervals resulting from Phi-Functions have more than one definition (marked
// as mustHaveRegister) with a hole before each definition. When the register is
// needed
// for the second definition : an earlier reloading is unnecessary.
! if (Debug.isLogEnabled()) {
! Debug.log("interval has hole just before maxSplitPos, so splitting at maxSplitPos");
! if (debug.isLogEnabled()) {
! debug.log("interval has hole just before maxSplitPos, so splitting at maxSplitPos");
}
optimalSplitPos = maxSplitPos;
} else {
// seach optimal block boundary between minSplitPos and maxSplitPos
! if (Debug.isLogEnabled()) {
! Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
! if (debug.isLogEnabled()) {
! debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
}
if (doLoopOptimization) {
// Loop optimization: if a loop-end marker is found between min- and
// max-position :
// then split before this loop
int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, allocator.getLastLirInstructionId(minBlock) + 2);
! if (Debug.isLogEnabled()) {
! Debug.log("loop optimization: loop end found at pos %d", loopEndPos);
! if (debug.isLogEnabled()) {
! debug.log("loop optimization: loop end found at pos %d", loopEndPos);
}
assert loopEndPos > minSplitPos : "invalid order";
if (loopEndPos < maxSplitPos) {
// loop-end marker found between min- and max-position
*** 391,415 ****
--- 392,416 ----
// Desired result: uses tagged as shouldHaveRegister inside a loop cause
// a reloading
// of the interval (normally, only mustHaveRegister causes a reloading)
AbstractBlockBase<?> loopBlock = allocator.blockForId(loopEndPos);
! if (Debug.isLogEnabled()) {
! Debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
! if (debug.isLogEnabled()) {
! debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
}
assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between";
int maxSpillPos = allocator.getLastLirInstructionId(loopBlock) + 2;
optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, maxSpillPos);
if (optimalSplitPos == maxSpillPos) {
optimalSplitPos = -1;
! if (Debug.isLogEnabled()) {
! Debug.log("loop optimization not necessary");
! if (debug.isLogEnabled()) {
! debug.log("loop optimization not necessary");
}
} else {
! if (Debug.isLogEnabled()) {
! Debug.log("loop optimization successful");
! if (debug.isLogEnabled()) {
! debug.log("loop optimization successful");
}
}
}
}
*** 418,429 ****
--- 419,430 ----
optimalSplitPos = findOptimalSplitPos(minBlock, maxBlock, maxSplitPos);
}
}
}
}
! if (Debug.isLogEnabled()) {
! Debug.log("optimal split position: %d", optimalSplitPos);
! if (debug.isLogEnabled()) {
! debug.log("optimal split position: %d", optimalSplitPos);
}
return optimalSplitPos;
}
*** 431,442 ****
--- 432,443 ----
// maxSplitPos in two parts:
// 1) the left part has already a location assigned
// 2) the right part is sorted into to the unhandled-list
@SuppressWarnings("try")
void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) {
! try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
+ DebugContext debug = allocator.getDebug();
! try (Indent indent = debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
assert interval.from() < minSplitPos : "cannot split at start of interval";
assert currentPosition < minSplitPos : "cannot split before current position";
assert minSplitPos <= maxSplitPos : "invalid order";
assert maxSplitPos <= interval.to() : "cannot split after end of interval";
*** 448,459 ****
--- 449,460 ----
assert optimalSplitPos > interval.from() : "cannot split at start of interval";
if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
// the split position would be just before the end of the interval
// . no split at all necessary
! if (Debug.isLogEnabled()) {
! Debug.log("no split necessary because optimal split position is at end of interval");
! if (debug.isLogEnabled()) {
! debug.log("no split necessary because optimal split position is at end of interval");
}
return;
}
// must calculate this before the actual split is performed and before split position is
*** 463,474 ****
--- 464,475 ----
if (!allocator.isBlockBegin(optimalSplitPos)) {
// move position before actual instruction (odd opId)
optimalSplitPos = (optimalSplitPos - 1) | 1;
}
! if (Debug.isLogEnabled()) {
! Debug.log("splitting at position %d", optimalSplitPos);
! if (debug.isLogEnabled()) {
! debug.log("splitting at position %d", optimalSplitPos);
}
assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
*** 477,499 ****
--- 478,501 ----
splitPart.setInsertMoveWhenActivated(moveNecessary);
assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
! if (Debug.isLogEnabled()) {
! Debug.log("left interval %s: %s", moveNecessary ? " " : "", interval.logString(allocator));
! Debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
! if (debug.isLogEnabled()) {
! debug.log("left interval %s: %s", moveNecessary ? " " : "", interval.logString(allocator));
! debug.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
}
}
}
// split an interval at the optimal position between minSplitPos and
// maxSplitPos in two parts:
// 1) the left part has already a location assigned
// 2) the right part is always on the stack and therefore ignored in further processing
@SuppressWarnings("try")
void splitForSpilling(Interval interval) {
+ DebugContext debug = allocator.getDebug();
// calculate allowed range of splitting position
int maxSplitPos = currentPosition;
int previousUsage = interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos);
if (previousUsage == currentPosition) {
/*
*** 503,524 ****
--- 505,526 ----
*/
previousUsage = interval.previousUsage(RegisterPriority.MustHaveRegister, maxSplitPos);
}
int minSplitPos = Math.max(previousUsage + 1, interval.from());
! try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
! try (Indent indent = debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
assert interval.state == State.Active : "why spill interval that is not active?";
assert interval.from() <= minSplitPos : "cannot split before start of interval";
assert minSplitPos <= maxSplitPos : "invalid order";
assert maxSplitPos < interval.to() : "cannot split at end end of interval";
assert currentPosition < interval.to() : "interval must not end before current position";
if (minSplitPos == interval.from()) {
// the whole interval is never used, so spill it entirely to memory
! try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
! try (Indent indent2 = debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval,
currentPosition);
allocator.assignSpillSlot(interval);
*** 533,544 ****
--- 535,546 ----
parent = parent.getSplitChildBeforeOpId(parent.from());
if (isRegister(parent.location())) {
if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
// parent is never used, so kick it out of its assigned register
! if (Debug.isLogEnabled()) {
! Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
! if (debug.isLogEnabled()) {
! debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
}
allocator.assignSpillSlot(parent);
handleSpillSlot(parent);
} else {
// do not go further back because the register is actually used by
*** 560,592 ****
--- 562,594 ----
if (!allocator.isBlockBegin(optimalSplitPos)) {
// move position before actual instruction (odd opId)
optimalSplitPos = (optimalSplitPos - 1) | 1;
}
! try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
! try (Indent indent2 = debug.logAndIndent("splitting at position %d", optimalSplitPos)) {
assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
Interval spilledPart = interval.split(optimalSplitPos, allocator);
allocator.assignSpillSlot(spilledPart);
handleSpillSlot(spilledPart);
changeSpillState(spilledPart, optimalSplitPos);
if (!allocator.isBlockBegin(optimalSplitPos)) {
! if (Debug.isLogEnabled()) {
! Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
! if (debug.isLogEnabled()) {
! debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
}
insertMove(optimalSplitPos, interval, spilledPart);
}
// the currentSplitChild is needed later when moves are inserted for reloading
assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
spilledPart.makeCurrentSplitChild();
! if (Debug.isLogEnabled()) {
! Debug.log("left interval: %s", interval.logString(allocator));
! Debug.log("spilled interval : %s", spilledPart.logString(allocator));
! if (debug.isLogEnabled()) {
! debug.log("left interval: %s", interval.logString(allocator));
! debug.log("spilled interval : %s", spilledPart.logString(allocator));
}
}
}
}
}
*** 695,705 ****
--- 697,708 ----
}
}
@SuppressWarnings("try")
boolean allocFreeRegister(Interval interval) {
try (Indent indent = Debug.logAndIndent("trying to find free register for %s", interval)) {
+ DebugContext debug = allocator.getDebug();
+ try (Indent indent = debug.logAndIndent("trying to find free register for %s", interval)) {
initUseLists(true);
freeExcludeActiveFixed();
freeExcludeActiveAny();
freeCollectInactiveFixed(interval);
*** 709,734 ****
--- 712,737 ----
// usePos contains the start of the next interval that has this register assigned
// (either as a fixed register or a normal allocated register in the past)
// only intervals overlapping with cur are processed, non-overlapping invervals can be
// ignored safely
! if (Debug.isLogEnabled()) {
! if (debug.isLogEnabled()) {
// Enable this logging to see all register states
! try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
! try (Indent indent2 = debug.logAndIndent("state of registers:")) {
for (Register register : availableRegs) {
int i = register.number;
! Debug.log("reg %d: usePos: %d", register.number, usePos[i]);
! debug.log("reg %d: usePos: %d", register.number, usePos[i]);
}
}
}
Register hint = null;
Interval locationHint = interval.locationHint(true);
if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
hint = asRegister(locationHint.location());
! if (Debug.isLogEnabled()) {
! Debug.log("hint register %d from interval %s", hint.number, locationHint);
! if (debug.isLogEnabled()) {
! debug.log("hint register %d from interval %s", hint.number, locationHint);
}
}
assert interval.location() == null : "register already assigned to interval";
// the register must be free at least until this position
*** 766,777 ****
--- 769,780 ----
return false;
}
splitPos = usePos[reg.number];
interval.assignLocation(reg.asValue(interval.kind()));
! if (Debug.isLogEnabled()) {
! Debug.log("selected register %d", reg.number);
! if (debug.isLogEnabled()) {
! debug.log("selected register %d", reg.number);
}
assert splitPos > 0 : "invalid splitPos";
if (needSplit) {
// register not available for full interval, so split it
*** 793,803 ****
--- 796,807 ----
}
// Split an Interval and spill it to memory so that cur can be placed in a register
@SuppressWarnings("try")
void allocLockedRegister(Interval interval) {
try (Indent indent = Debug.logAndIndent("alloc locked register: need to split and spill to get register for %s", 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);
*** 819,829 ****
--- 823,833 ----
// 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()) {
! if (debug.isLogEnabled()) {
printRegisterState();
}
reg = null;
ignore = interval.location() != null && isRegister(interval.location()) ? asRegister(interval.location()) : null;
*** 839,869 ****
--- 843,873 ----
}
}
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 (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");
! 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(Debug.INFO_LEVEL, allocator.getLIR(), description);
! debug.dump(DebugContext.INFO_LEVEL, allocator.getLIR(), description);
allocator.printIntervals(description);
throw new OutOfRegistersException("LinearScan: no register found", description);
}
splitAndSpillInterval(interval);
*** 874,885 ****
--- 878,889 ----
boolean needSplit = blockPos[reg.number] <= intervalTo;
int splitPos = blockPos[reg.number];
! if (Debug.isLogEnabled()) {
! Debug.log("decided to use register %d", 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()));
*** 899,914 ****
--- 903,919 ----
", interval.from()=" + interval.from() + "; already used candidates: " + Arrays.toString(availableRegs);
}
@SuppressWarnings("try")
void printRegisterState() {
try (Indent indent2 = Debug.logAndIndent("state of registers:")) {
+ DebugContext debug = allocator.getDebug();
+ try (Indent indent2 = debug.logAndIndent("state of registers:")) {
for (Register reg : availableRegs) {
int i = reg.number;
! try (Indent indent3 = Debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
! try (Indent indent3 = debug.logAndIndent("reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i])) {
for (int j = 0; j < spillIntervals[i].size(); j++) {
! Debug.log("%s ", spillIntervals[i].get(j));
! debug.log("%s ", spillIntervals[i].get(j));
}
}
}
}
}
*** 923,934 ****
--- 928,940 ----
// (an interval got a register until this position)
int pos = interval.from();
if (isOdd(pos)) {
// the current instruction is a call that blocks all registers
if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
if (Debug.isLogEnabled()) {
Debug.log("free register cannot be available because all registers blocked by following call");
+ DebugContext debug = allocator.getDebug();
+ if (debug.isLogEnabled()) {
+ debug.log("free register cannot be available because all registers blocked by following call");
}
// safety check that there is really no register available
assert !allocFreeRegister(interval) : "found a register for this interval";
return true;
*** 1017,1046 ****
--- 1023,1052 ----
// allocate a physical register or memory location to an interval
@Override
@SuppressWarnings("try")
protected boolean activateCurrent(Interval interval) {
boolean result = true;
! try (Indent indent = Debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber)) {
+ DebugContext debug = allocator.getDebug();
! try (Indent indent = debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber)) {
final Value operand = interval.operand;
if (interval.location() != null && isStackSlotValue(interval.location())) {
// activating an interval that has a stack slot assigned . split it at first use
// position
// used for method parameters
! if (Debug.isLogEnabled()) {
! Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
! if (debug.isLogEnabled()) {
! debug.log("interval has spill slot assigned (method parameter) . split it before first use");
}
splitStackInterval(interval);
result = false;
} else {
if (interval.location() == null) {
// interval has not assigned register . normal allocation
// (this is the normal case for most intervals)
! if (Debug.isLogEnabled()) {
! Debug.log("normal allocation of register");
! if (debug.isLogEnabled()) {
! debug.log("normal allocation of register");
}
// assign same spill slot to non-intersecting intervals
combineSpilledIntervals(interval);
*** 1061,1072 ****
--- 1067,1078 ----
// load spilled values that become active from stack slot to register
if (interval.insertMoveWhenActivated()) {
assert interval.isSplitChild();
assert interval.currentSplitChild() != null;
assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
! if (Debug.isLogEnabled()) {
! Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
! if (debug.isLogEnabled()) {
! debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
}
insertMove(interval.from(), interval.currentSplitChild(), interval);
}
interval.makeCurrentSplitChild();
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File