Only block registers temporarily in register allocation workarounds
Change-Id: Ibbe53001176ee01c16b702cc6f0df1924e257e28
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index c280514..827f316 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1640,7 +1640,7 @@
}
// Set all free positions for possible registers to max integer.
- RegisterPositions freePositions = new RegisterPositions(registerConstraint + 1);
+ RegisterPositions freePositions = new RegisterPositionsImpl(registerConstraint + 1);
if ((options().debug || code.method().getOptimizationInfo().isReachabilitySensitive())
&& !code.method().accessFlags.isStatic()) {
@@ -1958,13 +1958,13 @@
LiveIntervals unhandledInterval,
int registerConstraint,
boolean needsRegisterPair,
- RegisterPositions freePositions,
+ RegisterPositionsWithExtraBlockedRegisters freePositions,
RegisterPositions.Type type) {
if (workaroundNeeded.test(unhandledInterval)) {
int lastCandidate = candidate;
while (workaroundNeededForCandidate.test(unhandledInterval, candidate)) {
// Make the unusable register unavailable for allocation and try again.
- freePositions.setBlocked(candidate);
+ freePositions.setBlockedTemporarily(candidate);
candidate =
getLargestCandidate(
unhandledInterval, registerConstraint, freePositions, needsRegisterPair, type);
@@ -1972,8 +1972,17 @@
// candidate returned again once we have tried them all. In that case we didn't find a
// valid register candidate and we need to broaden the search to other types.
if (lastCandidate == candidate) {
+ assert false
+ : "Unexpected attempt to take blocked register "
+ + candidate
+ + " in "
+ + code.context().toSourceString();
return REGISTER_CANDIDATE_NOT_FOUND;
}
+ // If we did not find a valid register, then give up, and broaden the search to other types.
+ if (candidate == REGISTER_CANDIDATE_NOT_FOUND) {
+ return candidate;
+ }
lastCandidate = candidate;
}
}
@@ -1992,6 +2001,10 @@
if (candidate == REGISTER_CANDIDATE_NOT_FOUND) {
return candidate;
}
+ // Wrap the use positions such that registers blocked by the workarounds are only blocked until
+ // the end of this method.
+ RegisterPositionsWithExtraBlockedRegisters usePositionsWrapper =
+ new RegisterPositionsWithExtraBlockedRegisters(usePositions);
candidate =
handleWorkaround(
this::needsLongResultOverlappingLongOperandsWorkaround,
@@ -2000,7 +2013,7 @@
unhandledInterval,
registerConstraint,
needsRegisterPair,
- usePositions,
+ usePositionsWrapper,
type);
candidate =
handleWorkaround(
@@ -2010,7 +2023,7 @@
unhandledInterval,
registerConstraint,
needsRegisterPair,
- usePositions,
+ usePositionsWrapper,
type);
candidate =
handleWorkaround(
@@ -2020,7 +2033,7 @@
unhandledInterval,
registerConstraint,
needsRegisterPair,
- usePositions,
+ usePositionsWrapper,
type);
return candidate;
}
@@ -2033,8 +2046,8 @@
}
// Initialize all candidate registers to Integer.MAX_VALUE.
- RegisterPositions usePositions = new RegisterPositions(registerConstraint + 1);
- RegisterPositions blockedPositions = new RegisterPositions(registerConstraint + 1);
+ RegisterPositions usePositions = new RegisterPositionsImpl(registerConstraint + 1);
+ RegisterPositions blockedPositions = new RegisterPositionsImpl(registerConstraint + 1);
// Compute next use location for all currently active registers.
for (LiveIntervals intervals : active) {
@@ -2087,12 +2100,18 @@
boolean needsRegisterPair = unhandledInterval.getType().isWide();
// First look for a candidate that can be rematerialized.
- int candidate = getLargestValidCandidate(unhandledInterval, registerConstraint,
- needsRegisterPair, usePositions, Type.CONST_NUMBER);
+ int candidate =
+ getLargestValidCandidate(
+ unhandledInterval,
+ registerConstraint,
+ needsRegisterPair,
+ usePositions,
+ Type.CONST_NUMBER);
if (candidate != Integer.MAX_VALUE) {
// Look for a non-const, non-monitor candidate.
- int otherCandidate = getLargestValidCandidate(
- unhandledInterval, registerConstraint, needsRegisterPair, usePositions, Type.OTHER);
+ int otherCandidate =
+ getLargestValidCandidate(
+ unhandledInterval, registerConstraint, needsRegisterPair, usePositions, Type.OTHER);
if (otherCandidate == Integer.MAX_VALUE || candidate == REGISTER_CANDIDATE_NOT_FOUND) {
candidate = otherCandidate;
} else {
@@ -2104,6 +2123,7 @@
candidate = otherCandidate;
}
}
+
// If looking at constants and non-monitor registers did not find a valid spill candidate
// we allow ourselves to look at monitor spill candidates as well. Registers holding objects
// used as monitors should not be spilled if we can avoid it. Spilling them can lead
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
index f58a140..caafb2e 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
@@ -3,18 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.regalloc;
-import com.android.tools.r8.errors.Unreachable;
-import java.util.Arrays;
-import java.util.BitSet;
-
/**
* Simple mapping from a register to an int value.
- * <p>
- * The backing for the mapping grows as needed up to a given limit. If no mapping exists for
- * a register number the value is assumed to be Integer.MAX_VALUE.
+ *
+ * <p>The backing for the mapping grows as needed up to a given limit. If no mapping exists for a
+ * register number the value is assumed to be Integer.MAX_VALUE.
*/
-
-public class RegisterPositions {
+public abstract class RegisterPositions {
enum Type {
MONITOR,
@@ -23,103 +18,22 @@
ANY
}
- private static final int INITIAL_SIZE = 16;
- private final int limit;
- private int[] backing;
- private final BitSet registerHoldsConstant;
- private final BitSet registerHoldsMonitor;
- private final BitSet registerHoldsNewStringInstanceDisallowingSpilling;
- private final BitSet blockedRegisters;
+ public abstract boolean hasType(int index, Type type);
- public RegisterPositions(int limit) {
- this.limit = limit;
- backing = new int[INITIAL_SIZE];
- for (int i = 0; i < INITIAL_SIZE; i++) {
- backing[i] = Integer.MAX_VALUE;
- }
- registerHoldsConstant = new BitSet(limit);
- registerHoldsMonitor = new BitSet(limit);
- registerHoldsNewStringInstanceDisallowingSpilling = new BitSet(limit);
- blockedRegisters = new BitSet(limit);
- }
+ public abstract void set(int index, int value, LiveIntervals intervals);
- public boolean hasType(int index, Type type) {
- assert !isBlocked(index);
- switch (type) {
- case MONITOR:
- return holdsMonitor(index);
- case CONST_NUMBER:
- return holdsConstant(index);
- case OTHER:
- return !holdsMonitor(index)
- && !holdsConstant(index)
- && !holdsNewStringInstanceDisallowingSpilling(index);
- case ANY:
- return true;
- default:
- throw new Unreachable("Unexpected register position type: " + type);
- }
- }
+ public abstract int get(int index);
- private boolean holdsConstant(int index) {
- return registerHoldsConstant.get(index);
- }
+ public abstract int getLimit();
- private boolean holdsMonitor(int index) { return registerHoldsMonitor.get(index); }
+ public abstract void setBlocked(int index);
- private boolean holdsNewStringInstanceDisallowingSpilling(int index) {
- return registerHoldsNewStringInstanceDisallowingSpilling.get(index);
- }
+ public abstract boolean isBlocked(int index);
- public void set(int index, int value) {
- if (index >= backing.length) {
- grow(index + 1);
- }
- backing[index] = value;
- }
-
- public void set(int index, int value, LiveIntervals intervals) {
- set(index, value);
- registerHoldsConstant.set(index, intervals.isConstantNumberInterval());
- registerHoldsMonitor.set(index, intervals.usedInMonitorOperation());
- registerHoldsNewStringInstanceDisallowingSpilling.set(
- index, intervals.isNewStringInstanceDisallowingSpilling());
- }
-
- public int get(int index) {
- assert !isBlocked(index);
- if (index < backing.length) {
- return backing[index];
- }
- assert index < limit;
- return Integer.MAX_VALUE;
- }
-
- public void setBlocked(int index) {
- blockedRegisters.set(index);
- }
-
- public boolean isBlocked(int index) {
- return blockedRegisters.get(index);
- }
-
- public boolean isBlocked(int index, boolean isWide) {
+ public final boolean isBlocked(int index, boolean isWide) {
if (isBlocked(index)) {
return true;
}
return isWide && isBlocked(index + 1);
}
-
- public void grow(int minSize) {
- int size = backing.length;
- while (size < minSize) {
- size *= 2;
- }
- size = Math.min(size, limit);
- int oldSize = backing.length;
- backing = Arrays.copyOf(backing, size);
- for (int i = oldSize; i < size; i++) {
- backing[i] = Integer.MAX_VALUE;
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java
new file mode 100644
index 0000000..0f11ebf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java
@@ -0,0 +1,117 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.regalloc;
+
+import com.android.tools.r8.errors.Unreachable;
+import java.util.Arrays;
+import java.util.BitSet;
+
+public class RegisterPositionsImpl extends RegisterPositions {
+
+ private static final int INITIAL_SIZE = 16;
+ private final int limit;
+ private int[] backing;
+ private final BitSet registerHoldsConstant;
+ private final BitSet registerHoldsMonitor;
+ private final BitSet registerHoldsNewStringInstanceDisallowingSpilling;
+ private final BitSet blockedRegisters;
+
+ public RegisterPositionsImpl(int limit) {
+ this.limit = limit;
+ backing = new int[INITIAL_SIZE];
+ for (int i = 0; i < INITIAL_SIZE; i++) {
+ backing[i] = Integer.MAX_VALUE;
+ }
+ registerHoldsConstant = new BitSet(limit);
+ registerHoldsMonitor = new BitSet(limit);
+ registerHoldsNewStringInstanceDisallowingSpilling = new BitSet(limit);
+ blockedRegisters = new BitSet(limit);
+ }
+
+ @Override
+ public boolean hasType(int index, Type type) {
+ assert !isBlocked(index);
+ switch (type) {
+ case MONITOR:
+ return holdsMonitor(index);
+ case CONST_NUMBER:
+ return holdsConstant(index);
+ case OTHER:
+ return !holdsMonitor(index)
+ && !holdsConstant(index)
+ && !holdsNewStringInstanceDisallowingSpilling(index);
+ case ANY:
+ return true;
+ default:
+ throw new Unreachable("Unexpected register position type: " + type);
+ }
+ }
+
+ private boolean holdsConstant(int index) {
+ return registerHoldsConstant.get(index);
+ }
+
+ private boolean holdsMonitor(int index) {
+ return registerHoldsMonitor.get(index);
+ }
+
+ private boolean holdsNewStringInstanceDisallowingSpilling(int index) {
+ return registerHoldsNewStringInstanceDisallowingSpilling.get(index);
+ }
+
+ private void set(int index, int value) {
+ if (index >= backing.length) {
+ grow(index + 1);
+ }
+ backing[index] = value;
+ }
+
+ @Override
+ public void set(int index, int value, LiveIntervals intervals) {
+ set(index, value);
+ registerHoldsConstant.set(index, intervals.isConstantNumberInterval());
+ registerHoldsMonitor.set(index, intervals.usedInMonitorOperation());
+ registerHoldsNewStringInstanceDisallowingSpilling.set(
+ index, intervals.isNewStringInstanceDisallowingSpilling());
+ }
+
+ @Override
+ public int get(int index) {
+ assert !isBlocked(index);
+ if (index < backing.length) {
+ return backing[index];
+ }
+ assert index < limit;
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getLimit() {
+ return limit;
+ }
+
+ @Override
+ public void setBlocked(int index) {
+ blockedRegisters.set(index);
+ }
+
+ @Override
+ public boolean isBlocked(int index) {
+ return blockedRegisters.get(index);
+ }
+
+ private void grow(int minSize) {
+ int size = backing.length;
+ while (size < minSize) {
+ size *= 2;
+ }
+ size = Math.min(size, limit);
+ int oldSize = backing.length;
+ backing = Arrays.copyOf(backing, size);
+ for (int i = oldSize; i < size; i++) {
+ backing[i] = Integer.MAX_VALUE;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java
new file mode 100644
index 0000000..16c7bb4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.regalloc;
+
+import java.util.BitSet;
+
+public class RegisterPositionsWithExtraBlockedRegisters extends RegisterPositions {
+
+ private final RegisterPositions positions;
+ private final BitSet extraBlockedRegisters;
+
+ public RegisterPositionsWithExtraBlockedRegisters(RegisterPositions positions) {
+ this.positions = positions;
+ this.extraBlockedRegisters = new BitSet(positions.getLimit());
+ }
+
+ @Override
+ public boolean hasType(int index, Type type) {
+ assert !isBlockedTemporarily(index);
+ return positions.hasType(index, type);
+ }
+
+ @Override
+ public void set(int index, int value, LiveIntervals intervals) {
+ positions.set(index, value, intervals);
+ }
+
+ @Override
+ public int get(int index) {
+ assert !isBlockedTemporarily(index);
+ return positions.get(index);
+ }
+
+ @Override
+ public int getLimit() {
+ return positions.getLimit();
+ }
+
+ @Override
+ public void setBlocked(int index) {
+ positions.setBlocked(index);
+ }
+
+ public void setBlockedTemporarily(int index) {
+ extraBlockedRegisters.set(index);
+ }
+
+ @Override
+ public boolean isBlocked(int index) {
+ return positions.isBlocked(index) || isBlockedTemporarily(index);
+ }
+
+ public boolean isBlockedTemporarily(int index) {
+ return extraBlockedRegisters.get(index);
+ }
+}