Bug 1336139: Fix uint64 to floating-point conversion; r=sunfish
authorBenjamin Bouvier <benj@benj.me>
Fri, 10 Feb 2017 16:26:15 +0100
changeset 374838 654820d0aed7afe1c47a6b60dd6b261e54b493ca
parent 374837 bcb46d32449b7f9b53af8bc9512ec373c557c23a
child 374839 e824e868c3799a2322c57724e4316b514507c3de
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: Fix uint64 to floating-point conversion; r=sunfish MozReview-Commit-ID: 4Lk4ifPqO9d
js/src/jit-test/tests/wasm/conversion.js
js/src/jit/IonTypes.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/Simulator-arm.cpp
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/wasm/WasmBaselineCompile.cpp
js/src/wasm/WasmTypes.cpp
js/src/wasm/WasmTypes.h
testing/web-platform/mozilla/meta/wasm/conversions.wast.js.html.ini
--- a/js/src/jit-test/tests/wasm/conversion.js
+++ b/js/src/jit-test/tests/wasm/conversion.js
@@ -84,16 +84,23 @@ function testTrap(resultType, opcode, pa
     testConversion('f32', 'convert_s', 'i64', 0, 0.0);
     testConversion('f32', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f32', 'convert_s', 'i64', "0x11db9e76a2483", 314159275180032.0);
     testConversion('f32', 'convert_s', 'i64', "0x7fffffff", 2147483648.0); // closesth approx.
     testConversion('f32', 'convert_s', 'i64', "0x80000000", 2147483648.0);
     testConversion('f32', 'convert_s', 'i64', "0x80000001", 2147483648.0); // closesth approx.
 
+    // Interesting values at the boundaries.
+    testConversion('f32', 'convert_s', 'i64', "0x358a09a000000002", 3857906751034621952);
+    testConversion('f32', 'convert_s', 'i64', "0x8000004000000001", -9223371487098961920);
+    testConversion('f32', 'convert_s', 'i64', "0xffdfffffdfffffff", -9007200328482816);
+    testConversion('f32', 'convert_s', 'i64', "0x0020000020000001", 9007200328482816);
+    testConversion('f32', 'convert_s', 'i64', "0x7fffff4000000001", 9223371487098961920);
+
     testConversion('f64', 'convert_s', 'i64', 1, 1.0);
     testConversion('f64', 'convert_s', 'i64', -1, -1.0);
     testConversion('f64', 'convert_s', 'i64', 0, 0.0);
     testConversion('f64', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f64', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
     testConversion('f64', 'convert_s', 'i64', "0x10969d374b968e", 4669201609102990);
     testConversion('f64', 'convert_s', 'i64', "0x7fffffff", 2147483647.0);
     testConversion('f64', 'convert_s', 'i64', "0x80000000", 2147483648.0);
@@ -101,22 +108,34 @@ function testTrap(resultType, opcode, pa
 
     testConversion('f32', 'convert_u', 'i64', 1, 1.0);
     testConversion('f32', 'convert_u', 'i64', 0, 0.0);
     testConversion('f32', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f32', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
 
+    // Interesting values at the boundaries.
+    testConversion('f32', 'convert_u', 'i64', "0x100404900000008", 72128280609685500);
+    testConversion('f32', 'convert_u', 'i64', "0x7fffff4000000001", 9223371487098962000);
+    testConversion('f32', 'convert_u', 'i64', "0x0020000020000001", 9007200328482816);
+    testConversion('f32', 'convert_u', 'i64', "0x7fffffbfffffffff", 9223371487098961920);
+    testConversion('f32', 'convert_u', 'i64', "0x8000008000000001", 9223373136366403584);
+    testConversion('f32', 'convert_u', 'i64', "0xfffffe8000000001", 18446742974197923840);
+
     testConversion('f64', 'convert_u', 'i64', 1, 1.0);
     testConversion('f64', 'convert_u', 'i64', 0, 0.0);
     testConversion('f64', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
     testConversion('f64', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
     testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
     testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
+    testConversion('f64', 'convert_u', 'i64', "0xbf869c3369c26401", 13800889852755077000);
+    testConversion('f64', 'convert_u', 'i64', "0x7fffff4000000001", 9223371212221054976);
+    testConversion('f64', 'convert_u', 'i64', "0x8000008000000001", 9223372586610589696);
+    testConversion('f64', 'convert_u', 'i64', "0xfffffe8000000001", 18446742424442109952);
 
     testConversion('i64', 'trunc_s', 'f64', 0.0, 0);
     testConversion('i64', 'trunc_s', 'f64', "-0.0", 0);
     testConversion('i64', 'trunc_s', 'f64', 1.0, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.1, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.5, 1);
     testConversion('i64', 'trunc_s', 'f64', 1.99, 1);
     testConversion('i64', 'trunc_s', 'f64', 40.1, 40);
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -801,16 +801,21 @@ enum ABIFunctionType
     Args_Double_None = ArgType_Double << RetType_Shift,
 
     // int f(double)
     Args_Int_Double = Args_General0 | (ArgType_Double << ArgType_Shift),
 
     // float f(float)
     Args_Float32_Float32 = (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
 
+    // float f(int, int)
+    Args_Float32_IntInt = (ArgType_Float32 << RetType_Shift) |
+        (ArgType_General << (ArgType_Shift * 1)) |
+        (ArgType_General << (ArgType_Shift * 2)),
+
     // double f(double)
     Args_Double_Double = Args_Double_None | (ArgType_Double << ArgType_Shift),
 
     // double f(int)
     Args_Double_Int = Args_Double_None | (ArgType_General << ArgType_Shift),
 
     // double f(int, int)
     Args_Double_IntInt = Args_Double_Int | (ArgType_General << (ArgType_Shift * 2)),
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3021,40 +3021,42 @@ CodeGeneratorARM::visitOutOfLineWasmTrun
                                          ool->isUnsigned(), ool->rejoin(),
                                          ool->trapOffset());
 }
 
 void
 CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
-    FloatRegister output = ToFloatRegister(lir->output());
 
     MInt64ToFloatingPoint* mir = lir->mir();
     MIRType toType = mir->type();
 
     // We are free to clobber all registers, since this is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input.low);
     regs.take(input.high);
     Register temp = regs.takeAny();
 
     masm.setupUnalignedABICall(temp);
     masm.passABIArg(input.high);
     masm.passABIArg(input.low);
-    if (lir->mir()->isUnsigned())
-        masm.callWithABI(wasm::SymbolicAddress::Uint64ToFloatingPoint, MoveOp::DOUBLE);
-    else
-        masm.callWithABI(wasm::SymbolicAddress::Int64ToFloatingPoint, MoveOp::DOUBLE);
-
-    MOZ_ASSERT_IF(toType == MIRType::Double, output == ReturnDoubleReg);
-    if (toType == MIRType::Float32) {
-        MOZ_ASSERT(output == ReturnFloat32Reg);
-        masm.convertDoubleToFloat32(ReturnDoubleReg, output);
-    }
+
+    bool isUnsigned = mir->isUnsigned();
+    wasm::SymbolicAddress callee = toType == MIRType::Float32
+                                   ? (isUnsigned ? wasm::SymbolicAddress::Uint64ToFloat32
+                                                 : wasm::SymbolicAddress::Int64ToFloat32)
+                                   : (isUnsigned ? wasm::SymbolicAddress::Uint64ToDouble
+                                                 : wasm::SymbolicAddress::Int64ToDouble);
+
+    masm.callWithABI(callee, toType == MIRType::Float32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
+
+    DebugOnly<FloatRegister> output(ToFloatRegister(lir->output()));
+    MOZ_ASSERT_IF(toType == MIRType::Double, output.value == ReturnDoubleReg);
+    MOZ_ASSERT_IF(toType == MIRType::Float32, output.value == ReturnFloat32Reg);
 }
 
 void
 CodeGeneratorARM::visitCopySignF(LCopySignF* ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->getOperand(0));
     FloatRegister rhs = ToFloatRegister(ins->getOperand(1));
     FloatRegister output = ToFloatRegister(ins->getDef(0));
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -2433,16 +2433,17 @@ typedef double (*Prototype_Double_Double
 typedef double (*Prototype_Double_Int)(int32_t arg0);
 typedef double (*Prototype_Double_IntInt)(int32_t arg0, int32_t arg1);
 typedef int32_t (*Prototype_Int_Double)(double arg0);
 typedef int64_t (*Prototype_Int64_Double)(double arg0);
 typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
 typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
                                                  int32_t arg3);
 typedef float (*Prototype_Float32_Float32)(float arg0);
+typedef float (*Prototype_Float32_IntInt)(int arg0, int arg1);
 
 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
 
 typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
 typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
@@ -2620,16 +2621,23 @@ Simulator::softwareInterrupt(SimInstruct
             else
                 fval0 = mozilla::BitwiseCast<float>(arg0);
             Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
             float fresult = target(fval0);
             scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultFloat(fresult);
             break;
           }
+          case Args_Float32_IntInt: {
+            Prototype_Float32_IntInt target = reinterpret_cast<Prototype_Float32_IntInt>(external);
+            float fresult = target(arg0, arg1);
+            scratchVolatileRegisters(/* scratchFloat = true */);
+            setCallResultFloat(fresult);
+            break;
+          }
           case Args_Double_Int: {
             Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
             double dresult = target(arg0);
             scratchVolatileRegisters(/* scratchFloat = true */);
             setCallResultDouble(dresult);
             break;
           }
           case Args_Double_IntInt: {
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -734,27 +734,31 @@ CodeGeneratorX64::visitWasmTruncateToInt
 }
 
 void
 CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     FloatRegister output = ToFloatRegister(lir->output());
 
-    MIRType outputType = lir->mir()->type();
+    MInt64ToFloatingPoint* mir = lir->mir();
+    bool isUnsigned = mir->isUnsigned();
+
+    MIRType outputType = mir->type();
     MOZ_ASSERT(outputType == MIRType::Double || outputType == MIRType::Float32);
+    MOZ_ASSERT(isUnsigned == !lir->getTemp(0)->isBogusTemp());
 
     if (outputType == MIRType::Double) {
-        if (lir->mir()->isUnsigned())
-            masm.convertUInt64ToDouble(input, output, Register::Invalid());
+        if (isUnsigned)
+            masm.convertUInt64ToDouble(input, output, ToRegister(lir->getTemp(0)));
         else
             masm.convertInt64ToDouble(input, output);
     } else {
-        if (lir->mir()->isUnsigned())
-            masm.convertUInt64ToFloat32(input, output, Register::Invalid());
+        if (isUnsigned)
+            masm.convertUInt64ToFloat32(input, output, ToRegister(lir->getTemp(0)));
         else
             masm.convertInt64ToFloat32(input, output);
     }
 }
 
 void
 CodeGeneratorX64::visitNotI64(LNotI64* lir)
 {
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -480,16 +480,17 @@ LIRGeneratorX64::visitWasmTruncateToInt6
 
 void
 LIRGeneratorX64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Int64);
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
 
-    define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), LDefinition::BogusTemp()), ins);
+    LDefinition maybeTemp = ins->isUnsigned() ? temp() : LDefinition::BogusTemp();
+    define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
 LIRGeneratorX64::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     defineInt64(new(alloc()) LExtendInt32ToInt64(useAtStart(ins->input())), ins);
 }
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -88,71 +88,75 @@ MacroAssemblerX64::convertInt64ToFloat32
     zeroFloat32(output);
 
     vcvtsq2ss(input.reg, output, output);
 }
 
 bool
 MacroAssemblerX64::convertUInt64ToDoubleNeedsTemp()
 {
-    return false;
+    return true;
 }
 
 void
 MacroAssemblerX64::convertUInt64ToDouble(Register64 input, FloatRegister output, Register temp)
 {
-    MOZ_ASSERT(temp == Register::Invalid());
-
     // Zero the output register to break dependencies, see convertInt32ToDouble.
     zeroDouble(output);
 
     // If the input's sign bit is not set we use vcvtsq2sd directly.
-    // Else, we divide by 2, convert to double, and multiply the result by 2.
+    // Else, we divide by 2 and keep the LSB, convert to double, and multiply
+    // the result by 2.
     Label done;
     Label isSigned;
 
     testq(input.reg, input.reg);
     j(Assembler::Signed, &isSigned);
     vcvtsq2sd(input.reg, output, output);
     jump(&done);
 
     bind(&isSigned);
 
     ScratchRegisterScope scratch(asMasm());
     mov(input.reg, scratch);
+    mov(input.reg, temp);
     shrq(Imm32(1), scratch);
+    andq(Imm32(1), temp);
+    orq(temp, scratch);
+
     vcvtsq2sd(scratch, output, output);
     vaddsd(output, output, output);
 
     bind(&done);
 }
 
 void
 MacroAssemblerX64::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
 {
-    MOZ_ASSERT(temp == Register::Invalid());
-
     // Zero the output register to break dependencies, see convertInt32ToDouble.
     zeroFloat32(output);
 
-    // If the input's sign bit is not set we use vcvtsq2ss directly.
-    // Else, we divide by 2, convert to float, and multiply the result by 2.
+    // See comment in convertUInt64ToDouble.
     Label done;
     Label isSigned;
 
     testq(input.reg, input.reg);
     j(Assembler::Signed, &isSigned);
     vcvtsq2ss(input.reg, output, output);
     jump(&done);
 
     bind(&isSigned);
 
     ScratchRegisterScope scratch(asMasm());
     mov(input.reg, scratch);
+    mov(input.reg, temp);
     shrq(Imm32(1), scratch);
+    andq(Imm32(1), temp);
+    orq(temp, scratch);
+
     vcvtsq2ss(scratch, output, output);
     vaddss(output, output, output);
 
     bind(&done);
 }
 
 void
 MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -633,18 +633,21 @@ 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() && AssemblerX86Shared::HasSSE3()) ? temp() : LDefinition::BogusTemp();
