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;
   }