Add support for int-to-float & int-to-double in optimizing.
- Add support for the int-to-float and int-to-double Dex
instructions in the optimizing compiler.
- Generate x86, x86-64 and ARM (but not ARM64) code for
byte to float, short to float, int to float, char to
float, byte to double, short to double, int to double and
char to double HTypeConversion nodes.
- Add related tests to test/422-type-conversion.
Change-Id: I963f9d0184a5d3721af2d8f593f133d5af7aa6a3
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 7ead607..be8631a 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1002,6 +1002,16 @@
break;
}
+ case Instruction::INT_TO_FLOAT: {
+ Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimFloat);
+ break;
+ }
+
+ case Instruction::INT_TO_DOUBLE: {
+ Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimDouble);
+ break;
+ }
+
case Instruction::LONG_TO_INT: {
Conversion_12x(instruction, Primitive::kPrimLong, Primitive::kPrimInt);
break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 746d4af..1debaa5 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1444,9 +1444,49 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-float' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-double' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
break;
default:
@@ -1566,9 +1606,52 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar: {
+ // Processing a Dex `int-to-float' instruction.
+ __ vmovsr(out.As<SRegister>(), in.As<Register>());
+ __ vcvtsi(out.As<SRegister>(), out.As<SRegister>());
+ break;
+ }
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar: {
+ // Processing a Dex `int-to-double' instruction.
+ __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.As<Register>());
+ __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+ out.AsFpuRegisterPairLow<SRegister>());
+ break;
+ }
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
break;
default:
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 5fbcf96..36fe063 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1392,9 +1392,49 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-float' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-double' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
break;
default:
@@ -1534,9 +1574,47 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ // Processing a Dex `int-to-float' instruction.
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ __ cvtsi2ss(out.As<XmmRegister>(), in.As<Register>());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ // Processing a Dex `int-to-double' instruction.
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ __ cvtsi2sd(out.As<XmmRegister>(), in.As<Register>());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
break;
default:
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 47fb74f..29479a2 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1393,9 +1393,49 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-float' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ // Processing a Dex `int-to-double' instruction.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
break;
default:
@@ -1538,9 +1578,47 @@
break;
case Primitive::kPrimFloat:
+ switch (input_type) {
+ // Processing a Dex `int-to-float' instruction.
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ __ cvtsi2ss(out.As<XmmRegister>(), in.As<CpuRegister>());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ switch (input_type) {
+ // Processing a Dex `int-to-double' instruction.
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ __ cvtsi2sd(out.As<XmmRegister>(), in.As<CpuRegister>());
+ break;
+
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ };
break;
default:
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 0bf9585..37bc777 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -50,6 +50,19 @@
}
}
+ public static void assertFloatEquals(float expected, float result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertDoubleEquals(double expected, double result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+
public static void main(String[] args) {
// Generate, compile and check int-to-long Dex instructions.
byteToLong();
@@ -57,6 +70,18 @@
intToLong();
charToLong();
+ // Generate, compile and check int-to-float Dex instructions.
+ byteToFloat();
+ shortToFloat();
+ intToFloat();
+ charToFloat();
+
+ // Generate, compile and check int-to-double Dex instructions.
+ byteToDouble();
+ shortToDouble();
+ intToDouble();
+ charToDouble();
+
// Generate, compile and check long-to-int Dex instructions.
longToInt();
@@ -121,6 +146,100 @@
assertLongEquals(32768L, $opt$CharToLong((char)-32768)); // -(2^15)
}
+ private static void byteToFloat() {
+ assertFloatEquals(1F, $opt$ByteToFloat((byte)1));
+ assertFloatEquals(0F, $opt$ByteToFloat((byte)0));
+ assertFloatEquals(-1F, $opt$ByteToFloat((byte)-1));
+ assertFloatEquals(51F, $opt$ByteToFloat((byte)51));
+ assertFloatEquals(-51F, $opt$ByteToFloat((byte)-51));
+ assertFloatEquals(127F, $opt$ByteToFloat((byte)127)); // 2^7 - 1
+ assertFloatEquals(-127F, $opt$ByteToFloat((byte)-127)); // -(2^7 - 1)
+ assertFloatEquals(-128F, $opt$ByteToFloat((byte)-128)); // -(2^7)
+ }
+
+ private static void shortToFloat() {
+ assertFloatEquals(1F, $opt$ShortToFloat((short)1));
+ assertFloatEquals(0F, $opt$ShortToFloat((short)0));
+ assertFloatEquals(-1F, $opt$ShortToFloat((short)-1));
+ assertFloatEquals(51F, $opt$ShortToFloat((short)51));
+ assertFloatEquals(-51F, $opt$ShortToFloat((short)-51));
+ assertFloatEquals(32767F, $opt$ShortToFloat((short)32767)); // 2^15 - 1
+ assertFloatEquals(-32767F, $opt$ShortToFloat((short)-32767)); // -(2^15 - 1)
+ assertFloatEquals(-32768F, $opt$ShortToFloat((short)-32768)); // -(2^15)
+ }
+
+ private static void intToFloat() {
+ assertFloatEquals(1F, $opt$IntToFloat(1));
+ assertFloatEquals(0F, $opt$IntToFloat(0));
+ assertFloatEquals(-1F, $opt$IntToFloat(-1));
+ assertFloatEquals(51F, $opt$IntToFloat(51));
+ assertFloatEquals(-51F, $opt$IntToFloat(-51));
+ assertFloatEquals(16777215F, $opt$IntToFloat(16777215)); // 2^24 - 1
+ assertFloatEquals(-16777215F, $opt$IntToFloat(-16777215)); // -(2^24 - 1)
+ assertFloatEquals(16777216F, $opt$IntToFloat(16777216)); // 2^24
+ assertFloatEquals(-16777216F, $opt$IntToFloat(-16777216)); // -(2^24)
+ assertFloatEquals(2147483647F, $opt$IntToFloat(2147483647)); // 2^31 - 1
+ assertFloatEquals(-2147483648F, $opt$IntToFloat(-2147483648)); // -(2^31)
+ }
+
+ private static void charToFloat() {
+ assertFloatEquals(1F, $opt$CharToFloat((char)1));
+ assertFloatEquals(0F, $opt$CharToFloat((char)0));
+ assertFloatEquals(51F, $opt$CharToFloat((char)51));
+ assertFloatEquals(32767F, $opt$CharToFloat((char)32767)); // 2^15 - 1
+ assertFloatEquals(65535F, $opt$CharToFloat((char)65535)); // 2^16 - 1
+ assertFloatEquals(65535F, $opt$CharToFloat((char)-1));
+ assertFloatEquals(65485F, $opt$CharToFloat((char)-51));
+ assertFloatEquals(32769F, $opt$CharToFloat((char)-32767)); // -(2^15 - 1)
+ assertFloatEquals(32768F, $opt$CharToFloat((char)-32768)); // -(2^15)
+ }
+
+ private static void byteToDouble() {
+ assertDoubleEquals(1D, $opt$ByteToDouble((byte)1));
+ assertDoubleEquals(0D, $opt$ByteToDouble((byte)0));
+ assertDoubleEquals(-1D, $opt$ByteToDouble((byte)-1));
+ assertDoubleEquals(51D, $opt$ByteToDouble((byte)51));
+ assertDoubleEquals(-51D, $opt$ByteToDouble((byte)-51));
+ assertDoubleEquals(127D, $opt$ByteToDouble((byte)127)); // 2^7 - 1
+ assertDoubleEquals(-127D, $opt$ByteToDouble((byte)-127)); // -(2^7 - 1)
+ assertDoubleEquals(-128D, $opt$ByteToDouble((byte)-128)); // -(2^7)
+ }
+
+ private static void shortToDouble() {
+ assertDoubleEquals(1D, $opt$ShortToDouble((short)1));
+ assertDoubleEquals(0D, $opt$ShortToDouble((short)0));
+ assertDoubleEquals(-1D, $opt$ShortToDouble((short)-1));
+ assertDoubleEquals(51D, $opt$ShortToDouble((short)51));
+ assertDoubleEquals(-51D, $opt$ShortToDouble((short)-51));
+ assertDoubleEquals(32767D, $opt$ShortToDouble((short)32767)); // 2^15 - 1
+ assertDoubleEquals(-32767D, $opt$ShortToDouble((short)-32767)); // -(2^15 - 1)
+ assertDoubleEquals(-32768D, $opt$ShortToDouble((short)-32768)); // -(2^15)
+ }
+
+ private static void intToDouble() {
+ assertDoubleEquals(1D, $opt$IntToDouble(1));
+ assertDoubleEquals(0D, $opt$IntToDouble(0));
+ assertDoubleEquals(-1D, $opt$IntToDouble(-1));
+ assertDoubleEquals(51D, $opt$IntToDouble(51));
+ assertDoubleEquals(-51D, $opt$IntToDouble(-51));
+ assertDoubleEquals(16777216D, $opt$IntToDouble(16777216)); // 2^24
+ assertDoubleEquals(-16777216D, $opt$IntToDouble(-16777216)); // -(2^24)
+ assertDoubleEquals(2147483647D, $opt$IntToDouble(2147483647)); // 2^31 - 1
+ assertDoubleEquals(-2147483648D, $opt$IntToDouble(-2147483648)); // -(2^31)
+ }
+
+ private static void charToDouble() {
+ assertDoubleEquals(1D, $opt$CharToDouble((char)1));
+ assertDoubleEquals(0D, $opt$CharToDouble((char)0));
+ assertDoubleEquals(51D, $opt$CharToDouble((char)51));
+ assertDoubleEquals(32767D, $opt$CharToDouble((char)32767)); // 2^15 - 1
+ assertDoubleEquals(65535D, $opt$CharToDouble((char)65535)); // 2^16 - 1
+ assertDoubleEquals(65535D, $opt$CharToDouble((char)-1));
+ assertDoubleEquals(65485D, $opt$CharToDouble((char)-51));
+ assertDoubleEquals(32769D, $opt$CharToDouble((char)-32767)); // -(2^15 - 1)
+ assertDoubleEquals(32768D, $opt$CharToDouble((char)-32768)); // -(2^15)
+ }
+
private static void longToInt() {
assertIntEquals(1, $opt$LongToInt(1L));
assertIntEquals(0, $opt$LongToInt(0L));
@@ -281,6 +400,18 @@
static long $opt$IntToLong(int a) { return a; }
static long $opt$CharToLong(int a) { return a; }
+ // These methods produce int-to-float Dex instructions.
+ static float $opt$ByteToFloat(byte a) { return a; }
+ static float $opt$ShortToFloat(short a) { return a; }
+ static float $opt$IntToFloat(int a) { return a; }
+ static float $opt$CharToFloat(char a) { return a; }
+
+ // These methods produce int-to-double Dex instructions.
+ static double $opt$ByteToDouble(byte a) { return a; }
+ static double $opt$ShortToDouble(short a) { return a; }
+ static double $opt$IntToDouble(int a) { return a; }
+ static double $opt$CharToDouble(int a) { return a; }
+
// These methods produce long-to-int Dex instructions.
static int $opt$LongToInt(long a){ return (int)a; }
static int $opt$LongLiteralToInt(){ return (int)42L; }