+    LDefinition maybeTemp = (ins->isUnsigned() &&
+                             ins->type() == MIRType::Double &&
+                             AssemblerX86Shared::HasSSE3())
+                            ? temp()
+                            : LDefinition::BogusTemp();
 
     define(new(alloc()) LInt64ToFloatingPoint(useInt64Register(opd), maybeTemp), ins);
 }
 
 void
 LIRGeneratorX86::visitExtendInt32ToInt64(MExtendInt32ToInt64* ins)
 {
     if (ins->isUnsigned()) {
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -57,17 +57,17 @@ MacroAssemblerX86::convertUInt64ToDouble
         double add_constant = 18446744073709551616.0; // 2^64
         store64(Imm64(mozilla::BitwiseCast<uint64_t>(add_constant)), Address(esp, 0));
         fld(Operand(esp, 0));
         faddp();
         bind(&notNegative);
 
         fstp(Operand(esp, 0));
         vmovsd(Address(esp, 0), dest);
-        asMasm().freeStack(2*sizeof(intptr_t));
+        asMasm().freeStack(2 * sizeof(intptr_t));
         return;
     }
 
     // Following operation uses entire 128-bit of dest XMM register.
     // Currently higher 64-bit is free when we have access to lower 64-bit.
     MOZ_ASSERT(dest.size() == 8);
     FloatRegister dest128 = FloatRegister(dest.encoding(), FloatRegisters::Simd128);
 
@@ -898,31 +898,59 @@ MacroAssemblerX86::convertInt64ToDouble(
     zeroDouble(output);
 
     asMasm().Push(input.high);
     asMasm().Push(input.low);
     fild(Operand(esp, 0));
 
     fstp(Operand(esp, 0));
     vmovsd(Address(esp, 0), output);
-    asMasm().freeStack(2*sizeof(intptr_t));
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::convertInt64ToFloat32(Register64 input, FloatRegister output)
 {
-    convertInt64ToDouble(input, output);
-    convertDoubleToFloat32(output, output);
+    // Zero the output register to break dependencies, see convertInt32ToDouble.
+    zeroDouble(output);
+
+    asMasm().Push(input.high);
+    asMasm().Push(input.low);
+    fild(Operand(esp, 0));
+
+    fstp32(Operand(esp, 0));
+    vmovss(Address(esp, 0), output);
+    asMasm().freeStack(2 * sizeof(intptr_t));
 }
 
 void
 MacroAssemblerX86::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
 {
-    convertUInt64ToDouble(input, output.asDouble(), temp);
-    convertDoubleToFloat32(output, output);
+    MOZ_ASSERT(temp == Register::Invalid());
+
+    // Zero the dest register to break dependencies, see convertInt32ToDouble.
+    zeroDouble(output);
+
+    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);
+    store64(Imm64(add_constant_u64), Address(esp, 0));
+
+    fld(Operand(esp, 0));
+    faddp();
+    bind(&notNegative);
+
+    fstp32(Operand(esp, 0));
+    vmovss(Address(esp, 0), output);
+    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
@@ -3225,21 +3225,21 @@ class BaseCompiler
 # else
         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
 # endif
         return true;
     }
 #endif // FLOAT_TO_I64_CALLOUT
 
 #ifndef I64_TO_FLOAT_CALLOUT
-    bool convertI64ToFloatNeedsTemp(bool isUnsigned) const {
+    bool convertI64ToFloatNeedsTemp(ValType to, bool isUnsigned) const {
 # if defined(JS_CODEGEN_X86)
-        return isUnsigned && AssemblerX86Shared::HasSSE3();
+        return to == ValType::F64 && isUnsigned && AssemblerX86Shared::HasSSE3();
 # else
-        return false;
+        return isUnsigned;
 # endif
     }
 
     void convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest, RegI32 temp) {
 # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
         if (isUnsigned)
             masm.convertUInt64ToFloat32(src, dest, temp);
         else
@@ -5019,17 +5019,17 @@ BaseCompiler::emitConvertI64ToF32()
 }
 
 void
 BaseCompiler::emitConvertU64ToF32()
 {
     RegI64 r0 = popI64();
     RegF32 f0 = needF32();
     RegI32 temp;
-    if (convertI64ToFloatNeedsTemp(IsUnsigned(true)))
+    if (convertI64ToFloatNeedsTemp(ValType::F32, IsUnsigned(true)))
         temp = needI32();
     convertI64ToF32(r0, IsUnsigned(true), f0, temp);
     if (temp != Register::Invalid())
         freeI32(temp);
     freeI64(r0);
     pushF32(f0);
 }
 #endif
@@ -5076,17 +5076,17 @@ BaseCompiler::emitConvertI64ToF64()
 }
 
 void
 BaseCompiler::emitConvertU64ToF64()
 {
     RegI64 r0 = popI64();
     RegF64 d0 = needF64();
     RegI32 temp;
-    if (convertI64ToFloatNeedsTemp(IsUnsigned(true)))
+    if (convertI64ToFloatNeedsTemp(ValType::F64, IsUnsigned(true)))
         temp = needI32();
     convertI64ToF64(r0, IsUnsigned(true), d0, temp);
     if (temp != Register::Invalid())
         freeI32(temp);
     freeI64(r0);
     pushF64(d0);
 }
 #endif // I64_TO_FLOAT_CALLOUT
