[optimizing compiler] Add REM_FLOAT and REM_DOUBLE

- for arm, x86, x86_64 backends
- reinstated fmod quick entry points for x86. This is a partial revert
of bd3682eada753de52975ae2b4a712bd87dc139a6 which added inline assembly
for floting point rem on x86. Note that Quick still uses the inline
version.
- fix rem tests for longs

Change-Id: I73be19a9f2f2bcf3f718d9ca636e67bdd72b5440
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 39a9766..233f4a4 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -43,8 +43,9 @@
 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
 static constexpr size_t kRuntimeParameterCoreRegistersLength =
     arraysize(kRuntimeParameterCoreRegisters);
-static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { };
-static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
+static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
+static constexpr size_t kRuntimeParameterFpuRegistersLength =
+    arraysize(kRuntimeParameterFpuRegisters);
 
 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
  public:
@@ -1999,16 +2000,16 @@
   // 0x80000000(00000000)/-1 triggers an arithmetic exception!
   // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000)
   // so it's safe to just use negl instead of more complex comparisons.
-
-  __ cmpl(second_reg, Immediate(-1));
-  __ j(kEqual, slow_path->GetEntryLabel());
-
   if (type == Primitive::kPrimInt) {
+    __ cmpl(second_reg, Immediate(-1));
+    __ j(kEqual, slow_path->GetEntryLabel());
     // edx:eax <- sign-extended of eax
     __ cdq();
     // eax = quotient, edx = remainder
     __ idivl(second_reg);
   } else {
+    __ cmpq(second_reg, Immediate(-1));
+    __ j(kEqual, slow_path->GetEntryLabel());
     // rdx:rax <- sign-extended of rax
     __ cqo();
     // rax = quotient, rdx = remainder
@@ -2075,9 +2076,14 @@
 }
 
 void LocationsBuilderX86_64::VisitRem(HRem* rem) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
-  switch (rem->GetResultType()) {
+  Primitive::Type type = rem->GetResultType();
+  LocationSummary::CallKind call_kind =
+      (type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)
+      ? LocationSummary::kNoCall
+      : LocationSummary::kCall;
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
+
+  switch (type) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RegisterLocation(RAX));
@@ -2089,12 +2095,16 @@
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
-      LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+      InvokeRuntimeCallingConvention calling_convention;
+      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+      // The runtime helper puts the result in XMM0.
+      locations->SetOut(Location::FpuRegisterLocation(XMM0));
       break;
     }
 
     default:
-      LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
+      LOG(FATAL) << "Unexpected rem type " << type;
   }
 }
 
@@ -2106,13 +2116,16 @@
       GenerateDivRemIntegral(rem);
       break;
     }
-
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble: {
-      LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pFmodf), true));
+      codegen_->RecordPcInfo(rem, rem->GetDexPc());
       break;
     }
-
+    case Primitive::kPrimDouble: {
+      __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pFmod), true));
+      codegen_->RecordPcInfo(rem, rem->GetDexPc());
+      break;
+    }
     default:
       LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
   }