Bug 1301400: Baseline Wasm Compiler: Part 2: Implement WasmTruncateI64, r=lth
authorh4writer <hv1989@gmail.com>
Thu, 29 Sep 2016 22:33:22 +0200
changeset 315902 07b4fdd7588aab05136af8c7802d2737d50448ec
parent 315901 58829d3beda3cb5c7c9e83ef370f8d0c1c0789d3
child 315903 7c97d5898871280008baf27b37c98d2e22e52ba5
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1301400
milestone52.0a1
Bug 1301400: Baseline Wasm Compiler: Part 2: Implement WasmTruncateI64, r=lth
js/src/asmjs/WasmBaselineCompile.cpp
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/LIR-x86.h
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
--- a/js/src/asmjs/WasmBaselineCompile.cpp
+++ b/js/src/asmjs/WasmBaselineCompile.cpp
@@ -2719,50 +2719,48 @@ class BaseCompiler
             else
                 MOZ_CRASH("unexpected type");
         }
     };
 #endif
 
     MOZ_MUST_USE
     bool truncateF32ToI64(RegF32 src, RegI64 dest, bool isUnsigned, RegF64 temp) {
-#ifdef JS_CODEGEN_X64
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         OutOfLineCode* ool =
             addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(AnyReg(src),
                                                                               isUnsigned));
         if (!ool)
             return false;
         if (isUnsigned)
-            masm.wasmTruncateFloat32ToUInt64(src.reg, dest.reg.reg, ool->entry(),
+            masm.wasmTruncateFloat32ToUInt64(src.reg, dest.reg, ool->entry(),
                                              ool->rejoin(), temp.reg);
         else
-            masm.wasmTruncateFloat32ToInt64(src.reg, dest.reg.reg, ool->entry(),
+            masm.wasmTruncateFloat32ToInt64(src.reg, dest.reg, ool->entry(),
                                             ool->rejoin(), temp.reg);
-        masm.bind(ool->rejoin());
 #else
         MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI64");
 #endif
         return true;
     }
 
     MOZ_MUST_USE
     bool truncateF64ToI64(RegF64 src, RegI64 dest, bool isUnsigned, RegF64 temp) {
-#ifdef JS_CODEGEN_X64
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         OutOfLineCode* ool =
             addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(AnyReg(src),
                                                                               isUnsigned));
         if (!ool)
             return false;
         if (isUnsigned)
-            masm.wasmTruncateDoubleToUInt64(src.reg, dest.reg.reg, ool->entry(),
+            masm.wasmTruncateDoubleToUInt64(src.reg, dest.reg, ool->entry(),
                                             ool->rejoin(), temp.reg);
         else
-            masm.wasmTruncateDoubleToInt64(src.reg, dest.reg.reg, ool->entry(),
-                                            ool->rejoin(), temp.reg);
-        masm.bind(ool->rejoin());
+            masm.wasmTruncateDoubleToInt64(src.reg, dest.reg, ool->entry(),
+                                           ool->rejoin(), temp.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
 #endif
         return true;
     }
 
     void convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest) {
 #ifdef JS_CODEGEN_X64
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -804,17 +804,17 @@ CodeGeneratorX64::visitExtendInt32ToInt6
     else
         masm.movslq(ToOperand(input), output);
 }
 
 void
 CodeGeneratorX64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
-    Register output = ToRegister(lir->output());
+    Register64 output = ToOutRegister64(lir);
 
     MWasmTruncateToInt64* mir = lir->mir();
     MIRType inputType = mir->input()->type();
 
     MOZ_ASSERT(inputType == MIRType::Double || inputType == MIRType::Float32);
 
     auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input);
     addOutOfLineCode(ool, mir);
@@ -829,18 +829,16 @@ CodeGeneratorX64::visitWasmTruncateToInt
         else
             masm.wasmTruncateDoubleToInt64(input, output, oolEntry, oolRejoin, temp);
     } else {
         if (mir->isUnsigned())
             masm.wasmTruncateFloat32ToUInt64(input, output, oolEntry, oolRejoin, temp);
         else
             masm.wasmTruncateFloat32ToInt64(input, output, oolEntry, oolRejoin, temp);
     }