@@ -5966,31 +5966,25 @@ BaseCompiler::emitConvertInt64ToFloating
 
     masm.setupUnalignedABICall(temp);
 # ifdef JS_NUNBOX32
     masm.passABIArg(input.high);
     masm.passABIArg(input.low);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitConvertInt64ToFloatingCallout");
 # endif
-    masm.callWithABI(callee, MoveOp::DOUBLE);
+    masm.callWithABI(callee, resultType == ValType::F32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
 
     freeI32(temp);
     freeI64(input);
 
-    RegF64 rv = captureReturnedF64(call);
-
-    if (resultType == ValType::F32) {
-        RegF32 rv2 = needF32();
-        masm.convertDoubleToFloat32(rv, rv2);
-        freeF64(rv);
-        pushF32(rv2);
-    } else {
-        pushF64(rv);
-    }
+    if (resultType == ValType::F32)
+        pushF32(captureReturnedF32(call));
+    else
+        pushF64(captureReturnedF64(call));
 
     return true;
 }
 #endif // I64_TO_FLOAT_CALLOUT
 
 #ifdef FLOAT_TO_I64_CALLOUT
 // `Callee` always takes a double, so a float32 input must be converted.
 bool
@@ -7115,25 +7109,25 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitConversion(emitConvertF64ToF32, ValType::F64, ValType::F32));
           case uint16_t(Op::F32ConvertSI32):
             CHECK_NEXT(emitConversion(emitConvertI32ToF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32ConvertUI32):
             CHECK_NEXT(emitConversion(emitConvertU32ToF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32ConvertSI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Int64ToFloatingPoint,
+                                                SymbolicAddress::Int64ToFloat32,
                                                 ValType::I64, ValType::F32));
 #else
             CHECK_NEXT(emitConversion(emitConvertI64ToF32, ValType::I64, ValType::F32));
 #endif
           case uint16_t(Op::F32ConvertUI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Uint64ToFloatingPoint,
+                                                SymbolicAddress::Uint64ToFloat32,
                                                 ValType::I64, ValType::F32));
 #else
             CHECK_NEXT(emitConversion(emitConvertU64ToF32, ValType::I64, ValType::F32));
 #endif
           case uint16_t(Op::F32ReinterpretI32):
             CHECK_NEXT(emitConversion(emitReinterpretI32AsF32, ValType::I32, ValType::F32));
           case uint16_t(Op::F32Load):
             CHECK_NEXT(emitLoad(ValType::F32, Scalar::Float32));
