Version 0.1.21.
R=sgjesse@google.com
Merge: Fix bug in inactive linked interval splitting.
CL: https://r8-review.googlesource.com/c/r8/+/9680
Change-Id: I2bf1f016bfa6e2cb302b541c5e62cdb3c1798e8c
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index d9c37c0..70ad1f6 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -55,7 +55,7 @@
*/
public final class D8 {
- private static final String VERSION = "v0.1.20";
+ private static final String VERSION = "v0.1.21";
private static final int STATUS_ERROR = 1;
private D8() {}
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 77917af..7c34d93 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -28,7 +28,7 @@
import java.util.stream.Collectors;
public class GenerateMainDexList {
- private static final String VERSION = "v0.1.20";
+ private static final String VERSION = "v0.1.21";
private final Timing timing = new Timing("maindex");
private final InternalOptions options;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3378afa..1a6e1b0 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,7 +71,7 @@
public class R8 {
- private static final String VERSION = "v0.1.20";
+ private static final String VERSION = "v0.1.21";
private final Timing timing = new Timing("R8");
private final InternalOptions options;
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 d99e854..82b7c5e 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
@@ -137,9 +137,9 @@
// List of active intervals.
private List<LiveIntervals> active = new LinkedList<>();
// List of intervals where the current instruction falls into one of their live range holes.
- private List<LiveIntervals> inactive = new LinkedList<>();
+ protected List<LiveIntervals> inactive = new LinkedList<>();
// List of intervals that no register has been allocated to sorted by first live range.
- private PriorityQueue<LiveIntervals> unhandled =
+ protected PriorityQueue<LiveIntervals> unhandled =
new PriorityQueue<>(Comparator.comparingInt(LiveIntervals::getStart));
// The first register used for parallel moves. After register allocation the parallel move
@@ -1553,7 +1553,7 @@
splitOverlappingInactiveIntervals(unhandledInterval, needsRegisterPair, candidate);
}
- private void splitOverlappingInactiveIntervals(
+ protected void splitOverlappingInactiveIntervals(
LiveIntervals unhandledInterval,
boolean needsRegisterPair,
int candidate) {
@@ -1565,10 +1565,16 @@
(needsRegisterPair && intervals.usesRegister(candidate + 1))) &&
intervals.overlaps(unhandledInterval)) {
if (intervals.isLinked() && !intervals.isArgumentInterval()) {
+ // If the inactive register is linked but not an argument, it needs to get the
+ // same register again at the next use after the start of the unhandled interval.
+ // If there are no such uses, we can use a different register for the remainder
+ // of the inactive interval and therefore do not have to split here.
int nextUsePosition = intervals.firstUseAfter(unhandledInterval.getStart());
- LiveIntervals split = intervals.splitBefore(nextUsePosition);
- split.setRegister(intervals.getRegister());
- newInactive.add(split);
+ if (nextUsePosition != Integer.MAX_VALUE) {
+ LiveIntervals split = intervals.splitBefore(nextUsePosition);
+ split.setRegister(intervals.getRegister());
+ newInactive.add(split);
+ }
}
if (intervals.getStart() > unhandledInterval.getStart()) {
// The inactive live intervals hasn't started yet. Clear the temporary register
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
new file mode 100644
index 0000000..c3a177d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2017, 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.graph.DexApplication;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.smali.SmaliTestBase;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
+import java.util.PriorityQueue;
+import org.junit.Test;
+
+public class Regress68656641 extends SmaliTestBase {
+
+ private static class MyRegisterAllocator extends LinearScanRegisterAllocator {
+ public MyRegisterAllocator(IRCode code, InternalOptions options) {
+ super(code, options);
+ }
+
+ public void addInactiveIntervals(LiveIntervals intervals) {
+ inactive.add(intervals);
+ }
+
+ public void splitOverlappingInactiveIntervals(LiveIntervals intervals, int register) {
+ splitOverlappingInactiveIntervals(intervals, false, register);
+ }
+
+ public PriorityQueue<LiveIntervals> getUnhandled() {
+ return unhandled;
+ }
+ }
+
+ IRCode simpleCode(InternalOptions options) throws Exception {
+ SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
+ MethodSignature signature = builder.addStaticMethod(
+ "void",
+ DEFAULT_METHOD_NAME,
+ ImmutableList.of(),
+ 1,
+ " return-void");
+ DexApplication application = buildApplication(builder, options);
+ // Build the code, and split the code into three blocks.
+ ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
+ DexEncodedMethod method = getMethod(application, signature);
+ IRCode code = method.buildIR(valueNumberGenerator, new InternalOptions());
+ return code;
+ }
+
+
+ @Test
+ public void splitOverlappingInactiveIntervalWithNoNextUse() throws Exception {
+ InternalOptions options = new InternalOptions();
+ IRCode code = simpleCode(options);
+ MyRegisterAllocator allocator = new MyRegisterAllocator(code, options);
+ // Setup live an inactive live interval with ranges [0, 10[ and [20, 30[ with only
+ // uses in the first interval and which is linked to another interval.
+ LiveIntervals inactiveIntervals = new LiveIntervals(new Value(0, MoveType.SINGLE, null));
+ inactiveIntervals.addRange(new LiveRange(0, 10));
+ inactiveIntervals.addUse(new LiveIntervalsUse(0, 10));
+ inactiveIntervals.addUse(new LiveIntervalsUse(4, 10));
+ inactiveIntervals.addRange(new LiveRange(20, 30));
+ inactiveIntervals.setRegister(0);
+ LiveIntervals linked = new LiveIntervals(new Value(1, MoveType.SINGLE, null));
+ linked.setRegister(1);
+ inactiveIntervals.link(linked);
+ allocator.addInactiveIntervals(inactiveIntervals);
+ // Setup an unhandled interval that overlaps the inactive interval.
+ LiveIntervals unhandledIntervals = new LiveIntervals(new Value(2, MoveType.SINGLE, null));
+ unhandledIntervals.addRange(new LiveRange(12, 24));
+ // Split the overlapping inactive intervals and check that after the split, the second
+ // part of the inactive interval is unhandled and will therefore get a new register
+ // assigned later during allocation.
+ allocator.splitOverlappingInactiveIntervals(unhandledIntervals, 0);
+ assert allocator.getUnhandled().size() == 1;
+ assert allocator.getUnhandled().peek().getStart() == 20;
+ assert allocator.getUnhandled().peek().getEnd() == 30;
+ }
+}