-
-    masm.bind(ool->rejoin());
 }
 
 void
 CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
 {
     Register input = ToRegister(lir->input());
     FloatRegister output = ToFloatRegister(lir->output());
 
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -151,87 +151,93 @@ MacroAssemblerX64::convertUInt64ToFloat3
     shrq(Imm32(1), scratch);
     vcvtsq2ss(scratch, output, output);
     vaddss(output, output, output);
 
     bind(&done);
 }
 
 void
-MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register output, Label* oolEntry,
+MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                              Label* oolRejoin, FloatRegister tempReg)
 {
-    vcvttsd2sq(input, output);
-    cmpq(Imm32(1), output);
+    vcvttsd2sq(input, output.reg);
+    cmpq(Imm32(1), output.reg);
     j(Assembler::Overflow, oolEntry);
+    bind(oolRejoin);
 }
 
 void
-MacroAssemblerX64::wasmTruncateFloat32ToInt64(FloatRegister input, Register output, Label* oolEntry,
+MacroAssemblerX64::wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                               Label* oolRejoin, FloatRegister tempReg)
 {
-    vcvttss2sq(input, output);
-    cmpq(Imm32(1), output);
+    vcvttss2sq(input, output.reg);
+    cmpq(Imm32(1), output.reg);
     j(Assembler::Overflow, oolEntry);
+    bind(oolRejoin);
 }
 
 void
-MacroAssemblerX64::wasmTruncateDoubleToUInt64(FloatRegister input, Register output, Label* oolEntry,
+MacroAssemblerX64::wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                               Label* oolRejoin, FloatRegister tempReg)
 {
     // If the input < INT64_MAX, vcvttsd2sq will do the right thing, so
     // we use it directly. Else, we subtract INT64_MAX, convert to int64,
     // and then add INT64_MAX to the result.
 
     Label isLarge;
 
     ScratchDoubleScope scratch(asMasm());
     loadConstantDouble(double(0x8000000000000000), scratch);
     asMasm().branchDouble(Assembler::DoubleGreaterThanOrEqual, input, scratch, &isLarge);
-    vcvttsd2sq(input, output);
-    testq(output, output);
+    vcvttsd2sq(input, output.reg);
+    testq(output.reg, output.reg);
     j(Assembler::Signed, oolEntry);
     jump(oolRejoin);
 
     bind(&isLarge);
 
     moveDouble(input, tempReg);
     vsubsd(scratch, tempReg, tempReg);
-    vcvttsd2sq(tempReg, output);
-    testq(output, output);
+    vcvttsd2sq(tempReg, output.reg);
+    testq(output.reg, output.reg);
     j(Assembler::Signed, oolEntry);
-    asMasm().or64(Imm64(0x8000000000000000), Register64(output));
+    asMasm().or64(Imm64(0x8000000000000000), output);
+
+    bind(oolRejoin);
 }
 
 void
-MacroAssemblerX64::wasmTruncateFloat32ToUInt64(FloatRegister input, Register output, Label* oolEntry,
+MacroAssemblerX64::wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                                Label* oolRejoin, FloatRegister tempReg)
 {
     // If the input < INT64_MAX, vcvttss2sq will do the right thing, so
     // we use it directly. Else, we subtract INT64_MAX, convert to int64,
     // and then add INT64_MAX to the result.
 
     Label isLarge;
 
     ScratchFloat32Scope scratch(asMasm());
     loadConstantFloat32(float(0x8000000000000000), scratch);
     asMasm().branchFloat(Assembler::DoubleGreaterThanOrEqual, input, scratch, &isLarge);
-    vcvttss2sq(input, output);
-    testq(output, output);
+    vcvttss2sq(input, output.reg);
+    testq(output.reg, output.reg);
     j(Assembler::Signed, oolEntry);
     jump(oolRejoin);
 
     bind(&isLarge);
 
     moveFloat32(input, tempReg);
     vsubss(scratch, tempReg, tempReg);
-    vcvttss2sq(tempReg, output);
-    testq(output, output);
+    vcvttss2sq(tempReg, output.reg);
+    testq(output.reg, output.reg);
     j(Assembler::Signed, oolEntry);
-    asMasm().or64(Imm64(0x8000000000000000), Register64(output));
+    asMasm().or64(Imm64(0x8000000000000000), output);
+
+    bind(oolRejoin);
 }
 
 void
 MacroAssemblerX64::bindOffsets(const MacroAssemblerX86Shared::UsesVector& uses)
 {
     for (CodeOffset use : uses) {
         JmpDst dst(currentOffset());
         JmpSrc src(use.offset());
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -871,24 +871,24 @@ class MacroAssemblerX64 : public MacroAs
     void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
 
     void convertInt64ToDouble(Register input, FloatRegister output);
     void convertInt64ToFloat32(Register input, FloatRegister output);
 
     void convertUInt64ToDouble(Register input, FloatRegister output);
     void convertUInt64ToFloat32(Register input, FloatRegister output);
 
-    void wasmTruncateDoubleToInt64(FloatRegister input, Register output, Label* oolEntry,
+    void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                    Label* oolRejoin, FloatRegister tempDouble);
-    void wasmTruncateDoubleToUInt64(FloatRegister input, Register output, Label* oolEntry,
+    void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                     Label* oolRejoin, FloatRegister tempDouble);
 
-    void wasmTruncateFloat32ToInt64(FloatRegister input, Register output, Label* oolEntry,
+    void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                     Label* oolRejoin, FloatRegister tempDouble);
-    void wasmTruncateFloat32ToUInt64(FloatRegister input, Register output, Label* oolEntry,
+    void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
                                      Label* oolRejoin, FloatRegister tempDouble);
 
     void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
         CodeOffset label = loadRipRelativeInt64(dest);
         append(wasm::GlobalAccess(label, globalDataOffset));
     }
     void loadWasmPinnedRegsFromTls() {
         loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -1247,106 +1247,58 @@ CodeGeneratorX86::visitNotI64(LNotI64* l
 
 void
 CodeGeneratorX86::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register64 output = ToOutRegister64(lir);
 
     MWasmTruncateToInt64* mir = lir->mir();
-    Register temp = ToRegister(lir->temp1());
-    FloatRegister floatTemp = ToFloatRegister(lir->temp2());
+    FloatRegister floatTemp = ToFloatRegister(lir->temp());
 
     Label fail, convert;
 
     MOZ_ASSERT (mir->input()->type() == MIRType::Double || mir->input()->type() == MIRType::Float32);
 
     auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input);
     addOutOfLineCode(ool, mir);
 
-    masm.reserveStack(2 * sizeof(int32_t));
-    masm.storeDouble(input, Operand(esp, 0));
-
-    // Make sure input fits in (u)int64.
     if (mir->input()->type() == MIRType::Float32) {
         if (mir->isUnsigned())
-            masm.branchFloat32NotInUInt64Range(Address(esp, 0), temp, &fail);
+            masm.wasmTruncateFloat32ToUInt64(input, output, ool->entry(), ool->rejoin(), floatTemp);
         else
-            masm.branchFloat32NotInInt64Range(Address(esp, 0), temp, &fail);
+            masm.wasmTruncateFloat32ToInt64(input, output, ool->entry(), ool->rejoin(), floatTemp);
     } else {
         if (mir->isUnsigned())
-            masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail);
+            masm.wasmTruncateDoubleToUInt64(input, output, ool->entry(), ool->rejoin(), floatTemp);
         else
-            masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail);
+            masm.wasmTruncateDoubleToInt64(input, output, ool->entry(), ool->rejoin(), floatTemp);
     }
-    masm.jump(&convert);
-
-    // Handle failure in ool.
-    masm.bind(&fail);
-    masm.freeStack(2 * sizeof(int32_t));
-    masm.jump(ool->entry());
-    masm.bind(ool->rejoin());
-    masm.reserveStack(2 * sizeof(int32_t));
-    masm.storeDouble(input, Operand(esp, 0));
-
-    // Convert the double/float to int64.
-    masm.bind(&convert);
-    if (mir->input()->type() == MIRType::Float32) {
-        if (mir->isUnsigned())
-            masm.truncateFloat32ToUInt64(Address(esp, 0), Address(esp, 0), temp, floatTemp);
-        else
-            masm.truncateFloat32ToInt64(Address(esp, 0), Address(esp, 0), temp);
-    } else {
-        if (mir->isUnsigned())
-            masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, floatTemp);
-        else
-            masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp);
-    }
-
-    // Load value into int64 register.
-    masm.load64(Address(esp, 0), output);
-
-    masm.freeStack(2 * sizeof(int32_t));
 }
 
 void
 CodeGeneratorX86::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     FloatRegister output = ToFloatRegister(lir->output());
 
     MIRType outputType = lir->mir()->type();
     MOZ_ASSERT(outputType == MIRType::Double || outputType == MIRType::Float32);
 
