Migrate Integer and Long backport/desugar tests

Test: tools/test.py --dex_vm all --no-internal -v *Backport*
Change-Id: I0bab4bcafbbe2b30e0d6e59cbfe865da669c96f3
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 1636a89..26fcb1c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -33,6 +33,8 @@
 import com.android.tools.r8.ir.desugar.backports.CharacterMethods;
 import com.android.tools.r8.ir.desugar.backports.DoubleMethods;
 import com.android.tools.r8.ir.desugar.backports.FloatMethods;
+import com.android.tools.r8.ir.desugar.backports.IntegerMethods;
+import com.android.tools.r8.ir.desugar.backports.LongMethods;
 import com.android.tools.r8.ir.desugar.backports.MathMethods;
 import com.android.tools.r8.ir.desugar.backports.ObjectsMethods;
 import com.android.tools.r8.ir.desugar.backports.ShortMethods;
@@ -193,154 +195,6 @@
         original.holder.descriptor, original.name, original.proto);
   }
 
-  private static final class IntegerMethods extends TemplateMethodCode {
-    IntegerMethods(InternalOptions options, DexMethod method, String methodName) {
-      super(options, method, methodName, method.proto.toDescriptorString());
-    }
-
-    public static int hashCode(int i) {
-      return Integer.valueOf(i).hashCode();
-    }
-
-    public static int compare(int a, int b) {
-      return Integer.valueOf(a).compareTo(Integer.valueOf(b));
-    }
-
-    public static int max(int a, int b) {
-      return java.lang.Math.max(a, b);
-    }
-
-    public static int min(int a, int b) {
-      return java.lang.Math.min(a, b);
-    }
-
-    public static int sum(int a, int b) {
-      return a + b;
-    }
-
-    public static int divideUnsigned(int dividend, int divisor) {
-      long dividendLong = dividend & 0xffffffffL;
-      long divisorLong = divisor & 0xffffffffL;
-      return (int) (dividendLong / divisorLong);
-    }
-
-    public static int remainderUnsigned(int dividend, int divisor) {
-      long dividendLong = dividend & 0xffffffffL;
-      long divisorLong = divisor & 0xffffffffL;
-      return (int) (dividendLong % divisorLong);
-    }
-
-    public static int compareUnsigned(int a, int b) {
-      int aFlipped = a ^ Integer.MIN_VALUE;
-      int bFlipped = b ^ Integer.MIN_VALUE;
-      return Integer.compare(aFlipped, bFlipped);
-    }
-
-    public static long toUnsignedLong(int value) {
-      return value & 0xffffffffL;
-    }
-  }
-
-  private static final class LongMethods extends TemplateMethodCode {
-    LongMethods(InternalOptions options, DexMethod method, String methodName) {
-      super(options, method, methodName, method.proto.toDescriptorString());
-    }
-
-    public static int hashCode(long i) {
-      return Long.valueOf(i).hashCode();
-    }
-
-    public static long max(long a, long b) {
-      return java.lang.Math.max(a, b);
-    }
-
-    public static long min(long a, long b) {
-      return java.lang.Math.min(a, b);
-    }
-
-    public static long sum(long a, long b) {
-      return a + b;
-    }
-
-    public static long divideUnsigned(long dividend, long divisor) {
-      // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
-
-      if (divisor < 0) { // i.e., divisor >= 2^63:
-        // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
-        // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
-        // implementations of flip() and compare() are inlined here instead.
-        long dividendFlipped = dividend ^ Long.MIN_VALUE;
-        long divisorFlipped = divisor ^ Long.MIN_VALUE;
-        if (dividendFlipped < divisorFlipped) {
-          return 0; // dividend < divisor
-        } else {
-          return 1; // dividend >= divisor
-        }
-      }
-
-      // Optimization - use signed division if dividend < 2^63
-      if (dividend >= 0) {
-        return dividend / divisor;
-      }
-
-      // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
-      // guaranteed to be either exact or one less than the correct value. This follows from the
-      // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
-      // not quite trivial.
-      long quotient = ((dividend >>> 1) / divisor) << 1;
-      long rem = dividend - quotient * divisor;
-
-      // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
-      // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
-      // implementations of flip() and compare() are inlined here instead.
-      long remFlipped = rem ^ Long.MIN_VALUE;
-      long divisorFlipped = divisor ^ Long.MIN_VALUE;
-      return quotient + (remFlipped >= divisorFlipped ? 1 : 0);
-    }
-
-    public static long remainderUnsigned(long dividend, long divisor) {
-      // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
-
-      if (divisor < 0) { // i.e., divisor >= 2^63:
-        // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
-        // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
-        // implementations of flip() and compare() are inlined here instead.
-        long dividendFlipped = dividend ^ Long.MIN_VALUE;
-        long divisorFlipped = divisor ^ Long.MIN_VALUE;
-        if (dividendFlipped < divisorFlipped) {
-          return dividend; // dividend < divisor
-        } else {
-          return dividend - divisor; // dividend >= divisor
-        }
-      }
-
-      // Optimization - use signed modulus if dividend < 2^63
-      if (dividend >= 0) {
-        return dividend % divisor;
-      }
-
-      // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
-      // guaranteed to be either exact or one less than the correct value. This follows from the
-      // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
-      // not quite trivial.
-      long quotient = ((dividend >>> 1) / divisor) << 1;
-      long rem = dividend - quotient * divisor;
-
-      // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
-      // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
-      // implementations of flip() and compare() are inlined here instead.
-      long remFlipped = rem ^ Long.MIN_VALUE;
-      long divisorFlipped = divisor ^ Long.MIN_VALUE;
-      return rem - (remFlipped >= divisorFlipped ? divisor : 0);
-    }
-
-    public static int compareUnsigned(long a, long b) {
-      long aFlipped = a ^ Long.MIN_VALUE;
-      long bFlipped = b ^ Long.MIN_VALUE;
-      return Long.compare(aFlipped, bFlipped);
-    }
-  }
-
   public static final class RewritableMethods {
     // Map class, method, proto to a generator for creating the code and method.
     private final Map<DexString, Map<DexString, Map<DexProto, MethodGenerator>>> rewritable =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
new file mode 100644
index 0000000..3803667
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+
+public final class IntegerMethods extends TemplateMethodCode {
+  public IntegerMethods(InternalOptions options, DexMethod method, String methodName) {
+    super(options, method, methodName, method.proto.toDescriptorString());
+  }
+
+  public static int hashCode(int i) {
+    return Integer.valueOf(i).hashCode();
+  }
+
+  public static int compare(int a, int b) {
+    return Integer.valueOf(a).compareTo(Integer.valueOf(b));
+  }
+
+  public static int max(int a, int b) {
+    return Math.max(a, b);
+  }
+
+  public static int min(int a, int b) {
+    return Math.min(a, b);
+  }
+
+  public static int sum(int a, int b) {
+    return a + b;
+  }
+
+  public static int divideUnsigned(int dividend, int divisor) {
+    long dividendLong = dividend & 0xffffffffL;
+    long divisorLong = divisor & 0xffffffffL;
+    return (int) (dividendLong / divisorLong);
+  }
+
+  public static int remainderUnsigned(int dividend, int divisor) {
+    long dividendLong = dividend & 0xffffffffL;
+    long divisorLong = divisor & 0xffffffffL;
+    return (int) (dividendLong % divisorLong);
+  }
+
+  public static int compareUnsigned(int a, int b) {
+    int aFlipped = a ^ Integer.MIN_VALUE;
+    int bFlipped = b ^ Integer.MIN_VALUE;
+    return Integer.compare(aFlipped, bFlipped);
+  }
+
+  public static long toUnsignedLong(int value) {
+    return value & 0xffffffffL;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java
new file mode 100644
index 0000000..d868664
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java
@@ -0,0 +1,109 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+
+public final class LongMethods extends TemplateMethodCode {
+  public LongMethods(InternalOptions options, DexMethod method, String methodName) {
+    super(options, method, methodName, method.proto.toDescriptorString());
+  }
+
+  public static int hashCode(long i) {
+    return Long.valueOf(i).hashCode();
+  }
+
+  public static long max(long a, long b) {
+    return Math.max(a, b);
+  }
+
+  public static long min(long a, long b) {
+    return Math.min(a, b);
+  }
+
+  public static long sum(long a, long b) {
+    return a + b;
+  }
+
+  public static long divideUnsigned(long dividend, long divisor) {
+    // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
+
+    if (divisor < 0) { // i.e., divisor >= 2^63:
+      // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
+      // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+      // implementations of flip() and compare() are inlined here instead.
+      long dividendFlipped = dividend ^ Long.MIN_VALUE;
+      long divisorFlipped = divisor ^ Long.MIN_VALUE;
+      if (dividendFlipped < divisorFlipped) {
+        return 0; // dividend < divisor
+      } else {
+        return 1; // dividend >= divisor
+      }
+    }
+
+    // Optimization - use signed division if dividend < 2^63
+    if (dividend >= 0) {
+      return dividend / divisor;
+    }
+
+    // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+    // guaranteed to be either exact or one less than the correct value. This follows from the
+    // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
+    // not quite trivial.
+    long quotient = ((dividend >>> 1) / divisor) << 1;
+    long rem = dividend - quotient * divisor;
+
+    // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
+    // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+    // implementations of flip() and compare() are inlined here instead.
+    long remFlipped = rem ^ Long.MIN_VALUE;
+    long divisorFlipped = divisor ^ Long.MIN_VALUE;
+    return quotient + (remFlipped >= divisorFlipped ? 1 : 0);
+  }
+
+  public static long remainderUnsigned(long dividend, long divisor) {
+    // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
+
+    if (divisor < 0) { // i.e., divisor >= 2^63:
+      // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
+      // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+      // implementations of flip() and compare() are inlined here instead.
+      long dividendFlipped = dividend ^ Long.MIN_VALUE;
+      long divisorFlipped = divisor ^ Long.MIN_VALUE;
+      if (dividendFlipped < divisorFlipped) {
+        return dividend; // dividend < divisor
+      } else {
+        return dividend - divisor; // dividend >= divisor
+      }
+    }
+
+    // Optimization - use signed modulus if dividend < 2^63
+    if (dividend >= 0) {
+      return dividend % divisor;
+    }
+
+    // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+    // guaranteed to be either exact or one less than the correct value. This follows from the
+    // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
+    // not quite trivial.
+    long quotient = ((dividend >>> 1) / divisor) << 1;
+    long rem = dividend - quotient * divisor;
+
+    // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
+    // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+    // implementations of flip() and compare() are inlined here instead.
+    long remFlipped = rem ^ Long.MIN_VALUE;
+    long divisorFlipped = divisor ^ Long.MIN_VALUE;
+    return rem - (remFlipped >= divisorFlipped ? divisor : 0);
+  }
+
+  public static int compareUnsigned(long a, long b) {
+    long aFlipped = a ^ Long.MIN_VALUE;
+    long bFlipped = b ^ Long.MIN_VALUE;
+    return Long.compare(aFlipped, bFlipped);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
new file mode 100644
index 0000000..44f32ee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2019, 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.desugar;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import org.junit.Test;
+
+public class BackportedMethodMergeTest extends TestBase {
+  @Test
+  public void testD8Merge() throws Exception {
+    String jvmOutput = testForJvm()
+        .addTestClasspath()
+        .run(MergeRun.class).getStdOut();
+    // See b/123242448
+    Path zip1 = temp.newFile("first.zip").toPath();
+    Path zip2 = temp.newFile("second.zip").toPath();
+
+    testForD8()
+        .setMinApi(AndroidApiLevel.L)
+        .addProgramClasses(MergeRun.class, MergeInputB.class)
+        .compile()
+        .assertNoMessages()
+        .writeToZip(zip1);
+    testForD8()
+        .setMinApi(AndroidApiLevel.L)
+        .addProgramClasses(MergeInputA.class)
+        .compile()
+        .assertNoMessages()
+        .writeToZip(zip2);
+    testForD8()
+        .addProgramFiles(zip1, zip2)
+        .setMinApi(AndroidApiLevel.L)
+        .compile()
+        .assertNoMessages()
+        .run(MergeRun.class)
+        .assertSuccessWithOutput(jvmOutput);
+  }
+
+  static class MergeInputA {
+    public void foo() {
+      System.out.println(Integer.hashCode(42));
+      System.out.println(Double.hashCode(42.0));
+    }
+  }
+
+  static class MergeInputB {
+    public void foo() {
+      System.out.println(Integer.hashCode(43));
+      System.out.println(Double.hashCode(43.0));
+    }
+  }
+
+  static class MergeRun {
+    public static void main(String[] args) {
+      MergeInputA a = new MergeInputA();
+      MergeInputB b = new MergeInputB();
+      a.foo();
+      b.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
deleted file mode 100644
index ab3e7a9..0000000
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2018, 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.desugar;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static java.util.stream.Collectors.toList;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.desugar.backports.BooleanBackportTest;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @deprecated New tests should follow the pattern of {@link BooleanBackportTest}.
- */
-@Deprecated
-public class BackportedMethodRewriterTest extends TestBase {
-  static String expectedOutput = "";
-
-  @Before
-  public void testJvm() throws Exception {
-    expectedOutput = testForJvm()
-        .addTestClasspath()
-        .run(TestMethods.class).getStdOut();
-  }
-
-  @Test
-  public void testD8() throws Exception {
-    testForD8()
-        .addProgramClasses(TestMethods.class)
-        .run(TestMethods.class)
-        .assertSuccessWithOutput(expectedOutput);
-
-    assertDesugaring(AndroidApiLevel.O, 17);
-    assertDesugaring(AndroidApiLevel.N, 10);
-    assertDesugaring(AndroidApiLevel.K, 2);
-    assertDesugaring(AndroidApiLevel.J_MR2, 0);
-  }
-
-  private void assertDesugaring(AndroidApiLevel apiLevel, int expectedJavaInvokeStatics)
-      throws Exception {
-    D8TestCompileResult runResult = testForD8()
-        .addProgramClasses(TestMethods.class)
-        .setMinApi(apiLevel)
-        .compile();
-
-    MethodSubject mainMethod = runResult.inspector()
-        .clazz(TestMethods.class)
-        .mainMethod();
-    assertThat(mainMethod, isPresent());
-
-    List<InstructionSubject> javaInvokeStatics = mainMethod
-        .streamInstructions()
-        .filter(InstructionSubject::isInvokeStatic)
-        .filter(is -> is.getMethod().holder.toDescriptorString().startsWith("Ljava/"))
-        .collect(toList());
-
-    int actualJavaInvokeStatics = javaInvokeStatics.size();
-    assertEquals("Expected "
-        + expectedJavaInvokeStatics
-        + " invoke-static on java/*/<Type> but found "
-        + actualJavaInvokeStatics
-        + ": "
-        + javaInvokeStatics, expectedJavaInvokeStatics, actualJavaInvokeStatics);
-  }
-
-  @Test
-  public void testD8Merge() throws Exception {
-    String jvmOutput = testForJvm()
-        .addTestClasspath()
-        .run(MergeRun.class).getStdOut();
-    // See b/123242448
-    Path zip1 = temp.newFile("first.zip").toPath();
-    Path zip2 = temp.newFile("second.zip").toPath();
-
-    testForD8()
-        .setMinApi(AndroidApiLevel.L)
-        .addProgramClasses(MergeRun.class, MergeInputB.class)
-        .compile()
-        .assertNoMessages()
-        .writeToZip(zip1);
-    testForD8()
-        .setMinApi(AndroidApiLevel.L)
-        .addProgramClasses(MergeInputA.class)
-        .compile()
-        .assertNoMessages()
-        .writeToZip(zip2);
-    testForD8()
-        .addProgramFiles(zip1, zip2)
-        .setMinApi(AndroidApiLevel.L)
-        .compile()
-        .assertNoMessages()
-        .run(MergeRun.class)
-        .assertSuccessWithOutput(jvmOutput);
-  }
-
-
-  static class MergeInputA {
-    public void foo() {
-      System.out.println(Integer.hashCode(42));
-      System.out.println(Double.hashCode(42.0));
-    }
-  }
-
-  static class MergeInputB {
-    public void foo() {
-      System.out.println(Integer.hashCode(43));
-      System.out.println(Double.hashCode(43.0));
-    }
-  }
-
-  static class MergeRun {
-    public static void main(String[] args) {
-      MergeInputA a = new MergeInputA();
-      MergeInputB b = new MergeInputB();
-      a.foo();
-      b.foo();
-    }
-  }
-
-  static class TestMethods {
-    public static void main(String[] args) {
-      int[] aInts = new int[]{42, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
-      int[] bInts = new int[]{43, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
-      for (int aInt : aInts) {
-        System.out.println(Integer.hashCode(aInt));
-        System.out.println(Integer.toUnsignedLong(aInt));
-        for (int bInt : bInts) {
-          System.out.println(Integer.compare(aInt, bInt));
-          System.out.println(Integer.max(aInt, bInt));
-          System.out.println(Integer.min(aInt, bInt));
-          System.out.println(Integer.sum(aInt, bInt));
-          System.out.println(Integer.divideUnsigned(aInt, bInt));
-          System.out.println(Integer.remainderUnsigned(aInt, bInt));
-          System.out.println(Integer.compareUnsigned(aInt, bInt));
-        }
-      }
-
-      long[] aLongs = new long[]{42L, 1L, -1L, Integer.MIN_VALUE, Integer.MAX_VALUE,
-          Long.MAX_VALUE, Long.MIN_VALUE};
-      long[] bLongs = new long[]{43L, 2L, -2L, Integer.MIN_VALUE, Integer.MAX_VALUE,
-          Long.MAX_VALUE, Long.MIN_VALUE};
-      for (long aLong : aLongs) {
-        System.out.println(Long.hashCode(aLong));
-        for (long bLong : bLongs) {
-          System.out.println(Long.compare(aLong, bLong));
-          System.out.println(Long.max(aLong, bLong));
-          System.out.println(Long.min(aLong, bLong));
-          System.out.println(Long.sum(aLong, bLong));
-          System.out.println(Long.divideUnsigned(aLong, bLong));
-          System.out.println(Long.remainderUnsigned(aLong, bLong));
-          System.out.println(Long.compareUnsigned(aLong, bLong));
-        }
-      }
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java
new file mode 100644
index 0000000..952c7cd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java
@@ -0,0 +1,157 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class IntegerBackportTest extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters().withDexRuntimes().build();
+  }
+
+  public IntegerBackportTest(TestParameters parameters) {
+    super(parameters, Integer.class, Main.class);
+    registerTarget(AndroidApiLevel.O, 35);
+    registerTarget(AndroidApiLevel.N, 11);
+    registerTarget(AndroidApiLevel.K, 7);
+  }
+
+  static final class Main extends MiniAssert {
+    private static final int[] interestingValues = {
+        Integer.MIN_VALUE, Integer.MAX_VALUE,
+        Short.MIN_VALUE, Short.MAX_VALUE,
+        Byte.MIN_VALUE, Byte.MAX_VALUE,
+        0,
+        -1, 1,
+        -42, 42
+    };
+
+    public static void main(String[] args) {
+      testHashCode();
+      testToUnsignedLong();
+      testCompare();
+      testMax();
+      testMin();
+      testSum();
+      testCompareUnsigned();
+      testDivideUnsigned();
+      testRemainderUnsigned();
+    }
+
+    private static void testHashCode() {
+      for (int value : interestingValues) {
+        assertEquals(value, Integer.hashCode(value));
+      }
+    }
+
+    private static void testToUnsignedLong() {
+      assertEquals(0L, Integer.toUnsignedLong(0));
+      assertEquals(2_147_483_647L, Integer.toUnsignedLong(Integer.MAX_VALUE));
+      assertEquals(2_147_483_648L, Integer.toUnsignedLong(Integer.MIN_VALUE));
+      assertEquals(4_294_967_295L, Integer.toUnsignedLong(-1));
+    }
+
+    private static void testCompare() {
+      assertEquals(1, Integer.compare(1, 0));
+      assertEquals(0, Integer.compare(0, 0));
+      assertEquals(-1, Integer.compare(0, 1));
+      assertEquals(-1, Integer.compare(Integer.MIN_VALUE, Integer.MAX_VALUE));
+      assertEquals(1, Integer.compare(Integer.MAX_VALUE, Integer.MIN_VALUE));
+      assertEquals(0, Integer.compare(Integer.MIN_VALUE, Integer.MIN_VALUE));
+      assertEquals(0, Integer.compare(Integer.MAX_VALUE, Integer.MAX_VALUE));
+    }
+
+    private static void testMax() {
+      for (int x : interestingValues) {
+        for (int y : interestingValues) {
+          assertEquals(Math.max(x, y), Integer.max(x, y));
+        }
+      }
+    }
+
+    private static void testMin() {
+      for (int x : interestingValues) {
+        for (int y : interestingValues) {
+          assertEquals(Math.min(x, y), Integer.min(x, y));
+        }
+      }
+    }
+
+    private static void testSum() {
+      for (int x : interestingValues) {
+        for (int y : interestingValues) {
+          assertEquals(x + y, Integer.sum(x, y));
+        }
+      }
+    }
+
+    private static void testCompareUnsigned() {
+      assertEquals(0, Integer.compareUnsigned(0, 0));
+      assertEquals(-1, Integer.compareUnsigned(0, Integer.MAX_VALUE));
+      assertEquals(-1, Integer.compareUnsigned(0, Integer.MIN_VALUE));
+      assertEquals(-1, Integer.compareUnsigned(0, -1));
+
+      assertEquals(1, Integer.compareUnsigned(Integer.MAX_VALUE, 0));
+      assertEquals(0, Integer.compareUnsigned(Integer.MAX_VALUE, Integer.MAX_VALUE));
+      assertEquals(-1, Integer.compareUnsigned(Integer.MAX_VALUE, Integer.MIN_VALUE));
+      assertEquals(-1, Integer.compareUnsigned(Integer.MAX_VALUE, -1));
+
+      assertEquals(1, Integer.compareUnsigned(Integer.MIN_VALUE, 0));
+      assertEquals(1, Integer.compareUnsigned(Integer.MIN_VALUE, Integer.MAX_VALUE));
+      assertEquals(0, Integer.compareUnsigned(Integer.MIN_VALUE, Integer.MIN_VALUE));
+      assertEquals(-1, Integer.compareUnsigned(Integer.MIN_VALUE, -1));
+
+      assertEquals(1, Integer.compareUnsigned(-1, 0));
+      assertEquals(1, Integer.compareUnsigned(-1, Integer.MAX_VALUE));
+      assertEquals(1, Integer.compareUnsigned(-1, Integer.MIN_VALUE));
+      assertEquals(0, Integer.compareUnsigned(-1, -1));
+    }
+
+    private static void testDivideUnsigned() {
+      for (int x : interestingValues) {
+        for (int y : interestingValues) {
+          if (y == 0) continue;
+
+          BigInteger xUnsigned = BigInteger.valueOf(x & 0xffffffffL);
+          BigInteger yUnsigned = BigInteger.valueOf(y & 0xffffffffL);
+          int expected = xUnsigned.divide(yUnsigned).intValue();
+
+          assertEquals(expected, Integer.divideUnsigned(x, y));
+        }
+      }
+
+      try {
+        throw new AssertionError(Integer.divideUnsigned(1, 0));
+      } catch (ArithmeticException expected) {
+      }
+    }
+
+    private static void testRemainderUnsigned() {
+      for (int x : interestingValues) {
+        for (int y : interestingValues) {
+          if (y == 0) continue;
+
+          BigInteger xUnsigned = BigInteger.valueOf(x & 0xffffffffL);
+          BigInteger yUnsigned = BigInteger.valueOf(y & 0xffffffffL);
+          int expected = xUnsigned.remainder(yUnsigned).intValue();
+
+          assertEquals(expected, Integer.remainderUnsigned(x, y));
+        }
+      }
+
+      try {
+        throw new AssertionError(Integer.divideUnsigned(1, 0));
+      } catch (ArithmeticException expected) {
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java
new file mode 100644
index 0000000..469e652
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java
@@ -0,0 +1,163 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class LongBackportTest extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters().withDexRuntimes().build();
+  }
+
+  public LongBackportTest(TestParameters parameters) {
+    super(parameters, Long.class, Main.class);
+    registerTarget(AndroidApiLevel.O, 31);
+    registerTarget(AndroidApiLevel.N, 11);
+    registerTarget(AndroidApiLevel.K, 7);
+  }
+
+  static final class Main extends MiniAssert {
+    private static final long[] interestingValues = {
+        Long.MIN_VALUE, Long.MAX_VALUE,
+        Long.MIN_VALUE, Long.MAX_VALUE,
+        Short.MIN_VALUE, Short.MAX_VALUE,
+        Byte.MIN_VALUE, Byte.MAX_VALUE,
+        0L,
+        -1L, 1L,
+        -42L, 42L
+    };
+
+    public static void main(String[] args) {
+      testHashCode();
+      testCompare();
+      testMax();
+      testMin();
+      testSum();
+      testCompareUnsigned();
+      testDivideUnsigned();
+      testRemainderUnsigned();
+    }
+
+    private static void testHashCode() {
+      for (long value : interestingValues) {
+        assertEquals(expectedHashCode(value), Long.hashCode(value));
+      }
+    }
+
+    private static void testCompare() {
+      assertEquals(1, Long.compare(1, 0));
+      assertEquals(0, Long.compare(0, 0));
+      assertEquals(-1, Long.compare(0, 1));
+      assertEquals(-1, Long.compare(Long.MIN_VALUE, Long.MAX_VALUE));
+      assertEquals(1, Long.compare(Long.MAX_VALUE, Long.MIN_VALUE));
+      assertEquals(0, Long.compare(Long.MIN_VALUE, Long.MIN_VALUE));
+      assertEquals(0, Long.compare(Long.MAX_VALUE, Long.MAX_VALUE));
+    }
+
+    private static void testMax() {
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          assertEquals(Math.max(x, y), Long.max(x, y));
+        }
+      }
+    }
+
+    private static void testMin() {
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          assertEquals(Math.min(x, y), Long.min(x, y));
+        }
+      }
+    }
+
+    private static void testSum() {
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          assertEquals(x + y, Long.sum(x, y));
+        }
+      }
+    }
+
+    private static void testCompareUnsigned() {
+      assertEquals(0, Long.compareUnsigned(0, 0));
+      assertEquals(-1, Long.compareUnsigned(0, Long.MAX_VALUE));
+      assertEquals(-1, Long.compareUnsigned(0, Long.MIN_VALUE));
+      assertEquals(-1, Long.compareUnsigned(0, -1));
+
+      assertEquals(1, Long.compareUnsigned(Long.MAX_VALUE, 0));
+      assertEquals(0, Long.compareUnsigned(Long.MAX_VALUE, Long.MAX_VALUE));
+      assertEquals(-1, Long.compareUnsigned(Long.MAX_VALUE, Long.MIN_VALUE));
+      assertEquals(-1, Long.compareUnsigned(Long.MAX_VALUE, -1));
+
+      assertEquals(1, Long.compareUnsigned(Long.MIN_VALUE, 0));
+      assertEquals(1, Long.compareUnsigned(Long.MIN_VALUE, Long.MAX_VALUE));
+      assertEquals(0, Long.compareUnsigned(Long.MIN_VALUE, Long.MIN_VALUE));
+      assertEquals(-1, Long.compareUnsigned(Long.MIN_VALUE, -1));
+
+      assertEquals(1, Long.compareUnsigned(-1, 0));
+      assertEquals(1, Long.compareUnsigned(-1, Long.MAX_VALUE));
+      assertEquals(1, Long.compareUnsigned(-1, Long.MIN_VALUE));
+      assertEquals(0, Long.compareUnsigned(-1, -1));
+    }
+
+    private static void testDivideUnsigned() {
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          if (y == 0L) continue;
+
+          BigInteger xUnsigned = longToBigInteger(x);
+          BigInteger yUnsigned = longToBigInteger(y);
+          long expected = xUnsigned.divide(yUnsigned).longValue();
+
+          assertEquals(expected, Long.divideUnsigned(x, y));
+        }
+      }
+
+      try {
+        throw new AssertionError(Long.divideUnsigned(1L, 0L));
+      } catch (ArithmeticException expected) {
+      }
+    }
+
+    private static void testRemainderUnsigned() {
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          if (y == 0L) continue;
+
+          BigInteger xUnsigned = longToBigInteger(x);
+          BigInteger yUnsigned = longToBigInteger(y);
+          long expected = xUnsigned.remainder(yUnsigned).longValue();
+
+          assertEquals(expected, Long.remainderUnsigned(x, y));
+        }
+      }
+
+      try {
+        throw new AssertionError(Long.remainderUnsigned(1L, 0L));
+      } catch (ArithmeticException expected) {
+      }
+    }
+
+    @IgnoreInvokes
+    private static int expectedHashCode(long value) {
+      return Long.valueOf(value).hashCode();
+    }
+
+    private static BigInteger longToBigInteger(long value) {
+      BigInteger bigInt = BigInteger.valueOf(value & 0x7fffffffffffffffL);
+      if (value < 0) {
+        bigInt = bigInt.setBit(Long.SIZE - 1);
+      }
+      return bigInt;
+    }
+  }
+}