Bug 1455019 - [MIPS64] Add error detection for int64 <-> fp conversion in simulator. r=bbouvier
☠☠ backed out by 6e69352a940e ☠ ☠
authorDragan Mladjenovic <dragan.mladjenovic@rt-rk.com>
Wed, 25 Apr 2018 02:24:00 -0400
changeset 471812 1b5f2913b206dec1926bd8f482ec97d4897bc97e
parent 471811 f93d567284f7365632af954635ccfd438e8f2ed8
child 471813 53422b4220719b9d0c4c21da881b6baff2298266
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1455019
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1455019 - [MIPS64] Add error detection for int64 <-> fp conversion in simulator. r=bbouvier
js/src/jit/mips64/Simulator-mips64.cpp
js/src/jit/mips64/Simulator-mips64.h
--- a/js/src/jit/mips64/Simulator-mips64.cpp
+++ b/js/src/jit/mips64/Simulator-mips64.cpp
@@ -31,16 +31,17 @@
 
 #include "mozilla/Casting.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include <float.h>
+#include <limits>
 
 #include "jit/AtomicOperations.h"
 #include "jit/mips64/Assembler-mips64.h"
 #include "threading/LockGuard.h"
 #include "vm/Runtime.h"
 #include "wasm/WasmInstance.h"
 #include "wasm/WasmSignalHandlers.h"
 
