Mips portable floating point support

Fleshing out the portable floating point.

Change-Id: Ie7a6dcb168a4eb2a61a52e6d747da4118d54f3aa
diff --git a/src/compiler/codegen/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/FP/MipsFP.cc
index 6a51f69..64061fe 100644
--- a/src/compiler/codegen/mips/FP/MipsFP.cc
+++ b/src/compiler/codegen/mips/FP/MipsFP.cc
@@ -61,8 +61,7 @@
 
     return false;
 #else
-    UNIMPLEMENTED(WARNING) << "Need Mips soft float implementation";
-    return false;
+    return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
 #endif
 }
 
@@ -112,8 +111,7 @@
     storeValueWide(cUnit, rlDest, rlResult);
     return false;
 #else
-    UNIMPLEMENTED(WARNING) << "Need Mips soft float implementation";
-    return false;
+    return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
 #endif
 }
 
@@ -181,49 +179,48 @@
     }
     return false;
 #else
-    UNIMPLEMENTED(WARNING) << "Need Mips soft float implementation";
-    return false;
+    return genConversionPortable(cUnit, mir);
 #endif
 }
 
 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
                      RegLocation rlSrc1, RegLocation rlSrc2)
 {
-    UNIMPLEMENTED(WARNING) << "Need Mips implementation";
-    return false;
-#if 0
-    TemplateOpcode templateOpcode;
-    RegLocation rlResult = oatGetReturn(cUnit);
     bool wide = true;
+    int offset;
 
     switch(mir->dalvikInsn.opcode) {
         case OP_CMPL_FLOAT:
-            templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
+            offset = OFFSETOF_MEMBER(Thread, pCmplFloat);
             wide = false;
             break;
         case OP_CMPG_FLOAT:
-            templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
+            offset = OFFSETOF_MEMBER(Thread, pCmpgFloat);
             wide = false;
             break;
         case OP_CMPL_DOUBLE:
-            templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
+            offset = OFFSETOF_MEMBER(Thread, pCmplDouble);
             break;
         case OP_CMPG_DOUBLE:
-            templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
+            offset = OFFSETOF_MEMBER(Thread, pCmpgDouble);
             break;
         default:
             return true;
     }
-    loadValueAddress(cUnit, rlSrc1, r_A0);
-    oatClobber(cUnit, r_A0);
-    loadValueAddress(cUnit, rlSrc2, r_A1);
-    UNIMPLEMENTED(FATAL) << "Need callout to handler";
-#if 0
-    genDispatchToHandler(cUnit, templateOpcode);
-#endif
+    oatFlushAllRegs(cUnit);
+    oatLockCallTemps(cUnit);
+    if (wide) {
+        loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
+        loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
+    } else {
+        loadValueDirectFixed(cUnit, rlSrc1, rARG0);
+        loadValueDirectFixed(cUnit, rlSrc2, rARG1);
+    }
+    int rTgt = loadHelper(cUnit, offset);
+    opReg(cUnit, kOpBlx, rTgt);
+    RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
     return false;
-#endif
 }
 
 } //  namespace art
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 6ca6e14..de07c0c 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -28,6 +28,50 @@
 
 namespace art {
 
+extern "C" int art_cmpl_float(float a, float b) {
+    if (a == b) {
+        return 0;
+    } else if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+    return -1;
+}
+
+extern "C" int art_cmpg_float(float a, float b) {
+    if (a == b) {
+        return 0;
+    } else if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+    return 1;
+}
+
+extern "C" int art_cmpl_double(double a, double b) {
+    if (a == b) {
+        return 0;
+    } else if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+    return -1;
+}
+
+extern "C" int art_cmpg_double(double a, double b) {
+    if (a == b) {
+        return 0;
+    } else if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+    return 1;
+}
+
 // Place a special frame at the TOS that will save the callee saves for the given type
 static void  FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type) {
   // Be aware the store below may well stomp on an incoming argument
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 3ee0012..bad74c8 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -138,4 +138,42 @@
 
 #endif
 
+#if defined(__mips__)
+  /* Conversions */
+  extern "C" float __floatsisf(int op1);             // OP_INT_TO_FLOAT
+  extern "C" int __fixsfsi(float op1);               // OP_FLOAT_TO_INT
+  extern "C" float __truncdfsf2(double op1);         // OP_DOUBLE_TO_FLOAT
+  extern "C" double __extendsfdf2(float op1);        // OP_FLOAT_TO_DOUBLE
+  extern "C" double __floatsidf(int op1);            // OP_INT_TO_DOUBLE
+  extern "C" int __fixdfsi(double op1);              // OP_DOUBLE_TO_INT
+  extern "C" float __floatdisf(long long op1);       // OP_LONG_TO_FLOAT
+  extern "C" double __floatdidf(long long op1);      // OP_LONG_TO_DOUBLE
+  extern "C" long long __fixsfdi(float op1);         // OP_FLOAT_TO_LONG
+  extern "C" long long __fixdfdi(double op1);        // OP_DOUBLE_TO_LONG
+
+  /* Single-precision FP arithmetics */
+  extern "C" float __addsf3(float a, float b);   // OP_ADD_FLOAT[_2ADDR]
+  extern "C" float __subsf3(float a, float b);   // OP_SUB_FLOAT[_2ADDR]
+  extern "C" float __divsf3(float a, float b);   // OP_DIV_FLOAT[_2ADDR]
+  extern "C" float __mulsf3(float a, float b);   // OP_MUL_FLOAT[_2ADDR]
+  extern "C" float fmodf(float a, float b);          // OP_REM_FLOAT[_2ADDR]
+
+  /* Double-precision FP arithmetics */
+  extern "C" double __adddf3(double a, double b); // OP_ADD_DOUBLE[_2ADDR]
+  extern "C" double __subdf3(double a, double b); // OP_SUB_DOUBLE[_2ADDR]
+  extern "C" double __divdf3(double a, double b); // OP_DIV_DOUBLE[_2ADDR]
+  extern "C" double __muldf3(double a, double b); // OP_MUL_DOUBLE[_2ADDR]
+  extern "C" double fmod(double a, double b);         // OP_REM_DOUBLE[_2ADDR]
+
+  /* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+  extern "C" long long __divdi3(long long op1, long long op2);
+  extern "C" long long __moddi3(long long op1, long long op2);
+
+  /* Float and double comparison */
+  extern "C" int art_cmpl_float(float a, float b);
+  extern "C" int art_cmpl_double(double a, double b);
+  extern "C" int art_cmpg_float(float a, float b);
+  extern "C" int art_cmpg_double(double a, double b);
+#endif
+
 #endif  // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index dcaf01f..2f3ce6a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -72,6 +72,32 @@
 }
 
 void Thread::InitFunctionPointers() {
+#if defined(__mips)
+  pShlLong = art_shl_long;
+  pShrLong = art_shr_long;
+  pUshrLong = art_ushr_long;
+  pI2f = __floatsisf;
+  pF2iz = __fixsfi;
+  pD2f = __truncdfsf2;
+  pF2d = __extendsfdfs;
+  pD2iz = __fixdfsi;
+  pL2f = __floatdisf;
+  pL2d = __floatdidf;
+  pFadd = __addsf3;
+  pFsub = __subsf3;
+  pFdiv = divsf3;
+  pFmul = __mulsf3;
+  pFmodf = fmodf;
+  pDadd = __adddf3;
+  pDsub = __subdf3;
+  pDdiv = __divdf3;
+  pDmul = muldf3;
+  pFmod = fmod;
+  pCmplFloat = art_cmpl_float;
+  pCmpgFloat = arg_cmpl_float;
+  pCmplDouble = art_cmpl_double;
+  pCmpgDouble = arg_cmpl_double;
+#endif
 #if defined(__arm__)
   pShlLong = art_shl_long;
   pShrLong = art_shr_long;
diff --git a/src/thread.h b/src/thread.h
index 7ad433c..94659c4 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -656,6 +656,10 @@
   const void* (*pUnresolvedDirectMethodTrampolineFromCode)(Method*, Method**, Thread*,
                                                            Runtime::TrampolineType);
   void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
+  bool (*pCmplFloat)(float, float);
+  bool (*pCmpgFloat)(float, float);
+  bool (*pCmplDouble)(double, double);
+  bool (*pCmpgDouble)(double, double);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Thread);