-    // Zero the output register to break dependencies, see convertInt32ToDouble.
-    if (outputType == MIRType::Double)
-        masm.zeroDouble(output);
-    else
-        masm.zeroFloat32(output);
-
-    masm.Push(input.high);
-    masm.Push(input.low);
-    masm.fild(Operand(esp, 0));
-
-    if (lir->mir()->isUnsigned()) {
-        Label notNegative;
-        masm.branch32(Assembler::NotSigned, input.high, Imm32(0), &notNegative);
-        double add_constant = 18446744073709551616.0; // 2^64
-        masm.store64(Imm64(mozilla::BitwiseCast<uint64_t>(add_constant)), Address(esp, 0));
-        masm.fld(Operand(esp, 0));
-        masm.faddp();
-        masm.bind(&notNegative);
+    if (outputType == MIRType::Double) {
+        if (lir->mir()->isUnsigned())
+            masm.convertUInt64ToFloat64(input, output);
+        else
+            masm.convertInt64ToFloat64(input, output);
+    } else {
+        if (lir->mir()->isUnsigned())
+            masm.convertUInt64ToFloat32(input, output);
+        else
+            masm.convertInt64ToFloat32(input, output);
     }
-
-    masm.fstp(Operand(esp, 0));
-    masm.vmovsd(Address(esp, 0), output);
-    masm.freeStack(2*sizeof(intptr_t));
-
-    if (outputType == MIRType::Float32)
-        masm.convertDoubleToFloat32(output, output);
 }
 
 void
 CodeGeneratorX86::visitTestI64AndBranch(LTestI64AndBranch* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
 
     masm.testl(input.high, input.high);
--- a/js/src/jit/x86/LIR-x86.h
+++ b/js/src/jit/x86/LIR-x86.h
@@ -164,42 +164,32 @@ class LUDivOrModI64 : public LCallInstru
     }
     bool canBeNegativeOverflow() const {
         if (mir_->isMod())
             return mir_->toMod()->canBeNegativeDividend();
         return mir_->toDiv()->canBeNegativeOverflow();
     }
 };
 
-class LWasmTruncateToInt64 : public LInstructionHelper<INT64_PIECES, 1, 3>
+class LWasmTruncateToInt64 : public LInstructionHelper<INT64_PIECES, 1, 1>
 {
   public:
     LIR_HEADER(WasmTruncateToInt64);
 
-    LWasmTruncateToInt64(const LAllocation& in, const LDefinition& temp1, const LDefinition& temp2,
-                         const LDefinition& temp3)
+    LWasmTruncateToInt64(const LAllocation& in, const LDefinition& temp)
     {
         setOperand(0, in);
-        setTemp(0, temp1);
-        setTemp(1, temp2);
-        setTemp(2, temp3);
+        setTemp(0, temp);
     }
 
     MWasmTruncateToInt64* mir() const {
         return mir_->toWasmTruncateToInt64();
     }
 
-    const LDefinition* temp1() {
+    const LDefinition* temp() {
         return getTemp(0);
     }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-    const LDefinition* temp3() {
-        MOZ_ASSERT(mir()->isUnsigned());
-        return getTemp(2);
-    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_LIR_x86_h */
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -622,20 +622,18 @@ LIRGeneratorX86::visitRandom(MRandom* in
 }
 
 void
 LIRGeneratorX86::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
 
-    LDefinition temp1 = temp();
-    LDefinition temp2 = tempDouble();
-    LDefinition maybeTemp = ins->isUnsigned() ? tempDouble() : LDefinition::BogusTemp();
-    defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd), temp1, temp2, maybeTemp), ins);
+    LDefinition temp = tempDouble();
+    defineInt64(new(alloc()) LWasmTruncateToInt64(useRegister(opd), temp), ins);
 }
 
 void
 LIRGeneratorX86::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -800,8 +800,129 @@ MacroAssembler::wasmTruncateFloat32ToUIn
 
     branch32(Assembler::Condition::Signed, output, Imm32(0), oolEntry);
     or32(Imm32(0x80000000), output);
 
     bind(&done);
 }
 
 //}}} check_macroassembler_style
