Add Math.div methods
Bug: b/388147728
Change-Id: I2c3bd5bea211be4e5400a765a7b3a1e048229d9c
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 3553629..b52dbf0 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
@@ -2022,6 +2022,44 @@
addProvider(
new MethodGenerator(
method, BackportedMethods::MathMethods_ceilModLongInt, "ceilModLongInt"));
+
+ // int divideExact(int, int)
+ // long divideExact(long, long)
+ name = factory.createString("divideExact");
+ proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::MathMethods_divideExactInt, "divideExactInt"));
+ proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::MathMethods_divideExactLong, "divideExactLong"));
+
+ // int floorDivExact(int, int)
+ // long floorDivExact(long, long)
+ name = factory.createString("floorDivExact");
+ proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::MathMethods_floorDivExactInt, "floorDivExactInt"));
+ proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::MathMethods_floorDivExactLong, "floorDivExactLong"));
+
+ // long unsignedMultiplyHigh(long, long)
+ name = factory.createString("unsignedMultiplyHigh");
+ proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method,
+ BackportedMethods::MathMethods_unsignedMultiplyHigh,
+ "unsignedMultiplyHigh"));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index 89ca871..24224c7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -6193,6 +6193,348 @@
ImmutableList.of());
}
+ public static CfCode MathMethods_divideExactInt(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 2,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.INT, 0),
+ new CfConstNumber(-2147483648, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label2),
+ new CfLoad(ValueType.INT, 1),
+ new CfConstNumber(-1, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(factory.createString("integer overflow")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1}, new FrameType[] {FrameType.intType(), FrameType.intType()})),
+ new CfLoad(ValueType.INT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Div, NumericType.INT),
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode MathMethods_divideExactLong(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(-9223372036854775808L, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.NE, ValueType.INT, label2),
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(-1, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(factory.createString("long overflow")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Div, NumericType.LONG),
+ new CfReturn(ValueType.LONG),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode MathMethods_floorDivExactInt(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 5,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.INT, 0),
+ new CfConstNumber(-2147483648, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label2),
+ new CfLoad(ValueType.INT, 1),
+ new CfConstNumber(-1, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(factory.createString("integer overflow")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1}, new FrameType[] {FrameType.intType(), FrameType.intType()})),
+ new CfLoad(ValueType.INT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Div, NumericType.INT),
+ new CfStore(ValueType.INT, 2),
+ label3,
+ new CfLoad(ValueType.INT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfLoad(ValueType.INT, 2),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfStore(ValueType.INT, 3),
+ label4,
+ new CfLoad(ValueType.INT, 3),
+ new CfIf(IfType.NE, ValueType.INT, label6),
+ label5,
+ new CfLoad(ValueType.INT, 2),
+ new CfReturn(ValueType.INT),
+ label6,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfConstNumber(1, ValueType.INT),
+ new CfLoad(ValueType.INT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.INT),
+ new CfConstNumber(31, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfStore(ValueType.INT, 4),
+ label7,
+ new CfLoad(ValueType.INT, 4),
+ new CfIf(IfType.GE, ValueType.INT, label8),
+ new CfLoad(ValueType.INT, 2),
+ new CfConstNumber(1, ValueType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfGoto(label9),
+ label8,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 2),
+ label9,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ }),
+ new ArrayDeque<>(Arrays.asList(FrameType.intType()))),
+ new CfReturn(ValueType.INT),
+ label10),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode MathMethods_floorDivExactLong(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 6,
+ 10,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(-9223372036854775808L, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.NE, ValueType.INT, label2),
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(-1, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(factory.createString("long overflow")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Div, NumericType.LONG),
+ new CfStore(ValueType.LONG, 4),
+ label3,
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfLoad(ValueType.LONG, 4),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG),
+ new CfStore(ValueType.LONG, 6),
+ label4,
+ new CfLoad(ValueType.LONG, 6),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.NE, ValueType.INT, label6),
+ label5,
+ new CfLoad(ValueType.LONG, 4),
+ new CfReturn(ValueType.LONG),
+ label6,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfConstNumber(1, ValueType.LONG),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.LONG),
+ new CfConstNumber(63, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.LONG),
+ new CfStore(ValueType.LONG, 8),
+ label7,
+ new CfLoad(ValueType.LONG, 8),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.GE, ValueType.INT, label8),
+ new CfLoad(ValueType.LONG, 4),
+ new CfConstNumber(1, ValueType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG),
+ new CfGoto(label9),
+ label8,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 4),
+ label9,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ }),
+ new ArrayDeque<>(Arrays.asList(FrameType.longType()))),
+ new CfReturn(ValueType.LONG),
+ label10),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode MathMethods_floorDivInt(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -7451,6 +7793,176 @@
ImmutableList.of());
}
+ public static CfCode MathMethods_unsignedMultiplyHigh(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ CfLabel label11 = new CfLabel();
+ CfLabel label12 = new CfLabel();
+ CfLabel label13 = new CfLabel();
+ CfLabel label14 = new CfLabel();
+ CfLabel label15 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 6,
+ 22,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 4),
+ label1,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 6),
+ label2,
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 8),
+ label3,
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 10),
+ label4,
+ new CfLoad(ValueType.LONG, 6),
+ new CfLoad(ValueType.LONG, 10),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfStore(ValueType.LONG, 12),
+ label5,
+ new CfLoad(ValueType.LONG, 4),
+ new CfLoad(ValueType.LONG, 10),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfLoad(ValueType.LONG, 12),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 14),
+ label6,
+ new CfLoad(ValueType.LONG, 14),
+ new CfConstNumber(4294967295L, ValueType.LONG),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+ new CfStore(ValueType.LONG, 16),
+ label7,
+ new CfLoad(ValueType.LONG, 14),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfStore(ValueType.LONG, 18),
+ label8,
+ new CfLoad(ValueType.LONG, 16),
+ new CfLoad(ValueType.LONG, 6),
+ new CfLoad(ValueType.LONG, 8),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 16),
+ label9,
+ new CfLoad(ValueType.LONG, 4),
+ new CfLoad(ValueType.LONG, 8),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+ new CfLoad(ValueType.LONG, 18),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfLoad(ValueType.LONG, 16),
+ new CfConstNumber(32, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 20),
+ label10,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.GE, ValueType.INT, label12),
+ label11,
+ new CfLoad(ValueType.LONG, 20),
+ new CfLoad(ValueType.LONG, 2),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 20),
+ label12,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
+ },
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(IfType.GE, ValueType.INT, label14),
+ label13,
+ new CfLoad(ValueType.LONG, 20),
+ new CfLoad(ValueType.LONG, 0),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+ new CfStore(ValueType.LONG, 20),
+ label14,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
+ },
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 20),
+ new CfReturn(ValueType.LONG),
+ label15),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode MethodMethods_getParameterCount(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/test/examplesJava21/backport/MathJava21Test.java b/src/test/examplesJava21/backport/MathJava21Test.java
index ae6e48a..1c34ed9 100644
--- a/src/test/examplesJava21/backport/MathJava21Test.java
+++ b/src/test/examplesJava21/backport/MathJava21Test.java
@@ -25,7 +25,7 @@
public MathJava21Test(TestParameters parameters) {
super(parameters, Math.class, Main.class);
- registerTarget(AndroidApiLevel.V, 70);
+ registerTarget(AndroidApiLevel.V, 92);
}
static final class Main extends MiniAssert {
@@ -45,6 +45,14 @@
testCeilModIntInt();
testCeilModLongLong();
testCeilModLongInt();
+
+ testDivideExactInt();
+ testDivideExactLong();
+
+ testFloorDivExactInt();
+ testFloorDivExactLong();
+
+ testUnsignedMultiplyHigh();
}
private static void testClampInt() {
@@ -200,5 +208,64 @@
assertEquals(-3L, Math.ceilMod(-3L, 7));
assertEquals(0L, Math.ceilMod(Long.MIN_VALUE, -1));
}
+
+ private static void testDivideExactInt() {
+ assertEquals(1, Math.divideExact(7, 7));
+ assertEquals(-1, Math.divideExact(-7, 7));
+ assertEquals(0, Math.divideExact(3, 7));
+ assertEquals(0, Math.divideExact(-3, 7));
+ try {
+ Math.divideExact(Integer.MIN_VALUE, -1);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testDivideExactLong() {
+ assertEquals(1L, Math.divideExact(7L, 7L));
+ assertEquals(-1L, Math.divideExact(-7L, 7L));
+ assertEquals(0, Math.divideExact(3L, 7L));
+ assertEquals(0, Math.divideExact(-3L, 7L));
+ try {
+ Math.divideExact(Long.MIN_VALUE, -1L);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testFloorDivExactInt() {
+ assertEquals(1, Math.floorDivExact(7, 7));
+ assertEquals(-1, Math.floorDivExact(-7, 7));
+ assertEquals(0, Math.floorDivExact(3, 7));
+ assertEquals(-1, Math.floorDivExact(-3, 7));
+ try {
+ Math.floorDivExact(Integer.MIN_VALUE, -1);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testFloorDivExactLong() {
+ assertEquals(1L, Math.floorDivExact(7L, 7L));
+ assertEquals(-1L, Math.floorDivExact(-7L, 7L));
+ assertEquals(0L, Math.floorDivExact(3L, 7L));
+ assertEquals(-1L, Math.floorDivExact(-3L, 7L));
+ try {
+ Math.floorDivExact(Long.MIN_VALUE, -1L);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testUnsignedMultiplyHigh() {
+ assertEquals(
+ 31696182030193L, Math.unsignedMultiplyHigh(8222222222222222L, 71111111111111111L));
+ assertEquals(
+ 71079414929080917L, Math.unsignedMultiplyHigh(-8222222222222222L, 71111111111111111L));
+ }
}
}
diff --git a/src/test/examplesJava21/backport/StrictMathJava21Test.java b/src/test/examplesJava21/backport/StrictMathJava21Test.java
index 95f5d0e..e39d818 100644
--- a/src/test/examplesJava21/backport/StrictMathJava21Test.java
+++ b/src/test/examplesJava21/backport/StrictMathJava21Test.java
@@ -25,7 +25,7 @@
public StrictMathJava21Test(TestParameters parameters) {
super(parameters, StrictMath.class, Main.class);
- registerTarget(AndroidApiLevel.V, 70);
+ registerTarget(AndroidApiLevel.V, 92);
}
static final class Main extends MiniAssert {
@@ -45,6 +45,14 @@
testCeilModIntInt();
testCeilModLongLong();
testCeilModLongInt();
+
+ testDivideExactInt();
+ testDivideExactLong();
+
+ testFloorDivExactInt();
+ testFloorDivExactLong();
+
+ testUnsignedMultiplyHigh();
}
private static void testClampInt() {
@@ -200,5 +208,65 @@
assertEquals(-3L, StrictMath.ceilMod(-3L, 7));
assertEquals(0L, StrictMath.ceilMod(Long.MIN_VALUE, -1));
}
+
+ private static void testDivideExactInt() {
+ assertEquals(1, StrictMath.divideExact(7, 7));
+ assertEquals(-1, StrictMath.divideExact(-7, 7));
+ assertEquals(0, StrictMath.divideExact(3, 7));
+ assertEquals(0, StrictMath.divideExact(-3, 7));
+ try {
+ StrictMath.divideExact(Integer.MIN_VALUE, -1);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testDivideExactLong() {
+ assertEquals(1L, StrictMath.divideExact(7L, 7L));
+ assertEquals(-1L, StrictMath.divideExact(-7L, 7L));
+ assertEquals(0, StrictMath.divideExact(3L, 7L));
+ assertEquals(0, StrictMath.divideExact(-3L, 7L));
+ try {
+ StrictMath.divideExact(Long.MIN_VALUE, -1L);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testFloorDivExactInt() {
+ assertEquals(1, StrictMath.floorDivExact(7, 7));
+ assertEquals(-1, StrictMath.floorDivExact(-7, 7));
+ assertEquals(0, StrictMath.floorDivExact(3, 7));
+ assertEquals(-1, StrictMath.floorDivExact(-3, 7));
+ try {
+ StrictMath.floorDivExact(Integer.MIN_VALUE, -1);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testFloorDivExactLong() {
+ assertEquals(1L, StrictMath.floorDivExact(7L, 7L));
+ assertEquals(-1L, StrictMath.floorDivExact(-7L, 7L));
+ assertEquals(0L, StrictMath.floorDivExact(3L, 7L));
+ assertEquals(-1L, StrictMath.floorDivExact(-3L, 7L));
+ try {
+ StrictMath.floorDivExact(Long.MIN_VALUE, -1L);
+ fail("Should have thrown");
+ } catch (ArithmeticException ae) {
+
+ }
+ }
+
+ private static void testUnsignedMultiplyHigh() {
+ assertEquals(
+ 31696182030193L, StrictMath.unsignedMultiplyHigh(8222222222222222L, 71111111111111111L));
+ assertEquals(
+ 71079414929080917L,
+ StrictMath.unsignedMultiplyHigh(-8222222222222222L, 71111111111111111L));
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
index 16df7e5..86995f4 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
@@ -365,4 +365,68 @@
}
return rem;
}
+
+ public static int divideExactInt(int x, int y) {
+ if (x == Integer.MIN_VALUE && y == -1) {
+ throw new ArithmeticException("integer overflow");
+ }
+ return x / y;
+ }
+
+ public static long divideExactLong(long x, long y) {
+ if (x == Long.MIN_VALUE && y == -1) {
+ throw new ArithmeticException("long overflow");
+ }
+ return x / y;
+ }
+
+ public static int floorDivExactInt(int x, int y) {
+ if (x == Integer.MIN_VALUE && y == -1) {
+ throw new ArithmeticException("integer overflow");
+ }
+ // Inlined: return Math.floorDiv(x,y);
+ int div = x / y;
+ int rem = x - y * div;
+ if (rem == 0) {
+ return div;
+ }
+ int signum = 1 | ((x ^ y) >> (Integer.SIZE - 1));
+ return signum < 0 ? div - 1 : div;
+ }
+
+ public static long floorDivExactLong(long x, long y) {
+ if (x == Long.MIN_VALUE && y == -1) {
+ throw new ArithmeticException("long overflow");
+ }
+ // Inlined: return Math.floorDiv(x,y);
+ long div = x / y;
+ long rem = x - y * div;
+ if (rem == 0L) {
+ return div;
+ }
+ long signum = 1L | ((x ^ y) >> (Long.SIZE - 1));
+ return signum < 0L ? div - 1L : div;
+ }
+
+ public static long unsignedMultiplyHigh(long x, long y) {
+ long x1 = x >> 32;
+ long x2 = x & 0xFFFFFFFFL;
+ long y1 = y >> 32;
+ long y2 = y & 0xFFFFFFFFL;
+
+ long z2 = x2 * y2;
+ long t = x1 * y2 + (z2 >>> 32);
+ long z1 = t & 0xFFFFFFFFL;
+ long z0 = t >> 32;
+ z1 += x2 * y1;
+
+ long result = x1 * y1 + z0 + (z1 >> 32);
+ if (x < 0) {
+ result += y;
+ }
+ if (y < 0) {
+ result += x;
+ }
+ return result;
+ }
}