@@ -1552,16 +1553,17 @@ Simulator::setFCSRBit(uint32_t cc, bool 
 bool
 Simulator::testFCSRBit(uint32_t cc)
 {
     return FCSR_ & (1 << cc);
 }
 
 // Sets the rounding error codes in FCSR based on the result of the rounding.
 // Returns true if the operation was invalid.
+template <typename T>
 bool
 Simulator::setFCSRRoundError(double original, double rounded)
 {
     bool ret = false;
 
     setFCSRBit(kFCSRInexactCauseBit, false);
     setFCSRBit(kFCSRUnderflowCauseBit, false);
     setFCSRBit(kFCSROverflowCauseBit, false);
@@ -1579,17 +1581,19 @@ Simulator::setFCSRRoundError(double orig
     }
 
     if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
         setFCSRBit(kFCSRUnderflowFlagBit, true);
         setFCSRBit(kFCSRUnderflowCauseBit, true);
         ret = true;
     }
 
-    if (rounded > INT_MAX || rounded < INT_MIN) {
+    if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
+        (long double)rounded < (long double)std::numeric_limits<T>::min())
+    {
         setFCSRBit(kFCSROverflowFlagBit, true);
         setFCSRBit(kFCSROverflowCauseBit, true);
         // The reference is not really clear but it seems this is required:
         setFCSRBit(kFCSRInvalidOpFlagBit, true);
         setFCSRBit(kFCSRInvalidOpCauseBit, true);
         ret = true;
     }
 
@@ -2725,17 +2729,17 @@ Simulator::configureTypeRegister(SimInst
             break;
           case ff_xor:
             alu_out = rs ^ rt;
             break;
           case ff_nor:
             alu_out = ~(rs | rt);
             break;
           case ff_slt:
-            alu_out = I32_CHECK(rs) < I32_CHECK(rt) ? 1 : 0;
+            alu_out = I64(rs) < I64(rt) ? 1 : 0;
             break;
           case ff_sltu:
             alu_out = U64(rs) < U64(rt) ? 1 : 0;
             break;
           case ff_sync:
             break;
             // Break and trap instructions.
           case ff_break:
@@ -2769,17 +2773,17 @@ Simulator::configureTypeRegister(SimInst
                 i128hilo = U32(INT_MIN);
             } else {
                 uint32_t div = I32_CHECK(rs) / I32_CHECK(rt);
                 uint32_t mod = I32_CHECK(rs) % I32_CHECK(rt);
                 i128hilo = (I64(mod) << 32) | div;
             }
             break;
           case ff_ddiv:
-            if (I32_CHECK(rs) == INT_MIN && I32_CHECK(rt) == -1) {
+            if (I64(rs) == INT64_MIN && I64(rt) == -1) {
                 i128hilo = U64(INT64_MIN);
             } else {
                 uint64_t div = rs / rt;
                 uint64_t mod = rs % rt;
                 i128hilo = (I128(mod) << 64) | div;
             }
             break;
           case ff_divu: {
@@ -3081,75 +3085,82 @@ Simulator::decodeTypeRegister(SimInstruc
                 float rounded = std::floor(fs_value + 0.5);
                 int32_t result = I32(rounded);
                 if ((result & 1) != 0 && result - fs_value == 0.5) {
                     // If the number is halfway between two integers,
                     // round to the even one.
                     result--;
                 }
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(fs_value, rounded)) {
+                if (setFCSRRoundError<int32_t>(fs_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
-                }
                 break;
               }
               case ff_trunc_w_fmt: { // Truncate float to word (round towards 0).
                 float rounded = truncf(fs_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(fs_value, rounded)) {
+                if (setFCSRRoundError<int32_t>(fs_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
-                }
                 break;
               }
               case ff_floor_w_fmt: { // Round float to word towards negative infinity.
                 float rounded = std::floor(fs_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(fs_value, rounded)) {
+                if (setFCSRRoundError<int32_t>(fs_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
-                }
                 break;
               }
               case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
                 float rounded = std::ceil(fs_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(fs_value, rounded)) {
+                if (setFCSRRoundError<int32_t>(fs_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
-                }
                 break;
               }
-              case ff_cvt_l_fmt: {  // Mips64r2: Truncate float to 64-bit long-word.
-                float rounded = truncf(fs_value);
-                i64 = I64(rounded);
-                setFpuRegister(fd_reg, i64);
-                break;
-              }
+              case ff_cvt_l_fmt:  // Mips64r2: Truncate float to 64-bit long-word.
+                // Rounding modes are not yet supported.
+                MOZ_ASSERT((FCSR_ & 3) == 0);
+                // In rounding mode 0 it should behave like ROUND.
+                MOZ_FALLTHROUGH;
               case ff_round_l_fmt: {  // Mips64r2 instruction.
                 float rounded =
                     fs_value > 0 ? std::floor(fs_value + 0.5) : std::ceil(fs_value - 0.5);
                 i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(fs_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
               }
               case ff_trunc_l_fmt: {  // Mips64r2 instruction.
                 float rounded = truncf(fs_value);
                 i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(fs_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
               }
-              case ff_floor_l_fmt:  // Mips64r2 instruction.
-                i64 = I64(std::floor(fs_value));
+              case ff_floor_l_fmt: {  // Mips64r2 instruction.
+                float rounded = std::floor(fs_value);
+                i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(fs_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
-              case ff_ceil_l_fmt:  // Mips64r2 instruction.
-                i64 = I64(std::ceil(fs_value));
+              }
+              case ff_ceil_l_fmt: {  // Mips64r2 instruction.
+                float rounded = std::ceil(fs_value);
+                i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(fs_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
+              }
               case ff_cvt_ps_s:
               case ff_c_f_fmt:
                 MOZ_CRASH();
                 break;
               case ff_movf_fmt:
                 if (testFCSRBit(fcsr_cc)) {
                   setFpuRegisterFloat(fd_reg, getFpuRegisterFloat(fs_reg));
                 }
@@ -3232,74 +3243,85 @@ Simulator::decodeTypeRegister(SimInstruc
                 double rounded = std::floor(ds_value + 0.5);
                 int32_t result = I32(rounded);
                 if ((result & 1) != 0 && result - ds_value == 0.5) {
                     // If the number is halfway between two integers,
                     // round to the even one.
                     result--;
                 }
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(ds_value, rounded))
+                if (setFCSRRoundError<int32_t>(ds_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
                 break;
               }
               case ff_trunc_w_fmt: { // Truncate double to word (round towards 0).
                 double rounded = trunc(ds_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(ds_value, rounded))
+                if (setFCSRRoundError<int32_t>(ds_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
                 break;
               }
               case ff_floor_w_fmt: { // Round double to word towards negative infinity.
                 double rounded = std::floor(ds_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(ds_value, rounded))
+                if (setFCSRRoundError<int32_t>(ds_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
                 break;
               }
               case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
                 double rounded = std::ceil(ds_value);
                 int32_t result = I32(rounded);
                 setFpuRegisterLo(fd_reg, result);
-                if (setFCSRRoundError(ds_value, rounded))
+                if (setFCSRRoundError<int32_t>(ds_value, rounded))
                     setFpuRegisterLo(fd_reg, kFPUInvalidResult);
                 break;
               }
               case ff_cvt_s_fmt:  // Convert double to float (single).
                 setFpuRegisterFloat(fd_reg, static_cast<float>(ds_value));
                 break;
-              case ff_cvt_l_fmt: {  // Mips64r2: Truncate double to 64-bit long-word.
-                double rounded = trunc(ds_value);
+              case ff_cvt_l_fmt:  // Mips64r2: Truncate double to 64-bit long-word.
+                // Rounding modes are not yet supported.
+                MOZ_ASSERT((FCSR_ & 3) == 0);
+                // In rounding mode 0 it should behave like ROUND.
+                MOZ_FALLTHROUGH;
+              case ff_round_l_fmt: {  // Mips64r2 instruction.
+                double rounded =
+                    ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
                 i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(ds_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
               }
               case ff_trunc_l_fmt: {  // Mips64r2 instruction.
                 double rounded = trunc(ds_value);
                 i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
-                break;
-              }
-              case ff_round_l_fmt: {  // Mips64r2 instruction.
-                double rounded =
-                    ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
-                i64 = I64(rounded);
-                setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(ds_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
               }
-              case ff_floor_l_fmt:  // Mips64r2 instruction.
-                i64 = I64(std::floor(ds_value));
+              case ff_floor_l_fmt: {  // Mips64r2 instruction.
+                double rounded = std::floor(ds_value);
+                i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(ds_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
-              case ff_ceil_l_fmt:  // Mips64r2 instruction.
-                i64 = I64(std::ceil(ds_value));
+              }
+              case ff_ceil_l_fmt: {  // Mips64r2 instruction.
+                double rounded = std::ceil(ds_value);
+                i64 = I64(rounded);
                 setFpuRegister(fd_reg, i64);
+                if (setFCSRRoundError<int64_t>(ds_value, rounded))
+                    setFpuRegister(fd_reg, kFPUInvalidResult64);
                 break;
+              }
               case ff_c_f_fmt:
                 MOZ_CRASH();
                 break;
               case ff_movz_fmt:
                 if (rt == 0) {
                   setFpuRegisterDouble(fd_reg, getFpuRegisterDouble(fs_reg));
                 }
                 break;
--- a/js/src/jit/mips64/Simulator-mips64.h
+++ b/js/src/jit/mips64/Simulator-mips64.h
@@ -70,16 +70,17 @@ const int kPCRegister = 34;
 
 // Number coprocessor registers.
 const int kNumFPURegisters = 32;
 
 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
 const int kFCSRRegister = 31;
 const int kInvalidFPUControlRegister = -1;
 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
+const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1;
 
 // FCSR constants.
 const uint32_t kFCSRInexactFlagBit = 2;
 const uint32_t kFCSRUnderflowFlagBit = 3;
 const uint32_t kFCSROverflowFlagBit = 4;
 const uint32_t kFCSRDivideByZeroFlagBit = 5;
 const uint32_t kFCSRInvalidOpFlagBit = 6;
 
@@ -192,16 +193,17 @@ class Simulator {
     void setFpuRegisterDouble(int fpureg, double value);
     int64_t getFpuRegister(int fpureg) const;
     int32_t getFpuRegisterLo(int fpureg) const;
     int32_t getFpuRegisterHi(int fpureg) const;
     float getFpuRegisterFloat(int fpureg) const;
     double getFpuRegisterDouble(int fpureg) const;
     void setFCSRBit(uint32_t cc, bool value);
     bool testFCSRBit(uint32_t cc);
+    template <typename T>
     bool setFCSRRoundError(double original, double rounded);
 
     // Special case of set_register and get_register to access the raw PC value.
     void set_pc(int64_t value);
     int64_t get_pc() const;
 
     template <typename T>
     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }