Add support for float-to-double & double-to-float in optimizing.

Change-Id: I41b0fee5a28c83757697c8d000b7e224cf5a4534
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 0ac93a2..252e4fa 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1119,6 +1119,16 @@
       break;
     }
 
+    case Instruction::FLOAT_TO_DOUBLE: {
+      Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimDouble, dex_pc);
+      break;
+    }
+
+    case Instruction::DOUBLE_TO_FLOAT: {
+      Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimFloat, dex_pc);
+      break;
+    }
+
     case Instruction::INT_TO_BYTE: {
       Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte, dex_pc);
       break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index f050605..5076c85 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1501,8 +1501,9 @@
           break;
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1532,8 +1533,9 @@
           break;
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1728,8 +1730,9 @@
         }
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          __ vcvtsd(out.AsFpuRegister<SRegister>(),
+                    FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
           break;
 
         default:
@@ -1784,8 +1787,9 @@
         }
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+                    in.AsFpuRegister<SRegister>());
           break;
 
         default:
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 38dc8c5..2aa121d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1464,8 +1464,9 @@
           break;
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1494,8 +1495,9 @@
           break;
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1715,8 +1717,8 @@
         }
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
 
         default:
@@ -1762,8 +1764,8 @@
         }
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
 
         default:
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 7eecac1..5761fb1 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1445,8 +1445,9 @@
           break;
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1473,8 +1474,9 @@
           break;
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          locations->SetInAt(0, Location::RequiresFpuRegister());
+          locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
           break;
 
         default:
@@ -1686,8 +1688,8 @@
           break;
 
         case Primitive::kPrimDouble:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `double-to-float' instruction.
+          __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
 
         default:
@@ -1712,8 +1714,8 @@
           break;
 
         case Primitive::kPrimFloat:
-          LOG(FATAL) << "Type conversion from " << input_type
-                     << " to " << result_type << " not yet implemented";
+          // Processing a Dex `float-to-double' instruction.
+          __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
           break;
 
         default:
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 05cdf42..91618fc 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -62,6 +62,18 @@
     }
   }
 
+  public static void assertFloatIsNaN(float result) {
+    if (!Float.isNaN(result)) {
+      throw new Error("Expected: NaN, found: " + result);
+    }
+  }
+
+  public static void assertDoubleIsNaN(double result) {
+    if (!Double.isNaN(result)) {
+      throw new Error("Expected: NaN, found: " + result);
+    }
+  }
+
 
   public static void main(String[] args) {
     // Generate, compile and check int-to-long Dex instructions.
@@ -97,6 +109,12 @@
     // Generate, compile and check float-to-long Dex instructions.
     floatToLong();
 
+    // Generate, compile and check float-to-double Dex instructions.
+    floatToDouble();
+
+    // Generate, compile and check double-to-float Dex instructions.
+    doubleToFloat();
+
     // Generate, compile and check int-to-byte Dex instructions.
     shortToByte();
     intToByte();
@@ -371,6 +389,58 @@
     assertLongEquals(-9223372036854775808L, $opt$FloatToLong(Float.NEGATIVE_INFINITY));
   }
 
