Version 1.3.41.
Merge: Fix live range computations for values used across exceptional edges.
CL: https://r8-review.googlesource.com/30889
Bug: 119374410
Change-Id: I3436ccaac6da9c967008e26d3cdc6bdffd2af383
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 0b0fc19..3ea008a 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.3.40";
+ public static final String LABEL = "1.3.41";
private Version() {
}
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 b4995c9..9fd568b 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
@@ -2492,11 +2492,29 @@
Set<Value> live = new HashSet<>();
List<BasicBlock> successors = block.getSuccessors();
Set<Value> phiOperands = new HashSet<>();
+ Set<Value> exceptionalPhiOperands = new HashSet<>();
+ Set<Value> liveAtThrowingInstruction = new HashSet<>();
+ Set<BasicBlock> exceptionalSuccessors = block.getCatchHandlers().getUniqueTargets();
for (BasicBlock successor : successors) {
- live.addAll(liveAtEntrySets.get(successor).liveValues);
+ // Values live at entry to a block that is an exceptional successor are only live
+ // until the throwing instruction in this block. They are live until the end of
+ // the block only if they are used in normal flow as well.
+ // TODO(b/119771771): This makes the bootstrap test fail for the CF backend with what
+ // looks like inconsistent stack maps. It is safe to not do this, but we should
+ // double check if that is what we want.
+ boolean isExceptionalSuccessor = exceptionalSuccessors.contains(successor);
+ if (isExceptionalSuccessor && options.isGeneratingDex()) {
+ liveAtThrowingInstruction.addAll(liveAtEntrySets.get(successor).liveValues);
+ } else {
+ live.addAll(liveAtEntrySets.get(successor).liveValues);
+ }
for (Phi phi : successor.getPhis()) {
live.remove(phi);
- phiOperands.add(phi.getOperand(successor.getPredecessors().indexOf(block)));
+ if (isExceptionalSuccessor && options.isGeneratingDex()) {
+ exceptionalPhiOperands.add(phi.getOperand(successor.getPhis().indexOf(block)));
+ } else {
+ phiOperands.add(phi.getOperand(successor.getPredecessors().indexOf(block)));
+ }
}
}
live.addAll(phiOperands);
@@ -2561,6 +2579,37 @@
}
}
}
+ // Deal with values that are live on the exceptional edge only. Care must be taken
+ // to correctly deal with check-cast instructions. Check-cast can throw an exception
+ // so values (other than the in value in the check cast) live on the exceptional edge
+ // need to have their live range extended across the check-cast. This is because a
+ // 'r1 <- check-cast r0' maps to 'move r1, r0; check-cast r1' and when that
+ // happens r1 could be clobbered on the exceptional edge if r1 initially contained
+ // a value that is used in the exceptional code.
+ if (instruction.instructionTypeCanThrow()) {
+ for (Value use : liveAtThrowingInstruction) {
+ if (use.needsRegister() && !live.contains(use)) {
+ live.add(use);
+ addLiveRange(
+ use,
+ block,
+ getLiveRangeEndOnExceptionalFlow(instruction, use),
+ liveIntervals,
+ options);
+ }
+ }
+ for (Value operand : exceptionalPhiOperands) {
+ if (!live.contains(operand)) {
+ live.add(operand);
+ addLiveRange(
+ operand,
+ block,
+ getLiveRangeEndOnExceptionalFlow(instruction, operand),
+ liveIntervals,
+ options);
+ }
+ }
+ }
if (options.debug) {
int number = instruction.getNumber();
for (Value use : instruction.getDebugValues()) {
@@ -2575,6 +2624,14 @@
}
}
+ private static int getLiveRangeEndOnExceptionalFlow(Instruction instruction, Value value) {
+ int end = instruction.getNumber();
+ if (instruction.isCheckCast() && value != instruction.asCheckCast().object()) {
+ end += INSTRUCTION_NUMBER_DELTA;
+ }
+ return end;
+ }
+
private static boolean unconstrainedForCf(int constraint, InternalOptions options) {
return !options.isGeneratingClassFiles() || constraint == Constants.U16BIT_MAX;
}