Desugar Long.compareUnsigned and Integer.remainder/divide/compareUnsigned

Test: Java8MethodsTest
Change-Id: Iaf476a6761d8d73119faff3a7779f978cb7d0c22
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index 1ba0620..69d0b48 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -214,6 +214,18 @@
       return new IntegerMethods(options, method, "sumImpl");
     }
 
+    public static IntegerMethods divideUnsignedCode(InternalOptions options, DexMethod method) {
+      return new IntegerMethods(options, method, "divideUnsignedImpl");
+    }
+
+    public static IntegerMethods remainderUnsignedCode(InternalOptions options, DexMethod method) {
+      return new IntegerMethods(options, method, "remainderUnsignedImpl");
+    }
+
+    public static IntegerMethods compareUnsignedCode(InternalOptions options, DexMethod method) {
+      return new IntegerMethods(options, method, "compareUnsignedImpl");
+    }
+
     public static int hashCodeImpl(int i) {
       return Integer.valueOf(i).hashCode();
     }
@@ -229,6 +241,24 @@
     public static int sumImpl(int a, int b) {
       return a + b;
     }
+
+    public static int divideUnsignedImpl(int dividend, int divisor) {
+      long dividendLong = dividend & 0xffffffffL;
+      long divisorLong = divisor & 0xffffffffL;
+      return (int) (dividendLong / divisorLong);
+    }
+
+    public static int remainderUnsignedImpl(int dividend, int divisor) {
+      long dividendLong = dividend & 0xffffffffL;
+      long divisorLong = divisor & 0xffffffffL;
+      return (int) (dividendLong % divisorLong);
+    }
+
+    public static int compareUnsignedImpl(int a, int b) {
+      int aFlipped = a ^ Integer.MIN_VALUE;
+      int bFlipped = b ^ Integer.MIN_VALUE;
+      return (aFlipped < bFlipped) ? -1 : ((aFlipped > bFlipped) ? 1 : 0);
+    }
   }
 
   private static final class DoubleMethods extends TemplateMethodCode {
@@ -392,6 +422,10 @@
       return new LongMethods(options, method, "remainderUnsignedImpl");
     }
 
+    public static LongMethods compareUnsignedCode(InternalOptions options, DexMethod method) {
+      return new LongMethods(options, method, "compareUnsignedImpl");
+    }
+
     public static int hashCodeImpl(long i) {
       return Long.valueOf(i).hashCode();
     }
@@ -479,6 +513,12 @@
       long divisorFlipped = divisor ^ Long.MIN_VALUE;
       return rem - (remFlipped >= divisorFlipped ? divisor : 0);
     }
+
+    public static int compareUnsignedImpl(long a, long b) {
+      long aFlipped = a ^ Long.MIN_VALUE;
+      long bFlipped = b ^ Long.MIN_VALUE;
+      return (aFlipped < bFlipped) ? -1 : ((aFlipped > bFlipped) ? 1 : 0);
+    }
   }
 
   private static final class CharacterMethods extends TemplateMethodCode {
@@ -688,11 +728,31 @@
     }
 
     private void initializeJava8UnsignedOperations(DexItemFactory factory) {
-      DexString clazz = factory.boxedLongDescriptor;
+      DexString clazz = factory.boxedIntDescriptor;
+
+      // int Integer.divideUnsigned(int a, int b)
+      DexString method = factory.createString("divideUnsigned");
+      DexProto proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+      addOrGetMethod(clazz, method).put(proto,
+          new MethodGenerator(IntegerMethods::divideUnsignedCode, clazz, method, proto));
+
+      // int Integer.remainderUnsigned(int a, int b)
+      method = factory.createString("remainderUnsigned");
+      proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+      addOrGetMethod(clazz, method).put(proto,
+          new MethodGenerator(IntegerMethods::remainderUnsignedCode, clazz, method, proto));
+
+      // int Integer.compareUnsigned(int a, int b)
+      method = factory.createString("compareUnsigned");
+      proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+      addOrGetMethod(clazz, method).put(proto,
+          new MethodGenerator(IntegerMethods::compareUnsignedCode, clazz, method, proto));
+
+      clazz = factory.boxedLongDescriptor;
 
       // long Long.divideUnsigned(long a, long b)
-      DexString method = factory.createString("divideUnsigned");
-      DexProto proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+      method = factory.createString("divideUnsigned");
+      proto = factory.createProto(factory.longType, factory.longType, factory.longType);
       addOrGetMethod(clazz, method).put(proto,
           new MethodGenerator(LongMethods::divideUnsignedCode, clazz, method, proto));
 
@@ -701,6 +761,12 @@
       proto = factory.createProto(factory.longType, factory.longType, factory.longType);
       addOrGetMethod(clazz, method).put(proto,
           new MethodGenerator(LongMethods::remainderUnsignedCode, clazz, method, proto));
+
+      // int Long.compareUnsigned(long a, long b)
+      method = factory.createString("compareUnsigned");
+      proto = factory.createProto(factory.intType, factory.longType, factory.longType);
+      addOrGetMethod(clazz, method).put(proto,
+          new MethodGenerator(LongMethods::compareUnsignedCode, clazz, method, proto));
     }
 
     private Map<DexString, Map<DexProto, MethodGenerator>> addOrGetClass(DexString clazz) {
diff --git a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
index ebc9b29..cb4c9b7 100644
--- a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
@@ -36,7 +36,7 @@
         .run(Java8Methods.class)
         .assertSuccessWithOutput(expectedOutput);
 
-    assertDesugaring(AndroidApiLevel.O, 27);
+    assertDesugaring(AndroidApiLevel.O, 31);
     assertDesugaring(AndroidApiLevel.N, 25);
     assertDesugaring(AndroidApiLevel.M, 0);
   }
@@ -142,6 +142,9 @@
           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));
         }
       }
 
@@ -198,6 +201,7 @@
           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));
         }
       }