@@ -7180,25 +7174,25 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitConversion(emitConvertF32ToF64, ValType::F32, ValType::F64));
           case uint16_t(Op::F64ConvertSI32):
             CHECK_NEXT(emitConversion(emitConvertI32ToF64, ValType::I32, ValType::F64));
           case uint16_t(Op::F64ConvertUI32):
             CHECK_NEXT(emitConversion(emitConvertU32ToF64, ValType::I32, ValType::F64));
           case uint16_t(Op::F64ConvertSI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Int64ToFloatingPoint,
+                                                SymbolicAddress::Int64ToDouble,
                                                 ValType::I64, ValType::F64));
 #else
             CHECK_NEXT(emitConversion(emitConvertI64ToF64, ValType::I64, ValType::F64));
 #endif
           case uint16_t(Op::F64ConvertUI64):
 #ifdef I64_TO_FLOAT_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
-                                                SymbolicAddress::Uint64ToFloatingPoint,
+                                                SymbolicAddress::Uint64ToDouble,
                                                 ValType::I64, ValType::F64));
 #else
             CHECK_NEXT(emitConversion(emitConvertU64ToF64, ValType::I64, ValType::F64));
 #endif
           case uint16_t(Op::F64Load):
             CHECK_NEXT(emitLoad(ValType::F64, Scalar::Float64));
           case uint16_t(Op::F64Store):
             CHECK_NEXT(emitStore(ValType::F64, Scalar::Float64));
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -336,29 +336,43 @@ TruncateDoubleToUint64(double input)
     // Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1.
     // Therefore also sending the failure value.
     if (input >= double(UINT64_MAX) || input <= -1.0 || IsNaN(input))
         return 0x8000000000000000;
     return uint64_t(input);
 }
 
 static double