+  private static void floatToDouble() {
+    assertDoubleEquals(1D, $opt$FloatToDouble(1F));
+    assertDoubleEquals(0D, $opt$FloatToDouble(0F));
+    assertDoubleEquals(0D, $opt$FloatToDouble(-0F));
+    assertDoubleEquals(-1D, $opt$FloatToDouble(-1F));
+    assertDoubleEquals(51D, $opt$FloatToDouble(51F));
+    assertDoubleEquals(-51D, $opt$FloatToDouble(-51F));
+    assertDoubleEquals(0.5D, $opt$FloatToDouble(0.5F));
+    assertDoubleEquals(0.49999991059303284D, $opt$FloatToDouble(0.4999999F));
+    assertDoubleEquals(-0.49999991059303284D, $opt$FloatToDouble(-0.4999999F));
+    assertDoubleEquals(-0.5D, $opt$FloatToDouble(-0.5F));
+    assertDoubleEquals(42.19900131225586D, $opt$FloatToDouble(42.199F));
+    assertDoubleEquals(-42.19900131225586D, $opt$FloatToDouble(-42.199F));
+    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483647F));  // 2^31 - 1
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483647F));  // -(2^31 - 1)
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483648F));  // -(2^31)
+    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483648F));  // (2^31)
+    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483649F));  // -(2^31 + 1)
+    assertDoubleEquals(9223372036854775807D, $opt$FloatToDouble(9223372036854775807F));  // 2^63 - 1
+    assertDoubleEquals(-9223372036854775807D, $opt$FloatToDouble(-9223372036854775807F));  // -(2^63 - 1)
+    assertDoubleEquals(-9223372036854775808D, $opt$FloatToDouble(-9223372036854775808F));  // -(2^63)
+    assertDoubleIsNaN($opt$FloatToDouble(Float.NaN));
+    assertDoubleEquals(Double.POSITIVE_INFINITY, $opt$FloatToDouble(Float.POSITIVE_INFINITY));
+    assertDoubleEquals(Double.NEGATIVE_INFINITY, $opt$FloatToDouble(Float.NEGATIVE_INFINITY));
+  }
+
+  private static void doubleToFloat() {
+    assertFloatEquals(1F, $opt$DoubleToFloat(1D));
+    assertFloatEquals(0F, $opt$DoubleToFloat(0D));
+    assertFloatEquals(0F, $opt$DoubleToFloat(-0D));
+    assertFloatEquals(-1F, $opt$DoubleToFloat(-1D));
+    assertFloatEquals(51F, $opt$DoubleToFloat(51D));
+    assertFloatEquals(-51F, $opt$DoubleToFloat(-51D));
+    assertFloatEquals(0.5F, $opt$DoubleToFloat(0.5D));
+    assertFloatEquals(0.4999999F, $opt$DoubleToFloat(0.4999999D));
+    assertFloatEquals(-0.4999999F, $opt$DoubleToFloat(-0.4999999D));
+    assertFloatEquals(-0.5F, $opt$DoubleToFloat(-0.5D));
+    assertFloatEquals(42.199F, $opt$DoubleToFloat(42.199D));
+    assertFloatEquals(-42.199F, $opt$DoubleToFloat(-42.199D));
+    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483647D));  // 2^31 - 1
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483647D));  // -(2^31 - 1)
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483648D));  // -(2^31)
+    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483648D));  // (2^31)
+    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483649D));  // -(2^31 + 1)
+    assertFloatEquals(9223372036854775807F, $opt$DoubleToFloat(9223372036854775807D));  // 2^63 - 1
+    assertFloatEquals(-9223372036854775807F, $opt$DoubleToFloat(-9223372036854775807D));  // -(2^63 - 1)
+    assertFloatEquals(-9223372036854775808F, $opt$DoubleToFloat(-9223372036854775808D));  // -(2^63)
+    assertFloatIsNaN($opt$DoubleToFloat(Float.NaN));
+    assertFloatEquals(Float.POSITIVE_INFINITY, $opt$DoubleToFloat(Double.POSITIVE_INFINITY));
+    assertFloatEquals(Float.NEGATIVE_INFINITY, $opt$DoubleToFloat(Double.NEGATIVE_INFINITY));
+  }
+
   private static void shortToByte() {
     assertByteEquals((byte)1, $opt$ShortToByte((short)1));
     assertByteEquals((byte)0, $opt$ShortToByte((short)0));
@@ -499,51 +569,57 @@
 
 
   // These methods produce int-to-long Dex instructions.
-  static long $opt$ByteToLong(byte a) { return a; }
-  static long $opt$ShortToLong(short a) { return a; }
-  static long $opt$IntToLong(int a) { return a; }
-  static long $opt$CharToLong(int a) { return a; }
+  static long $opt$ByteToLong(byte a) { return (long)a; }
+  static long $opt$ShortToLong(short a) { return (long)a; }
+  static long $opt$IntToLong(int a) { return (long)a; }
+  static long $opt$CharToLong(int a) { return (long)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; }
+  static float $opt$ByteToFloat(byte a) { return (float)a; }
+  static float $opt$ShortToFloat(short a) { return (float)a; }
+  static float $opt$IntToFloat(int a) { return (float)a; }
+  static float $opt$CharToFloat(char a) { return (float)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; }
+  static double $opt$ByteToDouble(byte a) { return (double)a; }
+  static double $opt$ShortToDouble(short a) { return (double)a; }
+  static double $opt$IntToDouble(int a) { return (double)a; }
+  static double $opt$CharToDouble(int a) { return (double)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; }
+  static int $opt$LongToInt(long a) { return (int)a; }
+  static int $opt$LongLiteralToInt() { return (int)42L; }
 
   // This method produces a long-to-float Dex instruction.
-  static float $opt$LongToFloat(long a){ return (float)a; }
+  static float $opt$LongToFloat(long a) { return (float)a; }
 
   // This method produces a long-to-double Dex instruction.
-  static double $opt$LongToDouble(long a){ return (double)a; }
+  static double $opt$LongToDouble(long a) { return (double)a; }
 
   // This method produces a float-to-int Dex instruction.
-  static int $opt$FloatToInt(float a){ return (int)a; }
+  static int $opt$FloatToInt(float a) { return (int)a; }
+
+  // This method produces a float-to-double Dex instruction.
+  static double $opt$FloatToDouble(float a) { return (double)a; }
+
+  // This method produces a double-to-float Dex instruction.
+  static float $opt$DoubleToFloat(double a) { return (float)a; }
 
   // This method produces a float-to-long Dex instruction.
   static long $opt$FloatToLong(float a){ return (long)a; }
 
   // These methods produce int-to-byte Dex instructions.
-  static byte $opt$ShortToByte(short a){ return (byte)a; }
-  static byte $opt$IntToByte(int a){ return (byte)a; }
-  static byte $opt$CharToByte(char a){ return (byte)a; }
+  static byte $opt$ShortToByte(short a) { return (byte)a; }
+  static byte $opt$IntToByte(int a) { return (byte)a; }
+  static byte $opt$CharToByte(char a) { return (byte)a; }
 
   // These methods produce int-to-short Dex instructions.
-  static short $opt$ByteToShort(byte a){ return (short)a; }
-  static short $opt$IntToShort(int a){ return (short)a; }
-  static short $opt$CharToShort(char a){ return (short)a; }
+  static short $opt$ByteToShort(byte a) { return (short)a; }
+  static short $opt$IntToShort(int a) { return (short)a; }
+  static short $opt$CharToShort(char a) { return (short)a; }
 
   // These methods produce int-to-char Dex instructions.
-  static char $opt$ByteToChar(byte a){ return (char)a; }
-  static char $opt$ShortToChar(short a){ return (char)a; }
-  static char $opt$IntToChar(int a){ return (char)a; }
+  static char $opt$ByteToChar(byte a) { return (char)a; }
+  static char $opt$ShortToChar(short a) { return (char)a; }
+  static char $opt$IntToChar(int a) { return (char)a; }
 }