Support Baklava float16 to float conversions
Bug: b/413588305
Change-Id: I7d6299562707af45dcfd8f814ccc0dad99b4f14f
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 3787398..f385e6a 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -811,6 +811,12 @@
Paths.get("third_party", "openjdk", "jdk-11-test").toFile(),
Paths.get("third_party", "openjdk", "jdk-11-test.tar.gz.sha1").toFile(),
)
+ val jdk21Float16Test =
+ ThirdPartyDependency(
+ "float16-test",
+ Paths.get("third_party", "openjdk", "float16-test").toFile(),
+ Paths.get("third_party", "openjdk", "float16-test.tar.gz.sha1").toFile(),
+ )
val junit =
ThirdPartyDependency(
"junit",
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 ec6544c..947d140 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
@@ -1808,6 +1808,22 @@
new MethodWithForwardingGenerator(
method, BackportedMethods::ObjectsMethods_toIdentityString));
+ // short java.lang.Float.floatToFloat16(float)
+ // float java.lang.Float.float16ToFloat(short)
+ type = factory.boxedFloatType;
+ name = factory.createString("floatToFloat16");
+ proto = factory.createProto(factory.shortType, factory.floatType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodWithForwardingGenerator(
+ method, BackportedMethods::FloatMethods_floatToFloat16));
+ name = factory.createString("float16ToFloat");
+ proto = factory.createProto(factory.floatType, factory.shortType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodWithForwardingGenerator(
+ method, BackportedMethods::FloatMethods_float16ToFloat));
+
// android.os.Build
type = factory.androidOsBuildType;
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 1feeccb..15743f4 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
@@ -2861,6 +2861,691 @@
ImmutableList.of());
}
+ public static CfCode FloatMethods_float16ToFloat(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();
+ CfLabel label16 = new CfLabel();
+ CfLabel label17 = new CfLabel();
+ CfLabel label18 = new CfLabel();
+ CfLabel label19 = new CfLabel();
+ CfLabel label20 = new CfLabel();
+ CfLabel label21 = new CfLabel();
+ CfLabel label22 = new CfLabel();
+ CfLabel label23 = new CfLabel();
+ CfLabel label24 = new CfLabel();
+ CfLabel label25 = new CfLabel();
+ CfLabel label26 = new CfLabel();
+ CfLabel label27 = new CfLabel();
+ CfLabel label28 = new CfLabel();
+ CfLabel label29 = new CfLabel();
+ CfLabel label30 = new CfLabel();
+ CfLabel label31 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 18,
+ ImmutableList.of(
+ label0,
+ new CfConstNumber(32768, ValueType.INT),
+ new CfStore(ValueType.INT, 1),
+ label1,
+ new CfConstNumber(10, ValueType.INT),
+ new CfStore(ValueType.INT, 2),
+ label2,
+ new CfConstNumber(31, ValueType.INT),
+ new CfStore(ValueType.INT, 3),
+ label3,
+ new CfConstNumber(1023, ValueType.INT),
+ new CfStore(ValueType.INT, 4),
+ label4,
+ new CfConstNumber(1056964608, ValueType.INT),
+ new CfStore(ValueType.INT, 5),
+ label5,
+ new CfLoad(ValueType.INT, 5),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.floatType, factory.intType),
+ factory.createString("intBitsToFloat")),
+ false),
+ new CfStore(ValueType.FLOAT, 6),
+ label6,
+ new CfConstNumber(4194304, ValueType.INT),
+ new CfStore(ValueType.INT, 7),
+ label7,
+ new CfConstNumber(15, ValueType.INT),
+ new CfStore(ValueType.INT, 8),
+ label8,
+ new CfConstNumber(127, ValueType.INT),
+ new CfStore(ValueType.INT, 9),
+ label9,
+ new CfConstNumber(23, ValueType.INT),
+ new CfStore(ValueType.INT, 10),
+ label10,
+ new CfLoad(ValueType.INT, 0),
+ new CfConstNumber(65535, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 11),
+ label11,
+ new CfLoad(ValueType.INT, 11),
+ new CfLoad(ValueType.INT, 1),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 12),
+ label12,
+ new CfLoad(ValueType.INT, 11),
+ new CfLoad(ValueType.INT, 2),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.INT),
+ new CfLoad(ValueType.INT, 3),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 13),
+ label13,
+ new CfLoad(ValueType.INT, 11),
+ new CfLoad(ValueType.INT, 4),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 14),
+ label14,
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 15),
+ label15,
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 16),
+ label16,
+ new CfLoad(ValueType.INT, 13),
+ new CfIf(IfType.NE, ValueType.INT, label23),
+ label17,
+ new CfLoad(ValueType.INT, 14),
+ new CfIf(IfType.EQ, ValueType.INT, label29),
+ label18,
+ new CfLoad(ValueType.INT, 5),
+ new CfLoad(ValueType.INT, 14),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.floatType, factory.intType),
+ factory.createString("intBitsToFloat")),
+ false),
+ new CfStore(ValueType.FLOAT, 17),
+ label19,
+ new CfLoad(ValueType.FLOAT, 17),
+ new CfLoad(ValueType.FLOAT, 6),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.FLOAT),
+ new CfStore(ValueType.FLOAT, 17),
+ label20,
+ new CfLoad(ValueType.INT, 12),
+ new CfIf(IfType.NE, ValueType.INT, label21),
+ new CfLoad(ValueType.FLOAT, 17),
+ new CfGoto(label22),
+ label21,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType()
+ })),
+ new CfLoad(ValueType.FLOAT, 17),
+ new CfNeg(NumericType.FLOAT),
+ label22,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType()
+ }),
+ new ArrayDeque<>(Arrays.asList(FrameType.floatType()))),
+ new CfReturn(ValueType.FLOAT),
+ label23,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 14),
+ new CfConstNumber(13, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfStore(ValueType.INT, 16),
+ label24,
+ new CfLoad(ValueType.INT, 13),
+ new CfConstNumber(31, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label28),
+ label25,
+ new CfConstNumber(255, ValueType.INT),
+ new CfStore(ValueType.INT, 15),
+ label26,
+ new CfLoad(ValueType.INT, 16),
+ new CfIf(IfType.EQ, ValueType.INT, label29),
+ label27,
+ new CfLoad(ValueType.INT, 16),
+ new CfLoad(ValueType.INT, 7),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfStore(ValueType.INT, 16),
+ new CfGoto(label29),
+ label28,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 13),
+ new CfLoad(ValueType.INT, 8),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfLoad(ValueType.INT, 9),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfStore(ValueType.INT, 15),
+ label29,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
+ new FrameType[] {
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 12),
+ new CfConstNumber(16, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfLoad(ValueType.INT, 15),
+ new CfLoad(ValueType.INT, 10),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfLoad(ValueType.INT, 16),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfStore(ValueType.INT, 17),
+ label30,
+ new CfLoad(ValueType.INT, 17),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.floatType, factory.intType),
+ factory.createString("intBitsToFloat")),
+ false),
+ new CfReturn(ValueType.FLOAT),
+ label31),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode FloatMethods_floatToFloat16(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();
+ CfLabel label16 = new CfLabel();
+ CfLabel label17 = new CfLabel();
+ CfLabel label18 = new CfLabel();
+ CfLabel label19 = new CfLabel();
+ CfLabel label20 = new CfLabel();
+ CfLabel label21 = new CfLabel();
+ CfLabel label22 = new CfLabel();
+ CfLabel label23 = new CfLabel();
+ CfLabel label24 = new CfLabel();
+ CfLabel label25 = new CfLabel();
+ CfLabel label26 = new CfLabel();
+ CfLabel label27 = new CfLabel();
+ CfLabel label28 = new CfLabel();
+ CfLabel label29 = new CfLabel();
+ CfLabel label30 = new CfLabel();
+ CfLabel label31 = new CfLabel();
+ CfLabel label32 = new CfLabel();
+ CfLabel label33 = new CfLabel();
+ CfLabel label34 = new CfLabel();
+ CfLabel label35 = new CfLabel();
+ CfLabel label36 = new CfLabel();
+ CfLabel label37 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 18,
+ ImmutableList.of(
+ label0,
+ new CfConstNumber(10, ValueType.INT),
+ new CfStore(ValueType.INT, 1),
+ label1,
+ new CfConstNumber(15, ValueType.INT),
+ new CfStore(ValueType.INT, 2),
+ label2,
+ new CfConstNumber(15, ValueType.INT),
+ new CfStore(ValueType.INT, 3),
+ label3,
+ new CfConstNumber(127, ValueType.INT),
+ new CfStore(ValueType.INT, 4),
+ label4,
+ new CfConstNumber(23, ValueType.INT),
+ new CfStore(ValueType.INT, 5),
+ label5,
+ new CfConstNumber(31, ValueType.INT),
+ new CfStore(ValueType.INT, 6),
+ label6,
+ new CfConstNumber(255, ValueType.INT),
+ new CfStore(ValueType.INT, 7),
+ label7,
+ new CfConstNumber(8388607, ValueType.INT),
+ new CfStore(ValueType.INT, 8),
+ label8,
+ new CfLoad(ValueType.FLOAT, 0),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.intType, factory.floatType),
+ factory.createString("floatToRawIntBits")),
+ false),
+ new CfStore(ValueType.INT, 9),
+ label9,
+ new CfLoad(ValueType.INT, 9),
+ new CfLoad(ValueType.INT, 6),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.INT),
+ new CfStore(ValueType.INT, 10),
+ label10,
+ new CfLoad(ValueType.INT, 9),
+ new CfLoad(ValueType.INT, 5),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.INT),
+ new CfLoad(ValueType.INT, 7),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 11),
+ label11,
+ new CfLoad(ValueType.INT, 9),
+ new CfLoad(ValueType.INT, 8),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 12),
+ label12,
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 13),
+ label13,
+ new CfConstNumber(0, ValueType.INT),
+ new CfStore(ValueType.INT, 14),
+ label14,
+ new CfLoad(ValueType.INT, 11),
+ new CfConstNumber(255, ValueType.INT),
+ new CfIfCmp(IfType.NE, ValueType.INT, label19),
+ label15,
+ new CfConstNumber(31, ValueType.INT),
+ new CfStore(ValueType.INT, 13),
+ label16,
+ new CfLoad(ValueType.INT, 12),
+ new CfIf(IfType.EQ, ValueType.INT, label17),
+ new CfConstNumber(512, ValueType.INT),
+ new CfGoto(label18),
+ label17,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfConstNumber(0, ValueType.INT),
+ label18,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ }),
+ new ArrayDeque<>(Arrays.asList(FrameType.intType()))),
+ new CfStore(ValueType.INT, 14),
+ new CfGoto(label36),
+ label19,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 11),
+ new CfLoad(ValueType.INT, 4),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfLoad(ValueType.INT, 3),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfStore(ValueType.INT, 11),
+ label20,
+ new CfLoad(ValueType.INT, 11),
+ new CfConstNumber(31, ValueType.INT),
+ new CfIfCmp(IfType.LT, ValueType.INT, label22),
+ label21,
+ new CfConstNumber(31, ValueType.INT),
+ new CfStore(ValueType.INT, 13),
+ new CfGoto(label36),
+ label22,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 11),
+ new CfIf(IfType.GT, ValueType.INT, label32),
+ label23,
+ new CfLoad(ValueType.INT, 11),
+ new CfConstNumber(-10, ValueType.INT),
+ new CfIfCmp(IfType.GE, ValueType.INT, label24),
+ new CfGoto(label36),
+ label24,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 12),
+ new CfConstNumber(8388608, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfStore(ValueType.INT, 12),
+ label25,
+ new CfConstNumber(14, ValueType.INT),
+ new CfLoad(ValueType.INT, 11),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfStore(ValueType.INT, 15),
+ label26,
+ new CfLoad(ValueType.INT, 12),
+ new CfLoad(ValueType.INT, 15),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.INT),
+ new CfStore(ValueType.INT, 14),
+ label27,
+ new CfLoad(ValueType.INT, 12),
+ new CfConstNumber(1, ValueType.INT),
+ new CfLoad(ValueType.INT, 15),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfConstNumber(1, ValueType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfStore(ValueType.INT, 16),
+ label28,
+ new CfConstNumber(1, ValueType.INT),
+ new CfLoad(ValueType.INT, 15),
+ new CfConstNumber(1, ValueType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfStore(ValueType.INT, 17),
+ label29,
+ new CfLoad(ValueType.INT, 16),
+ new CfLoad(ValueType.INT, 14),
+ new CfConstNumber(1, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfLoad(ValueType.INT, 17),
+ new CfIfCmp(IfType.LE, ValueType.INT, label31),
+ label30,
+ new CfIinc(14, 1),
+ label31,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfGoto(label36),
+ label32,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 11),
+ new CfStore(ValueType.INT, 13),
+ label33,
+ new CfLoad(ValueType.INT, 12),
+ new CfConstNumber(13, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.INT),
+ new CfStore(ValueType.INT, 14),
+ label34,
+ new CfLoad(ValueType.INT, 12),
+ new CfConstNumber(8191, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfLoad(ValueType.INT, 14),
+ new CfConstNumber(1, ValueType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.INT),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfConstNumber(4096, ValueType.INT),
+ new CfIfCmp(IfType.LE, ValueType.INT, label36),
+ label35,
+ new CfIinc(14, 1),
+ label36,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+ new FrameType[] {
+ FrameType.floatType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType(),
+ FrameType.intType()
+ })),
+ new CfLoad(ValueType.INT, 10),
+ new CfLoad(ValueType.INT, 2),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfLoad(ValueType.INT, 13),
+ new CfLoad(ValueType.INT, 1),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Shl, NumericType.INT),
+ new CfLoad(ValueType.INT, 14),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.INT),
+ new CfLogicalBinop(CfLogicalBinop.Opcode.Or, NumericType.INT),
+ new CfNumberConversion(NumericType.INT, NumericType.SHORT),
+ new CfReturn(ValueType.INT),
+ label37),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode FloatMethods_isFinite(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
index a452fea..0be353e 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
@@ -9,4 +9,117 @@
public static boolean isFinite(float f) {
return !Float.isInfinite(f) && !Float.isNaN(f);
}
+
+ /*
+ * Source: The Android Open Source Project
+ * License: the Apache License, Version 2.0
+ * Github: https://github.com/caoccao/Javet/blob/main/src/main/java/com/caoccao/javet/utils/Float16.java
+ */
+ public static float float16ToFloat(short float16) {
+ // The float16 format has 1 sign bit, 5 exponent bits, and 10 mantissa bits.
+ // The exponent bias is 15.
+ int signMask = 0x8000;
+ int exponentShift = 10;
+ int shiftedExponentMask = 0x1f;
+ int significandMask = 0x3ff;
+ int fp32DenormalMagic = 126 << 23;
+ float fp32DenormalFloat = Float.intBitsToFloat(fp32DenormalMagic);
+ int fp32QnanMask = 0x400000;
+ int exponentBias = 15;
+ int fp32ExponentBias = 127;
+ int fp32ExponentShift = 23;
+
+ int bits = float16 & 0xffff;
+ int s = bits & signMask;
+ int e = (bits >>> exponentShift) & shiftedExponentMask;
+ int m = (bits) & significandMask;
+ int outE = 0;
+ int outM = 0;
+ if (e == 0) { // Denormal or 0
+ if (m != 0) {
+ // Convert denorm fp16 into normalized fp32
+ float o = Float.intBitsToFloat(fp32DenormalMagic + m);
+ o -= fp32DenormalFloat;
+ return s == 0 ? o : -o;
+ }
+ } else {
+ outM = m << 13;
+ if (e == 0x1f) { // Infinite or NaN
+ outE = 0xff;
+ if (outM != 0) { // SNaNs are quieted
+ outM |= fp32QnanMask;
+ }
+ } else {
+ outE = e - exponentBias + fp32ExponentBias;
+ }
+ }
+ int out = (s << 16) | (outE << fp32ExponentShift) | outM;
+ return Float.intBitsToFloat(out);
+ }
+
+ /*
+ * Source: The Android Open Source Project
+ * License: the Apache License, Version 2.0
+ * Github: https://github.com/caoccao/Javet/blob/main/src/main/java/com/caoccao/javet/utils/Float16.java
+ */
+ public static short floatToFloat16(float flt) {
+ // The float16 format has 1 sign bit, 5 exponent bits, and 10 mantissa bits.
+ // The exponent bias is 15.
+ int exponentShift = 10;
+ int signShift = 15;
+ int exponentBias = 15;
+ int fp32ExponentBias = 127;
+ int fp32ExponentShift = 23;
+ int fp32SignShift = 31;
+ int fp32ShiftedExponentMask = 0xff;
+ int fp32SignificandMask = 0x7fffff;
+
+ int bits = Float.floatToRawIntBits(flt);
+ int s = (bits >>> fp32SignShift);
+ int e = (bits >>> fp32ExponentShift) & fp32ShiftedExponentMask;
+ int m = (bits) & fp32SignificandMask;
+ int outE = 0;
+ int outM = 0;
+ if (e == 0xff) { // Infinite or NaN
+ outE = 0x1f;
+ outM = m != 0 ? 0x200 : 0;
+ } else {
+ e = e - fp32ExponentBias + exponentBias;
+ if (e >= 0x1f) { // Overflow
+ outE = 0x1f;
+ } else if (e <= 0) { // Underflow
+ if (e < -10) {
+ // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
+ } else {
+ // The fp32 value is a normalized float less than MIN_NORMAL,
+ // we convert to a denorm fp16
+ m = m | 0x800000;
+ int shift = 14 - e;
+ outM = m >> shift;
+ int lowm = m & ((1 << shift) - 1);
+ int hway = 1 << (shift - 1);
+ // if above halfway or exactly halfway and outM is odd
+ if (lowm + (outM & 1) > hway) {
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ } else {
+ outE = e;
+ outM = m >> 13;
+ // if above halfway or exactly halfway and outM is odd
+ if ((m & 0x1fff) + (outM & 0x1) > 0x1000) {
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ }
+ // The outM is added here as the +1 increments for outM above can
+ // cause an overflow in the exponent bit which is OK.
+ return (short) ((s << signShift) | (outE << exponentShift) + outM);
+ }
}
diff --git a/src/test/java21/com/android/tools/r8/jdk21/backport/Jdk21Float16Test.java b/src/test/java21/com/android/tools/r8/jdk21/backport/Jdk21Float16Test.java
new file mode 100644
index 0000000..23b00dd
--- /dev/null
+++ b/src/test/java21/com/android/tools/r8/jdk21/backport/Jdk21Float16Test.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2025, 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.jdk21.backport;
+
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Jdk21Float16Test extends TestBase {
+
+ private static final String FLOAT_16_TEST_NAME = "Binary16Conversion";
+ private static final String FLOAT_16_NAN_TEST_NAME = "Binary16ConversionNaN";
+
+ private static Path getTestPath(String name) {
+ return Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "float16-test", name + JAVA_EXTENSION);
+ }
+
+ private static final Path[] JDK_21_FLOAT_16_TEST_JAVA_FILES =
+ new Path[] {getTestPath(FLOAT_16_TEST_NAME), getTestPath(FLOAT_16_NAN_TEST_NAME)};
+
+ private static Path[] JDK_21_FLOAT_16_TEST_CLASS_FILES;
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().withCfRuntime(CfVm.JDK21).build();
+ }
+
+ @BeforeClass
+ public static void compileTestClasses() throws Exception {
+ // Build test constants.
+ Path output = getStaticTemp().newFolder("output").toPath();
+ javac(TestRuntime.getCheckedInJdk21(), getStaticTemp())
+ .addSourceFiles(JDK_21_FLOAT_16_TEST_JAVA_FILES)
+ .setOutputPath(output)
+ .compile();
+ JDK_21_FLOAT_16_TEST_CLASS_FILES =
+ new Path[] {
+ output.resolve(FLOAT_16_TEST_NAME + CLASS_EXTENSION),
+ output.resolve(FLOAT_16_TEST_NAME + "$Binary16" + CLASS_EXTENSION),
+ output.resolve(FLOAT_16_NAN_TEST_NAME + CLASS_EXTENSION)
+ };
+ }
+
+ @Test
+ public void testFloat16() throws Exception {
+ testForD8(parameters)
+ .addProgramFiles(JDK_21_FLOAT_16_TEST_CLASS_FILES)
+ .run(parameters.getRuntime(), FLOAT_16_TEST_NAME)
+ .assertSuccessWithOutput("");
+ }
+
+ @Test
+ public void testFloat16NaN() throws Exception {
+ Assume.assumeTrue("The test fails also on jdk21", false);
+ testForD8(parameters)
+ .addProgramFiles(JDK_21_FLOAT_16_TEST_CLASS_FILES)
+ .run(parameters.getRuntime(), FLOAT_16_NAN_TEST_NAME)
+ .assertSuccessWithOutput("");
+ }
+}
diff --git a/third_party/openjdk/float16-test.tar.gz.sha1 b/third_party/openjdk/float16-test.tar.gz.sha1
new file mode 100644
index 0000000..ded34fa
--- /dev/null
+++ b/third_party/openjdk/float16-test.tar.gz.sha1
@@ -0,0 +1 @@
+166f74a089e05b71c4b7d8da71b3f2c1e25cda59
\ No newline at end of file