+
+void
+MacroAssemblerX86::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                             Label* oolRejoin, FloatRegister tempReg)
+{
+    Label fail, convert;
+    Register temp = output.high;
+
+    // Make sure input fits in (u)int64.
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeDouble(input, Operand(esp, 0));
+    asMasm().branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail);
+    jump(&convert);
+
+    // Handle failure in ool.
+    bind(&fail);
+    asMasm().freeStack(2 * sizeof(int32_t));
+    jump(oolEntry);
+    bind(oolRejoin);
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeDouble(input, Operand(esp, 0));
+
+    // Convert the double/float to int64.
+    bind(&convert);
+    asMasm().truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp);
+
+    // Load value into int64 register.
+    load64(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(int32_t));
+}
+
+void
+MacroAssemblerX86::wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                              Label* oolRejoin, FloatRegister tempReg)
+{
+    Label fail, convert;
+    Register temp = output.high;
+
+    // Make sure input fits in (u)int64.
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeFloat32(input, Operand(esp, 0));
+    asMasm().branchFloat32NotInInt64Range(Address(esp, 0), temp, &fail);
+    jump(&convert);
+
+    // Handle failure in ool.
+    bind(&fail);
+    asMasm().freeStack(2 * sizeof(int32_t));
+    jump(oolEntry);
+    bind(oolRejoin);
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeFloat32(input, Operand(esp, 0));
+
+    // Convert the double/float to int64.
+    bind(&convert);
+    asMasm().truncateFloat32ToInt64(Address(esp, 0), Address(esp, 0), temp);
+
+    // Load value into int64 register.
+    load64(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(int32_t));
+}
+
+void
+MacroAssemblerX86::wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                              Label* oolRejoin, FloatRegister tempReg)
+{
+    Label fail, convert;
+    Register temp = output.high;
+
+    // Make sure input fits in (u)int64.
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeDouble(input, Operand(esp, 0));
+    asMasm().branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail);
+    jump(&convert);
+
+    // Handle failure in ool.
+    bind(&fail);
+    asMasm().freeStack(2 * sizeof(int32_t));
+    jump(oolEntry);
+    bind(oolRejoin);
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeDouble(input, Operand(esp, 0));
+
+    // Convert the double/float to int64.
+    bind(&convert);
+    asMasm().truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, tempReg);
+
+    // Load value into int64 register.
+    load64(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(int32_t));
+}
+
+void
+MacroAssemblerX86::wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                               Label* oolRejoin, FloatRegister tempReg)
+{
+    Label fail, convert;
+    Register temp = output.high;
+
+    // Make sure input fits in (u)int64.
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeFloat32(input, Operand(esp, 0));
+    asMasm().branchFloat32NotInUInt64Range(Address(esp, 0), temp, &fail);
+    jump(&convert);
+
+    // Handle failure in ool.
+    bind(&fail);
+    asMasm().freeStack(2 * sizeof(int32_t));
+    jump(oolEntry);
+    bind(oolRejoin);
+    asMasm().reserveStack(2 * sizeof(int32_t));
+    asMasm().storeFloat32(input, Operand(esp, 0));
+
+    // Convert the double/float to int64.
+    bind(&convert);
+    asMasm().truncateFloat32ToUInt64(Address(esp, 0), Address(esp, 0), temp, tempReg);
+
+    // Load value into int64 register.
+    load64(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(int32_t));
+}
+
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -831,16 +831,25 @@ class MacroAssemblerX86 : public MacroAs
     // Note: this function clobbers the source register.
     inline void convertUInt32ToDouble(Register src, FloatRegister dest);
 
     // Note: this function clobbers the source register.
     inline void convertUInt32ToFloat32(Register src, FloatRegister dest);
 
     void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
 
+    void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                   Label* oolRejoin, FloatRegister tempDouble);
+    void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                    Label* oolRejoin, FloatRegister tempDouble);
+    void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                    Label* oolRejoin, FloatRegister tempDouble);
+    void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
+                                     Label* oolRejoin, FloatRegister tempDouble);
+
     void incrementInt32Value(const Address& addr) {
         addl(Imm32(1), payloadOf(addr));
     }
 
     inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
     void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
         CodeOffset label = movlWithPatch(PatchedAbsoluteAddress(), dest);