Delegate long-to-float type conversions to the runtime on ARM.

On ARM, translate long-to-float type conversions (from both
Quick and Optimizing) as calls to the runtime routine
art_l2f, instead of generating ad hoc code, so as to improve
the precision of the conversions.

Bug: 20413424
Change-Id: I8c414ee1c6f4ff1f32ee78f75734cfd3cf579f71
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 987a6c4..1c68654 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1456,11 +1456,12 @@
   Primitive::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
 
-  // The float-to-long and double-to-long type conversions rely on a
-  // call to the runtime.
+  // The float-to-long, double-to-long and long-to-float type conversions
+  // rely on a call to the runtime.
   LocationSummary::CallKind call_kind =
-      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
-       && result_type == Primitive::kPrimLong)
+      (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+        && result_type == Primitive::kPrimLong)
+       || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
       ? LocationSummary::kCall
       : LocationSummary::kNoCall;
   LocationSummary* locations =
@@ -1603,15 +1604,14 @@
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case Primitive::kPrimLong: {
           // Processing a Dex `long-to-float' instruction.
-          locations->SetInAt(0, Location::RequiresRegister());
-          locations->SetOut(Location::RequiresFpuRegister());
-          locations->AddTemp(Location::RequiresRegister());
-          locations->AddTemp(Location::RequiresRegister());
-          locations->AddTemp(Location::RequiresFpuRegister());
-          locations->AddTemp(Location::RequiresFpuRegister());
+          InvokeRuntimeCallingConvention calling_convention;
+          locations->SetInAt(0, Location::RegisterPairLocation(
+              calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+          locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
           break;
+        }
 
         case Primitive::kPrimDouble:
           // Processing a Dex `double-to-float' instruction.
@@ -1820,47 +1820,13 @@
           break;
         }
 
-        case Primitive::kPrimLong: {
+        case Primitive::kPrimLong:
           // Processing a Dex `long-to-float' instruction.
-          Register low = in.AsRegisterPairLow<Register>();
-          Register high = in.AsRegisterPairHigh<Register>();
-          SRegister output = out.AsFpuRegister<SRegister>();
-          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
-          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
-          SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
-          DRegister temp1_d = FromLowSToD(temp1_s);
-          SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
-          DRegister temp2_d = FromLowSToD(temp2_s);
-
-          // Operations use doubles for precision reasons (each 32-bit
-          // half of a long fits in the 53-bit mantissa of a double,
-          // but not in the 24-bit mantissa of a float).  This is
-          // especially important for the low bits.  The result is
-          // eventually converted to float.
-
-          // temp1_d = int-to-double(high)
-          __ vmovsr(temp1_s, high);
-          __ vcvtdi(temp1_d, temp1_s);
-          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
-          // as an immediate value into `temp2_d` does not work, as
-          // this instruction only transfers 8 significant bits of its
-          // immediate operand.  Instead, use two 32-bit core
-          // registers to load `k2Pow32EncodingForDouble` into
-          // `temp2_d`.
-          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
-          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
-          __ vmovdrr(temp2_d, constant_low, constant_high);
-          // temp1_d = temp1_d * 2^32
-          __ vmuld(temp1_d, temp1_d, temp2_d);
-          // temp2_d = unsigned-to-double(low)
-          __ vmovsr(temp2_s, low);
-          __ vcvtdu(temp2_d, temp2_s);
-          // temp1_d = temp1_d + temp2_d
-          __ vaddd(temp1_d, temp1_d, temp2_d);
-          // output = double-to-float(temp1_d);
-          __ vcvtsd(output, temp1_d);
+          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
+                                  conversion,
+                                  conversion->GetDexPc(),
+                                  nullptr);
           break;
-        }
 
         case Primitive::kPrimDouble:
           // Processing a Dex `double-to-float' instruction.