Fix shift rewriting for arithemetic right shift

Arithemitic right shift with more more than the bits in the value
does not always yield 0 but 0 or -1 depending on the upper bit
in the value.

Also add a more exhaustive test of successive shift operations.

Bug: b/342067836
Change-Id: I368a0c5de057503aa4e6b65e984a9c73e13ae62b
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/BinopRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/BinopRewriter.java
index ec2d309..9929d22 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/BinopRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/BinopRewriter.java
@@ -365,12 +365,15 @@
       ConstNumber constARight,
       Value input,
       IRCode code) {
+    assert binop.isShl() || binop.isShr() || binop.isUshr();
     int mask = input.outType().isWide() ? 63 : 31;
     int intA = constARight.getIntValue() & mask;
     int intB = constBRight.getIntValue() & mask;
     if (intA + intB > mask) {
-      ConstNumber zero = code.createNumberConstant(0, binop.outValue().getType());
-      iterator.replaceCurrentInstruction(zero);
+      if (!binop.isShr()) {
+        ConstNumber zero = code.createNumberConstant(0, binop.outValue().getType());
+        iterator.replaceCurrentInstruction(zero);
+      }
     } else {
       iterator.previous();
       Value newConstantValue =
diff --git a/src/test/java/com/android/tools/r8/ir/ShiftExhaustiveTest.java b/src/test/java/com/android/tools/r8/ir/ShiftExhaustiveTest.java
new file mode 100644
index 0000000..13ef103
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/ShiftExhaustiveTest.java
@@ -0,0 +1,610 @@
+// Copyright (c) 2024, 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;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ShiftExhaustiveTest extends TestBase {
+
+  private static final List<String> shiptOperations = ImmutableList.of(">>", ">>>", "<<");
+  private static final List<Integer> negativeShiftValuesForInt =
+      ImmutableList.of(0, -1, -2, -10, -20, -30, -31, -32);
+  private static final List<Integer> positiveShiftValuesForInt =
+      ImmutableList.of(0, 1, 2, 10, 20, 30, 31, 32);
+  private static final List<Integer> negativeShiftValuesForLong =
+      ImmutableList.of(0, -1, -2, -20, -40, -62, -63, -64);
+  private static final List<Integer> positiveShiftValuesForLong =
+      ImmutableList.of(0, 1, 2, 20, 40, 62, 63, 64);
+  private static final List<Integer> testValuesInt =
+      ImmutableList.of(
+          Integer.MIN_VALUE,
+          Integer.MIN_VALUE + 1,
+          -2,
+          -1,
+          0,
+          1,
+          2,
+          Integer.MAX_VALUE - 1,
+          Integer.MAX_VALUE);
+  private static final List<Long> testValuesLong =
+      ImmutableList.of(
+          Long.MIN_VALUE,
+          Long.MIN_VALUE + 1L,
+          -2L,
+          -1L,
+          0L,
+          1L,
+          2L,
+          Long.MAX_VALUE - 1,
+          Long.MAX_VALUE);
+
+  private static List<String> EXPECTED_RESULT;
+
+  @BeforeClass
+  public static void generateExpectedResult() {
+    List<String> result = new ArrayList<>();
+    for (int i : testValuesInt) {
+      generateTestResultsInt(i, result);
+    }
+    for (long l : testValuesLong) {
+      generateTestResultsLong(l, result);
+    }
+    EXPECTED_RESULT = result;
+  }
+
+  public static void generateTestResultsInt(int x, List<String> result) {
+    for (String op : shiptOperations) {
+      for (int f : negativeShiftValuesForInt) {
+        for (int s : positiveShiftValuesForInt) {
+          if (op.equals(">>")) {
+            result.add("" + (x >> f >> s));
+          }
+          if (op.equals(">>>")) {
+            result.add("" + (x >>> f >>> s));
+          }
+          if (op.equals("<<")) {
+            result.add("" + (x << f << s));
+          }
+        }
+      }
+    }
+  }
+
+  public static void generateTestResultsLong(long x, List<String> result) {
+    for (String op : shiptOperations) {
+      for (int f : negativeShiftValuesForLong) {
+        for (int s : positiveShiftValuesForLong) {
+          switch (op) {
+            case ">>":
+              result.add("" + (x >> f >> s));
+              break;
+            case ">>>":
+              result.add("" + (x >>> f >>> s));
+              break;
+            case "<<":
+              result.add("" + (x << f << s));
+              break;
+          }
+        }
+      }
+    }
+  }
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  private final TestParameters parameters;
+
+  public ShiftExhaustiveTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm(parameters)
+        .addProgramClasses(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addKeepMainRule(Main.class)
+        .enableInliningAnnotations()
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED_RESULT);
+  }
+
+  // Methods of Main class generated by outer class main method below.
+  public static class Main {
+
+    public static void main(String[] args) {
+      testInt(-2147483648);
+      testInt(-2147483647);
+      testInt(-2);
+      testInt(-1);
+      testInt(0);
+      testInt(1);
+      testInt(2);
+      testInt(2147483646);
+      testInt(2147483647);
+      testLong(-9223372036854775808L);
+      testLong(-9223372036854775807L);
+      testLong(-2L);
+      testLong(-1L);
+      testLong(0L);
+      testLong(1L);
+      testLong(2L);
+      testLong(9223372036854775806L);
+      testLong(9223372036854775807L);
+    }
+
+    @NeverInline
+    private static void testInt(int x) {
+      System.out.println(x >> 0 >> 0);
+      System.out.println(x >> 0 >> 1);
+      System.out.println(x >> 0 >> 2);
+      System.out.println(x >> 0 >> 10);
+      System.out.println(x >> 0 >> 20);
+      System.out.println(x >> 0 >> 30);
+      System.out.println(x >> 0 >> 31);
+      System.out.println(x >> 0 >> 32);
+      System.out.println(x >> -1 >> 0);
+      System.out.println(x >> -1 >> 1);
+      System.out.println(x >> -1 >> 2);
+      System.out.println(x >> -1 >> 10);
+      System.out.println(x >> -1 >> 20);
+      System.out.println(x >> -1 >> 30);
+      System.out.println(x >> -1 >> 31);
+      System.out.println(x >> -1 >> 32);
+      System.out.println(x >> -2 >> 0);
+      System.out.println(x >> -2 >> 1);
+      System.out.println(x >> -2 >> 2);
+      System.out.println(x >> -2 >> 10);
+      System.out.println(x >> -2 >> 20);
+      System.out.println(x >> -2 >> 30);
+      System.out.println(x >> -2 >> 31);
+      System.out.println(x >> -2 >> 32);
+      System.out.println(x >> -10 >> 0);
+      System.out.println(x >> -10 >> 1);
+      System.out.println(x >> -10 >> 2);
+      System.out.println(x >> -10 >> 10);
+      System.out.println(x >> -10 >> 20);
+      System.out.println(x >> -10 >> 30);
+      System.out.println(x >> -10 >> 31);
+      System.out.println(x >> -10 >> 32);
+      System.out.println(x >> -20 >> 0);
+      System.out.println(x >> -20 >> 1);
+      System.out.println(x >> -20 >> 2);
+      System.out.println(x >> -20 >> 10);
+      System.out.println(x >> -20 >> 20);
+      System.out.println(x >> -20 >> 30);
+      System.out.println(x >> -20 >> 31);
+      System.out.println(x >> -20 >> 32);
+      System.out.println(x >> -30 >> 0);
+      System.out.println(x >> -30 >> 1);
+      System.out.println(x >> -30 >> 2);
+      System.out.println(x >> -30 >> 10);
+      System.out.println(x >> -30 >> 20);
+      System.out.println(x >> -30 >> 30);
+      System.out.println(x >> -30 >> 31);
+      System.out.println(x >> -30 >> 32);
+      System.out.println(x >> -31 >> 0);
+      System.out.println(x >> -31 >> 1);
+      System.out.println(x >> -31 >> 2);
+      System.out.println(x >> -31 >> 10);
+      System.out.println(x >> -31 >> 20);
+      System.out.println(x >> -31 >> 30);
+      System.out.println(x >> -31 >> 31);
+      System.out.println(x >> -31 >> 32);
+      System.out.println(x >> -32 >> 0);
+      System.out.println(x >> -32 >> 1);
+      System.out.println(x >> -32 >> 2);
+      System.out.println(x >> -32 >> 10);
+      System.out.println(x >> -32 >> 20);
+      System.out.println(x >> -32 >> 30);
+      System.out.println(x >> -32 >> 31);
+      System.out.println(x >> -32 >> 32);
+      System.out.println(x >>> 0 >>> 0);
+      System.out.println(x >>> 0 >>> 1);
+      System.out.println(x >>> 0 >>> 2);
+      System.out.println(x >>> 0 >>> 10);
+      System.out.println(x >>> 0 >>> 20);
+      System.out.println(x >>> 0 >>> 30);
+      System.out.println(x >>> 0 >>> 31);
+      System.out.println(x >>> 0 >>> 32);
+      System.out.println(x >>> -1 >>> 0);
+      System.out.println(x >>> -1 >>> 1);
+      System.out.println(x >>> -1 >>> 2);
+      System.out.println(x >>> -1 >>> 10);
+      System.out.println(x >>> -1 >>> 20);
+      System.out.println(x >>> -1 >>> 30);
+      System.out.println(x >>> -1 >>> 31);
+      System.out.println(x >>> -1 >>> 32);
+      System.out.println(x >>> -2 >>> 0);
+      System.out.println(x >>> -2 >>> 1);
+      System.out.println(x >>> -2 >>> 2);
+      System.out.println(x >>> -2 >>> 10);
+      System.out.println(x >>> -2 >>> 20);
+      System.out.println(x >>> -2 >>> 30);
+      System.out.println(x >>> -2 >>> 31);
+      System.out.println(x >>> -2 >>> 32);
+      System.out.println(x >>> -10 >>> 0);
+      System.out.println(x >>> -10 >>> 1);
+      System.out.println(x >>> -10 >>> 2);
+      System.out.println(x >>> -10 >>> 10);
+      System.out.println(x >>> -10 >>> 20);
+      System.out.println(x >>> -10 >>> 30);
+      System.out.println(x >>> -10 >>> 31);
+      System.out.println(x >>> -10 >>> 32);
+      System.out.println(x >>> -20 >>> 0);
+      System.out.println(x >>> -20 >>> 1);
+      System.out.println(x >>> -20 >>> 2);
+      System.out.println(x >>> -20 >>> 10);
+      System.out.println(x >>> -20 >>> 20);
+      System.out.println(x >>> -20 >>> 30);
+      System.out.println(x >>> -20 >>> 31);
+      System.out.println(x >>> -20 >>> 32);
+      System.out.println(x >>> -30 >>> 0);
+      System.out.println(x >>> -30 >>> 1);
+      System.out.println(x >>> -30 >>> 2);
+      System.out.println(x >>> -30 >>> 10);
+      System.out.println(x >>> -30 >>> 20);
+      System.out.println(x >>> -30 >>> 30);
+      System.out.println(x >>> -30 >>> 31);
+      System.out.println(x >>> -30 >>> 32);
+      System.out.println(x >>> -31 >>> 0);
+      System.out.println(x >>> -31 >>> 1);
+      System.out.println(x >>> -31 >>> 2);
+      System.out.println(x >>> -31 >>> 10);
+      System.out.println(x >>> -31 >>> 20);
+      System.out.println(x >>> -31 >>> 30);
+      System.out.println(x >>> -31 >>> 31);
+      System.out.println(x >>> -31 >>> 32);
+      System.out.println(x >>> -32 >>> 0);
+      System.out.println(x >>> -32 >>> 1);
+      System.out.println(x >>> -32 >>> 2);
+      System.out.println(x >>> -32 >>> 10);
+      System.out.println(x >>> -32 >>> 20);
+      System.out.println(x >>> -32 >>> 30);
+      System.out.println(x >>> -32 >>> 31);
+      System.out.println(x >>> -32 >>> 32);
+      System.out.println(x << 0 << 0);
+      System.out.println(x << 0 << 1);
+      System.out.println(x << 0 << 2);
+      System.out.println(x << 0 << 10);
+      System.out.println(x << 0 << 20);
+      System.out.println(x << 0 << 30);
+      System.out.println(x << 0 << 31);
+      System.out.println(x << 0 << 32);
+      System.out.println(x << -1 << 0);
+      System.out.println(x << -1 << 1);
+      System.out.println(x << -1 << 2);
+      System.out.println(x << -1 << 10);
+      System.out.println(x << -1 << 20);
+      System.out.println(x << -1 << 30);
+      System.out.println(x << -1 << 31);
+      System.out.println(x << -1 << 32);
+      System.out.println(x << -2 << 0);
+      System.out.println(x << -2 << 1);
+      System.out.println(x << -2 << 2);
+      System.out.println(x << -2 << 10);
+      System.out.println(x << -2 << 20);
+      System.out.println(x << -2 << 30);
+      System.out.println(x << -2 << 31);
+      System.out.println(x << -2 << 32);
+      System.out.println(x << -10 << 0);
+      System.out.println(x << -10 << 1);
+      System.out.println(x << -10 << 2);
+      System.out.println(x << -10 << 10);
+      System.out.println(x << -10 << 20);
+      System.out.println(x << -10 << 30);
+      System.out.println(x << -10 << 31);
+      System.out.println(x << -10 << 32);
+      System.out.println(x << -20 << 0);
+      System.out.println(x << -20 << 1);
+      System.out.println(x << -20 << 2);
+      System.out.println(x << -20 << 10);
+      System.out.println(x << -20 << 20);
+      System.out.println(x << -20 << 30);
+      System.out.println(x << -20 << 31);
+      System.out.println(x << -20 << 32);
+      System.out.println(x << -30 << 0);
+      System.out.println(x << -30 << 1);
+      System.out.println(x << -30 << 2);
+      System.out.println(x << -30 << 10);
+      System.out.println(x << -30 << 20);
+      System.out.println(x << -30 << 30);
+      System.out.println(x << -30 << 31);
+      System.out.println(x << -30 << 32);
+      System.out.println(x << -31 << 0);
+      System.out.println(x << -31 << 1);
+      System.out.println(x << -31 << 2);
+      System.out.println(x << -31 << 10);
+      System.out.println(x << -31 << 20);
+      System.out.println(x << -31 << 30);
+      System.out.println(x << -31 << 31);
+      System.out.println(x << -31 << 32);
+      System.out.println(x << -32 << 0);
+      System.out.println(x << -32 << 1);
+      System.out.println(x << -32 << 2);
+      System.out.println(x << -32 << 10);
+      System.out.println(x << -32 << 20);
+      System.out.println(x << -32 << 30);
+      System.out.println(x << -32 << 31);
+      System.out.println(x << -32 << 32);
+    }
+
+    @NeverInline
+    private static void testLong(long x) {
+      System.out.println(x >> 0 >> 0);
+      System.out.println(x >> 0 >> 1);
+      System.out.println(x >> 0 >> 2);
+      System.out.println(x >> 0 >> 20);
+      System.out.println(x >> 0 >> 40);
+      System.out.println(x >> 0 >> 62);
+      System.out.println(x >> 0 >> 63);
+      System.out.println(x >> 0 >> 64);
+      System.out.println(x >> -1 >> 0);
+      System.out.println(x >> -1 >> 1);
+      System.out.println(x >> -1 >> 2);
+      System.out.println(x >> -1 >> 20);
+      System.out.println(x >> -1 >> 40);
+      System.out.println(x >> -1 >> 62);
+      System.out.println(x >> -1 >> 63);
+      System.out.println(x >> -1 >> 64);
+      System.out.println(x >> -2 >> 0);
+      System.out.println(x >> -2 >> 1);
+      System.out.println(x >> -2 >> 2);
+      System.out.println(x >> -2 >> 20);
+      System.out.println(x >> -2 >> 40);
+      System.out.println(x >> -2 >> 62);
+      System.out.println(x >> -2 >> 63);
+      System.out.println(x >> -2 >> 64);
+      System.out.println(x >> -20 >> 0);
+      System.out.println(x >> -20 >> 1);
+      System.out.println(x >> -20 >> 2);
+      System.out.println(x >> -20 >> 20);
+      System.out.println(x >> -20 >> 40);
+      System.out.println(x >> -20 >> 62);
+      System.out.println(x >> -20 >> 63);
+      System.out.println(x >> -20 >> 64);
+      System.out.println(x >> -40 >> 0);
+      System.out.println(x >> -40 >> 1);
+      System.out.println(x >> -40 >> 2);
+      System.out.println(x >> -40 >> 20);
+      System.out.println(x >> -40 >> 40);
+      System.out.println(x >> -40 >> 62);
+      System.out.println(x >> -40 >> 63);
+      System.out.println(x >> -40 >> 64);
+      System.out.println(x >> -62 >> 0);
+      System.out.println(x >> -62 >> 1);
+      System.out.println(x >> -62 >> 2);
+      System.out.println(x >> -62 >> 20);
+      System.out.println(x >> -62 >> 40);
+      System.out.println(x >> -62 >> 62);
+      System.out.println(x >> -62 >> 63);
+      System.out.println(x >> -62 >> 64);
+      System.out.println(x >> -63 >> 0);
+      System.out.println(x >> -63 >> 1);
+      System.out.println(x >> -63 >> 2);
+      System.out.println(x >> -63 >> 20);
+      System.out.println(x >> -63 >> 40);
+      System.out.println(x >> -63 >> 62);
+      System.out.println(x >> -63 >> 63);
+      System.out.println(x >> -63 >> 64);
+      System.out.println(x >> -64 >> 0);
+      System.out.println(x >> -64 >> 1);
+      System.out.println(x >> -64 >> 2);
+      System.out.println(x >> -64 >> 20);
+      System.out.println(x >> -64 >> 40);
+      System.out.println(x >> -64 >> 62);
+      System.out.println(x >> -64 >> 63);
+      System.out.println(x >> -64 >> 64);
+      System.out.println(x >>> 0 >>> 0);
+      System.out.println(x >>> 0 >>> 1);
+      System.out.println(x >>> 0 >>> 2);
+      System.out.println(x >>> 0 >>> 20);
+      System.out.println(x >>> 0 >>> 40);
+      System.out.println(x >>> 0 >>> 62);
+      System.out.println(x >>> 0 >>> 63);
+      System.out.println(x >>> 0 >>> 64);
+      System.out.println(x >>> -1 >>> 0);
+      System.out.println(x >>> -1 >>> 1);
+      System.out.println(x >>> -1 >>> 2);
+      System.out.println(x >>> -1 >>> 20);
+      System.out.println(x >>> -1 >>> 40);
+      System.out.println(x >>> -1 >>> 62);
+      System.out.println(x >>> -1 >>> 63);
+      System.out.println(x >>> -1 >>> 64);
+      System.out.println(x >>> -2 >>> 0);
+      System.out.println(x >>> -2 >>> 1);
+      System.out.println(x >>> -2 >>> 2);
+      System.out.println(x >>> -2 >>> 20);
+      System.out.println(x >>> -2 >>> 40);
+      System.out.println(x >>> -2 >>> 62);
+      System.out.println(x >>> -2 >>> 63);
+      System.out.println(x >>> -2 >>> 64);
+      System.out.println(x >>> -20 >>> 0);
+      System.out.println(x >>> -20 >>> 1);
+      System.out.println(x >>> -20 >>> 2);
+      System.out.println(x >>> -20 >>> 20);
+      System.out.println(x >>> -20 >>> 40);
+      System.out.println(x >>> -20 >>> 62);
+      System.out.println(x >>> -20 >>> 63);
+      System.out.println(x >>> -20 >>> 64);
+      System.out.println(x >>> -40 >>> 0);
+      System.out.println(x >>> -40 >>> 1);
+      System.out.println(x >>> -40 >>> 2);
+      System.out.println(x >>> -40 >>> 20);
+      System.out.println(x >>> -40 >>> 40);
+      System.out.println(x >>> -40 >>> 62);
+      System.out.println(x >>> -40 >>> 63);
+      System.out.println(x >>> -40 >>> 64);
+      System.out.println(x >>> -62 >>> 0);
+      System.out.println(x >>> -62 >>> 1);
+      System.out.println(x >>> -62 >>> 2);
+      System.out.println(x >>> -62 >>> 20);
+      System.out.println(x >>> -62 >>> 40);
+      System.out.println(x >>> -62 >>> 62);
+      System.out.println(x >>> -62 >>> 63);
+      System.out.println(x >>> -62 >>> 64);
+      System.out.println(x >>> -63 >>> 0);
+      System.out.println(x >>> -63 >>> 1);
+      System.out.println(x >>> -63 >>> 2);
+      System.out.println(x >>> -63 >>> 20);
+      System.out.println(x >>> -63 >>> 40);
+      System.out.println(x >>> -63 >>> 62);
+      System.out.println(x >>> -63 >>> 63);
+      System.out.println(x >>> -63 >>> 64);
+      System.out.println(x >>> -64 >>> 0);
+      System.out.println(x >>> -64 >>> 1);
+      System.out.println(x >>> -64 >>> 2);
+      System.out.println(x >>> -64 >>> 20);
+      System.out.println(x >>> -64 >>> 40);
+      System.out.println(x >>> -64 >>> 62);
+      System.out.println(x >>> -64 >>> 63);
+      System.out.println(x >>> -64 >>> 64);
+      System.out.println(x << 0 << 0);
+      System.out.println(x << 0 << 1);
+      System.out.println(x << 0 << 2);
+      System.out.println(x << 0 << 20);
+      System.out.println(x << 0 << 40);
+      System.out.println(x << 0 << 62);
+      System.out.println(x << 0 << 63);
+      System.out.println(x << 0 << 64);
+      System.out.println(x << -1 << 0);
+      System.out.println(x << -1 << 1);
+      System.out.println(x << -1 << 2);
+      System.out.println(x << -1 << 20);
+      System.out.println(x << -1 << 40);
+      System.out.println(x << -1 << 62);
+      System.out.println(x << -1 << 63);
+      System.out.println(x << -1 << 64);
+      System.out.println(x << -2 << 0);
+      System.out.println(x << -2 << 1);
+      System.out.println(x << -2 << 2);
+      System.out.println(x << -2 << 20);
+      System.out.println(x << -2 << 40);
+      System.out.println(x << -2 << 62);
+      System.out.println(x << -2 << 63);
+      System.out.println(x << -2 << 64);
+      System.out.println(x << -20 << 0);
+      System.out.println(x << -20 << 1);
+      System.out.println(x << -20 << 2);
+      System.out.println(x << -20 << 20);
+      System.out.println(x << -20 << 40);
+      System.out.println(x << -20 << 62);
+      System.out.println(x << -20 << 63);
+      System.out.println(x << -20 << 64);
+      System.out.println(x << -40 << 0);
+      System.out.println(x << -40 << 1);
+      System.out.println(x << -40 << 2);
+      System.out.println(x << -40 << 20);
+      System.out.println(x << -40 << 40);
+      System.out.println(x << -40 << 62);
+      System.out.println(x << -40 << 63);
+      System.out.println(x << -40 << 64);
+      System.out.println(x << -62 << 0);
+      System.out.println(x << -62 << 1);
+      System.out.println(x << -62 << 2);
+      System.out.println(x << -62 << 20);
+      System.out.println(x << -62 << 40);
+      System.out.println(x << -62 << 62);
+      System.out.println(x << -62 << 63);
+      System.out.println(x << -62 << 64);
+      System.out.println(x << -63 << 0);
+      System.out.println(x << -63 << 1);
+      System.out.println(x << -63 << 2);
+      System.out.println(x << -63 << 20);
+      System.out.println(x << -63 << 40);
+      System.out.println(x << -63 << 62);
+      System.out.println(x << -63 << 63);
+      System.out.println(x << -63 << 64);
+      System.out.println(x << -64 << 0);
+      System.out.println(x << -64 << 1);
+      System.out.println(x << -64 << 2);
+      System.out.println(x << -64 << 20);
+      System.out.println(x << -64 << 40);
+      System.out.println(x << -64 << 62);
+      System.out.println(x << -64 << 63);
+      System.out.println(x << -64 << 64);
+    }
+  }
+
+  private static void generateTestMain() {
+    System.out.println("    public static void main(String[] args) {");
+    for (int i : testValuesInt) {
+      System.out.println("      testInt(" + i + ");");
+    }
+    for (long l : testValuesLong) {
+      System.out.println("      testLong(" + l + "L);");
+    }
+    System.out.println("    }");
+  }
+
+  private static void generateTestSourceInt() {
+    System.out.println("    @NeverInline");
+    System.out.println("    private static void testInt(int x) {");
+    for (String op : shiptOperations) {
+      for (int f : negativeShiftValuesForInt) {
+        for (int s : positiveShiftValuesForInt) {
+          System.out.println(
+              "      System.out.println(x " + op + " " + f + " " + op + " " + s + ");");
+        }
+      }
+    }
+    System.out.println("    }");
+  }
+
+  private static void generateTestSourceLong() {
+    System.out.println("    @NeverInline");
+    System.out.println("    private static void testLong(long x) {");
+    for (String op : shiptOperations) {
+      for (int f : negativeShiftValuesForLong) {
+        for (int s : positiveShiftValuesForLong) {
+          System.out.println(
+              "      System.out.println(x " + op + " " + f + " " + op + " " + s + ");");
+        }
+      }
+    }
+    System.out.println("    }");
+  }
+
+  public static void main(String[] args) {
+    generateTestMain();
+    System.out.println();
+    generateTestSourceInt();
+    System.out.println();
+    generateTestSourceLong();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/ShiftOppositeSignTest.java b/src/test/java/com/android/tools/r8/ir/ShiftOppositeSignTest.java
index 62cd987..e54e7b5 100644
--- a/src/test/java/com/android/tools/r8/ir/ShiftOppositeSignTest.java
+++ b/src/test/java/com/android/tools/r8/ir/ShiftOppositeSignTest.java
@@ -18,6 +18,13 @@
 
   private static final String EXPECTED_RESULT =
       StringUtils.lines(
+          "=== 2147483647 ===",
+          "shl: 0 -134217728 0 -512",
+          "shr: 0 15 0 4194303",
+          "ushr: 0 15 0 4194303",
+          "shl: 0 -64 -268435456 0",
+          "shr: 0 33554431 7 0",
+          "ushr: 0 33554431 7 0",
           "=== 1 ===",
           "shl: 0 134217728 0 512",
           "shr: 0 0 0 0",
@@ -31,7 +38,21 @@
           "ushr: 0 0 0 241",
           "shl: 0 7901184 0 0",
           "shr: 0 1929 0 0",
-          "ushr: 0 1929 0 0");
+          "ushr: 0 1929 0 0",
+          "=== -1 ===",
+          "shl: 0 -134217728 0 -512",
+          "shr: -1 -1 -1 -1",
+          "ushr: 0 31 0 8388607",
+          "shl: 0 -64 -268435456 0",
+          "shr: -1 -1 -1 -1",
+          "ushr: 0 67108863 15 0",
+          "=== -2147483648 ===",
+          "shl: 0 0 0 0",
+          "shr: -1 -16 -1 -4194304",
+          "ushr: 0 16 0 4194304",
+          "shl: 0 0 0 0",
+          "shr: -1 -33554432 -8 -1",
+          "ushr: 0 33554432 8 0");
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -66,8 +87,11 @@
   public static class Main {
 
     public static void main(String[] args) {
+      test(Integer.MAX_VALUE);
       test(1);
       test(123456);
+      test(-1);
+      test(Integer.MIN_VALUE);
     }
 
     @NeverInline