Fix target block index offset in switch eliminator

Bug: 181320553
Change-Id: I8d8347006e618bb9b72f2580bc2d3b8819fe96af
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
index 733db77..6c9bfbb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
@@ -83,20 +83,20 @@
   boolean optimize() {
     if (canBeOptimized()) {
       int originalNumberOfSuccessors = block.getSuccessors().size();
-      unlinkDeadSuccessors();
+      IntList removedSuccessorIndices = unlinkDeadSuccessors();
       if (hasAlwaysHitCase() || allSwitchCasesMarkedForRemoval()) {
         // Replace switch with a simple goto.
         replaceSwitchByGoto();
       } else {
         // Replace switch by a new switch where the dead switch cases have been removed.
-        replaceSwitchByOptimizedSwitch(originalNumberOfSuccessors);
+        replaceSwitchByOptimizedSwitch(originalNumberOfSuccessors, removedSuccessorIndices);
       }
       return true;
     }
     return false;
   }
 
-  private void unlinkDeadSuccessors() {
+  private IntList unlinkDeadSuccessors() {
     IntPredicate successorHasBecomeDeadPredicate = computeSuccessorHasBecomeDeadPredicate();
     IntList successorIndicesToBeRemoved = new IntArrayList();
     for (int i = 0; i < block.getSuccessors().size(); i++) {
@@ -111,6 +111,7 @@
     }
     successorIndicesToBeRemoved.sort(Comparator.naturalOrder());
     block.removeSuccessorsByIndex(successorIndicesToBeRemoved);
+    return successorIndicesToBeRemoved;
   }
 
   private IntPredicate computeSuccessorHasBecomeDeadPredicate() {
@@ -136,16 +137,12 @@
     iterator.replaceCurrentInstruction(new Goto(target));
   }
 
-  private void replaceSwitchByOptimizedSwitch(int originalNumberOfSuccessors) {
+  private void replaceSwitchByOptimizedSwitch(
+      int originalNumberOfSuccessors, IntList removedSuccessorIndices) {
     int[] targetBlockIndexOffset = new int[originalNumberOfSuccessors];
-    for (int i : switchCasesToBeRemoved) {
-      int targetBlockIndex = theSwitch.getTargetBlockIndex(i);
-      // Add 1 because we are interested in the number of targets removed before a given index.
-      if (targetBlockIndex + 1 < targetBlockIndexOffset.length) {
-        targetBlockIndexOffset[targetBlockIndex + 1] = 1;
-      }
+    for (int removedSuccessorIndex : removedSuccessorIndices) {
+      targetBlockIndexOffset[removedSuccessorIndex] = 1;
     }
-
     for (int i = 1; i < targetBlockIndexOffset.length; i++) {
       targetBlockIndexOffset[i] += targetBlockIndexOffset[i - 1];
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java
new file mode 100644
index 0000000..6fd4739
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java
@@ -0,0 +1,82 @@
+// 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.optimize.switches;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DeadSwitchCaseWithSharedTargetTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public DeadSwitchCaseWithSharedTargetTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepRules(
+            "-assumevalues class " + Main.class.getTypeName() + " {",
+            "  static int FIELD return 27..30;",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("?", "?", "O", "P", "Q", "R", "?");
+  }
+
+  static class Main {
+
+    static int FIELD;
+    static boolean alwaysTrue = System.currentTimeMillis() >= 0;
+
+    public static void main(String[] args) {
+      test(25);
+      test(26);
+      test(27);
+      test(28);
+      test(29);
+      test(30);
+      test(31);
+    }
+
+    static void test(int i) {
+      if (alwaysTrue) {
+        FIELD = i;
+      }
+      switch (FIELD) {
+        case 26:
+        case 27:
+          System.out.println("O");
+          break;
+        case 28:
+          System.out.println("P");
+          break;
+        case 29:
+          System.out.println("Q");
+          break;
+        case 30:
+          System.out.println("R");
+          break;
+        default:
+          System.out.println("?");
+          break;
+      }
+    }
+  }
+}