-Int64ToFloatingPoint(int32_t x_hi, uint32_t x_lo)
+Int64ToDouble(int32_t x_hi, uint32_t x_lo)
 {
     int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
     return double(x);
 }
 
+static float
+Int64ToFloat32(int32_t x_hi, uint32_t x_lo)
+{
+    int64_t x = int64_t((uint64_t(x_hi) << 32)) + int64_t(x_lo);
+    return float(x);
+}
+
 static double
-Uint64ToFloatingPoint(int32_t x_hi, uint32_t x_lo)
+Uint64ToDouble(int32_t x_hi, uint32_t x_lo)
 {
     uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
     return double(x);
 }
 
+static float
+Uint64ToFloat32(int32_t x_hi, uint32_t x_lo)
+{
+    uint64_t x = (uint64_t(x_hi) << 32) + uint64_t(x_lo);
+    return float(x);
+}
+
 template <class F>
 static inline void*
 FuncCast(F* pf, ABIFunctionType type)
 {
     void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
 #ifdef JS_SIMULATOR
     pv = Simulator::RedirectNativeFunction(pv, type);
 #endif
@@ -406,20 +420,24 @@ wasm::AddressOf(SymbolicAddress imm, JSC
       case SymbolicAddress::ModI64:
         return FuncCast(ModI64, Args_General4);
       case SymbolicAddress::UModI64:
         return FuncCast(UModI64, Args_General4);
       case SymbolicAddress::TruncateDoubleToUint64:
         return FuncCast(TruncateDoubleToUint64, Args_Int64_Double);
       case SymbolicAddress::TruncateDoubleToInt64:
         return FuncCast(TruncateDoubleToInt64, Args_Int64_Double);
-      case SymbolicAddress::Uint64ToFloatingPoint:
-        return FuncCast(Uint64ToFloatingPoint, Args_Double_IntInt);
-      case SymbolicAddress::Int64ToFloatingPoint:
-        return FuncCast(Int64ToFloatingPoint, Args_Double_IntInt);
+      case SymbolicAddress::Uint64ToDouble:
+        return FuncCast(Uint64ToDouble, Args_Double_IntInt);
+      case SymbolicAddress::Uint64ToFloat32:
+        return FuncCast(Uint64ToFloat32, Args_Float32_IntInt);
+      case SymbolicAddress::Int64ToDouble:
+        return FuncCast(Int64ToDouble, Args_Double_IntInt);
+      case SymbolicAddress::Int64ToFloat32:
+        return FuncCast(Int64ToFloat32, Args_Float32_IntInt);
 #if defined(JS_CODEGEN_ARM)
       case SymbolicAddress::aeabi_idivmod:
         return FuncCast(__aeabi_idivmod, Args_General2);
       case SymbolicAddress::aeabi_uidivmod:
         return FuncCast(__aeabi_uidivmod, Args_General2);
       case SymbolicAddress::AtomicCmpXchg:
         return FuncCast(atomics_cmpxchg_asm_callout, Args_General5);
       case SymbolicAddress::AtomicXchg:
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1030,18 +1030,20 @@ enum class SymbolicAddress
     CoerceInPlace_ToInt32,
     CoerceInPlace_ToNumber,
     DivI64,
     UDivI64,
     ModI64,
     UModI64,
     TruncateDoubleToInt64,
     TruncateDoubleToUint64,
-    Uint64ToFloatingPoint,
-    Int64ToFloatingPoint,
+    Uint64ToFloat32,
+    Uint64ToDouble,
+    Int64ToFloat32,
+    Int64ToDouble,
     GrowMemory,
     CurrentMemory,
     Limit
 };
 
 void*
 AddressOf(SymbolicAddress imm, JSContext* cx);
 
deleted file mode 100644
--- a/testing/web-platform/mozilla/meta/wasm/conversions.wast.js.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[conversions.wast.js.html]
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1336139
-  type: testharness
-  [#499 A wast test that runs without any special assertion.]
-    expected: FAIL
-
-  [#505 A wast test that runs without any special assertion.]
-    expected: FAIL
-