Bug 1336139: Set and restore FPU precision before applying the u64 -> f32 conversion on x86; r=sunfish
authorBenjamin Bouvier <benj@benj.me>
Wed, 01 Mar 2017 16:49:52 +0100
changeset 374839 e824e868c3799a2322c57724e4316b514507c3de
parent 374838 654820d0aed7afe1c47a6b60dd6b261e54b493ca
child 374840 17aafd546d57dfac9a403e1cfc78a89a82cec01a
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1336139
milestone54.0a1
Bug 1336139: Set and restore FPU precision before applying the u64 -> f32 conversion on x86; r=sunfish MozReview-Commit-ID: 5dMdTwiWRx
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/wasm/WasmBaselineCompile.cpp
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -634,18 +634,18 @@ LIRGeneratorX86::visitWasmTruncateToInt6
 void
 LIRGeneratorX86::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
     LDefinition maybeTemp = (ins->isUnsigned() &&
-                             ins->type() == MIRType::Double &&
-                             AssemblerX86Shared::HasSSE3())
+                             ((ins->type() == MIRType::Double && AssemblerX86Shared::HasSSE3()) ||
+                              ins->type() == MIRType::Float32))
                             ? temp()
                             : LDefinition::BogusTemp();
 
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
 LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -919,21 +919,27 @@ MacroAssemblerX86::convertInt64ToFloat32
     fstp32(Operand(esp, 0));
     vmovss(Address(esp, 0), output);
     asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
 {
-    MOZ_ASSERT(temp == Register::Invalid());
-
     // Zero the dest register to break dependencies, see convertInt32ToDouble.
     zeroDouble(output);
 
+    // Set the FPU precision to 80 bits.
+    asMasm().reserveStack(2 * sizeof(intptr_t));
+    fnstcw(Operand(esp, 0));
+    load32(Operand(esp, 0), temp);
+    orl(Imm32(0x300), temp);
+    store32(temp, Operand(esp, sizeof(intptr_t)));
+    fldcw(Operand(esp, sizeof(intptr_t)));
+
     asMasm().Push(input.high);
     asMasm().Push(input.low);
     fild(Operand(esp, 0));
 
     Label notNegative;
     asMasm().branch32(Assembler::NotSigned, input.high, Imm32(0), &notNegative);
     double add_constant = 18446744073709551616.0; // 2^64
     uint64_t add_constant_u64 = mozilla::BitwiseCast<uint64_t>(add_constant);
@@ -941,16 +947,20 @@ MacroAssemblerX86::convertUInt64ToFloat3
 
     fld(Operand(esp, 0));
     faddp();
     bind(&notNegative);
 
     fstp32(Operand(esp, 0));
     vmovss(Address(esp, 0), output);
     asMasm().freeStack(2 * sizeof(intptr_t));
+
+    // Restore FPU precision to the initial value.
+    fldcw(Operand(esp, 0));
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                              Label* oolRejoin, FloatRegister tempReg)
 {
     Label fail, convert;
     Register temp = output.high;
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -3227,17 +3227,19 @@ class BaseCompiler
 # endif
         return true;
     }
 #endif // FLOAT_TO_I64_CALLOUT
 
 #ifndef I64_TO_FLOAT_CALLOUT
     bool convertI64ToFloatNeedsTemp(ValType to, bool isUnsigned) const {
 # if defined(JS_CODEGEN_X86)
-        return to == ValType::F64 && isUnsigned && AssemblerX86Shared::HasSSE3();
+        return isUnsigned &&
+               ((to == ValType::F64 && AssemblerX86Shared::HasSSE3()) ||
+               to == ValType::F32);
 # else
         return isUnsigned;
 # endif
     }
 
     void convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest, RegI32 temp) {
 # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         if (isUnsigned)