Bug 1252432 part 4 - Implement wasm {f32,f64}.convert_{u,s}/i64 on x64. r=sunfish
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 15 Mar 2016 14:37:14 +0100
changeset 288775 c1c767f1d938c77905642365198c4f48fdcf022f
parent 288774 4e3b9f88ef1a80c037e50d1ebf89f33452d514a9
child 288776 7f8a1c681597d1f1cfcc33fe47dcf59aff04b924
push id30089
push userkwierso@gmail.com
push dateWed, 16 Mar 2016 00:26:08 +0000
treeherdermozilla-central@7773387a9a2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1252432
milestone48.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 1252432 part 4 - Implement wasm {f32,f64}.convert_{u,s}/i64 on x64. r=sunfish
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmIonCompile.cpp
js/src/asmjs/WasmTextToBinary.cpp
js/src/jit-test/tests/wasm/basic-conversion.js
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/arm/Lowering-arm.h
js/src/jit/arm64/Lowering-arm64.cpp
js/src/jit/arm64/Lowering-arm64.h
js/src/jit/mips-shared/Lowering-mips-shared.cpp
js/src/jit/mips-shared/Lowering-mips-shared.h
js/src/jit/none/Lowering-none.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/CodeGenerator-x64.h
js/src/jit/x64/LIR-x64.h
js/src/jit/x64/LOpcodes-x64.h
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x64/Lowering-x64.h
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/Lowering-x86.h
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -786,28 +786,27 @@ DecodeExpr(FunctionDecoder& f, ExprType*
         return f.fail("NYI: i64");
       case Expr::F32ConvertSI32:
       case Expr::F32ConvertUI32:
         return DecodeConversionOperator(f, ValType::F32, ValType::I32, type);
       case Expr::F32ReinterpretI32:
         return f.fail("NYI: reinterpret");
       case Expr::F32ConvertSI64:
       case Expr::F32ConvertUI64:
-        return f.fail("NYI: i64") &&
-               DecodeConversionOperator(f, ValType::F32, ValType::I64, type);
+        return DecodeConversionOperator(f, ValType::F32, ValType::I64, type);
       case Expr::F32DemoteF64:
         return DecodeConversionOperator(f, ValType::F32, ValType::F64, type);
       case Expr::F64ConvertSI32:
       case Expr::F64ConvertUI32:
         return DecodeConversionOperator(f, ValType::F64, ValType::I32, type);
       case Expr::F64ConvertSI64:
       case Expr::F64ConvertUI64:
+        return DecodeConversionOperator(f, ValType::F64, ValType::I64, type);
       case Expr::F64ReinterpretI64:
-        return f.fail("NYI: i64") &&
-               DecodeConversionOperator(f, ValType::F64, ValType::I64, type);
+        return f.fail("NYI: i64");
       case Expr::F64PromoteF32:
         return DecodeConversionOperator(f, ValType::F64, ValType::F32, type);
       case Expr::I32Load8S:
       case Expr::I32Load8U:
         return DecodeLoad(f, 1, ValType::I32, type);
       case Expr::I32Load16S:
       case Expr::I32Load16U:
         return DecodeLoad(f, 2, ValType::I32, type);
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -462,16 +462,25 @@ class FunctionCompiler
     {
         if (inDeadCode())
             return nullptr;
         MExtendInt32ToInt64* ins = MExtendInt32ToInt64::NewAsmJS(alloc(), op, isUnsigned);
         curBlock_->add(ins);
         return ins;
     }
 
+    MDefinition* convertI64ToFloatingPoint(MDefinition* op, MIRType type, bool isUnsigned)
+    {
+        if (inDeadCode())
+            return nullptr;
+        MInt64ToFloatingPoint* ins = MInt64ToFloatingPoint::NewAsmJS(alloc(), op, type, isUnsigned);
+        curBlock_->add(ins);
+        return ins;
+    }
+
     template <class T>
     MDefinition* truncate(MDefinition* op, bool isUnsigned)
     {
         if (inDeadCode())
             return nullptr;
         T* ins = T::NewAsmJS(alloc(), op, isUnsigned);
         curBlock_->add(ins);
         return ins;
@@ -2386,16 +2395,27 @@ EmitTruncate(FunctionCompiler& f, bool i
     MDefinition* in;
     if (!EmitExpr(f, &in))
         return false;
     *def = f.truncate<T>(in, isUnsigned);
     return true;
 }
 
 static bool
+EmitConvertI64ToFloatingPoint(FunctionCompiler& f, ValType type, bool isUnsigned,
+                              MDefinition** def)
+{
+    MDefinition* in;
+    if (!EmitExpr(f, &in))
+        return false;
+    *def = f.convertI64ToFloatingPoint(in, ToMIRType(type), isUnsigned);
+    return true;
+}
+
+static bool
 EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign, MDefinition** def)
 {
     switch (op) {
       case SimdOperation::Constructor:
         return EmitSimdCtor(f, type, def);
       case SimdOperation::Fn_extractLane:
         return EmitExtractLane(f, type, sign, def);
       case SimdOperation::Fn_replaceLane:
@@ -2894,16 +2914,20 @@ EmitExpr(FunctionCompiler& f, MDefinitio
       case Expr::F32Floor:
         return EmitF32MathBuiltinCall(f, exprOffset, op, def);
       case Expr::F32DemoteF64:
         return EmitUnary<MToFloat32>(f, def);
       case Expr::F32ConvertSI32:
         return EmitUnary<MToFloat32>(f, def);
       case Expr::F32ConvertUI32:
         return EmitUnary<MAsmJSUnsignedToFloat32>(f, def);
+      case Expr::F32ConvertSI64:
+      case Expr::F32ConvertUI64:
+        return EmitConvertI64ToFloatingPoint(f, ValType::F32,
+                                             IsUnsigned(op == Expr::F32ConvertUI64), def);
       case Expr::F32Load:
         return EmitLoad(f, Scalar::Float32, def);
       case Expr::F32Store:
         return EmitStore(f, Scalar::Float32, def);
       case Expr::F32StoreF64:
         return EmitStoreWithCoercion(f, Scalar::Float32, Scalar::Float64, def);
 
       // F64
@@ -2943,16 +2967,20 @@ EmitExpr(FunctionCompiler& f, MDefinitio
       case Expr::F64Atan2:
         return EmitF64MathBuiltinCall(f, exprOffset, op, def);
       case Expr::F64PromoteF32:
         return EmitUnary<MToDouble>(f, def);
       case Expr::F64ConvertSI32:
         return EmitUnary<MToDouble>(f, def);
       case Expr::F64ConvertUI32:
         return EmitUnary<MAsmJSUnsignedToDouble>(f, def);
+      case Expr::F64ConvertSI64:
+      case Expr::F64ConvertUI64:
+        return EmitConvertI64ToFloatingPoint(f, ValType::F64,
+                                             IsUnsigned(op == Expr::F64ConvertUI64), def);
       case Expr::F64Load:
         return EmitLoad(f, Scalar::Float64, def);
       case Expr::F64Store:
         return EmitStore(f, Scalar::Float64, def);
       case Expr::F64StoreF32:
         return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def);
 
       // SIMD
@@ -3018,20 +3046,16 @@ EmitExpr(FunctionCompiler& f, MDefinitio
       // Future opcodes
       case Expr::Select:
       case Expr::F32CopySign:
       case Expr::F32Trunc:
       case Expr::F32Nearest:
       case Expr::F64CopySign:
       case Expr::F64Nearest:
       case Expr::F64Trunc:
-      case Expr::F32ConvertSI64:
-      case Expr::F32ConvertUI64:
-      case Expr::F64ConvertSI64:
-      case Expr::F64ConvertUI64:
       case Expr::I64ReinterpretF64:
       case Expr::F64ReinterpretI64:
       case Expr::I32ReinterpretF32:
       case Expr::F32ReinterpretI32:
       case Expr::I64Load8S:
       case Expr::I64Load16S:
       case Expr::I64Load32S:
       case Expr::I64Load8U:
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -1426,22 +1426,32 @@ WasmTokenStream::next()
                 if (consume(MOZ_UTF16("add")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::F32Add, begin, cur_);
                 break;
               case 'c':
                 if (consume(MOZ_UTF16("ceil")))
                     return WasmToken(WasmToken::UnaryOpcode, Expr::F32Ceil, begin, cur_);
                 if (consume(MOZ_UTF16("const")))
                     return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
-                if (consume(MOZ_UTF16("convert_s/i32")))
+                if (consume(MOZ_UTF16("convert_s/i32"))) {
                     return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertSI32,
                                      begin, cur_);
-                if (consume(MOZ_UTF16("convert_u/i32")))
+                }
+                if (consume(MOZ_UTF16("convert_u/i32"))) {
                     return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertUI32,
                                      begin, cur_);
+                }
+                if (consume(MOZ_UTF16("convert_s/i64"))) {
+                    return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertSI64,
+                                     begin, cur_);
+                }
+                if (consume(MOZ_UTF16("convert_u/i64"))) {
+                    return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertUI64,
+                                     begin, cur_);
+                }
                 if (consume(MOZ_UTF16("copysign")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::F32CopySign, begin, cur_);
                 break;
               case 'd':
                 if (consume(MOZ_UTF16("demote/f64")))
                     return WasmToken(WasmToken::ConversionOpcode, Expr::F32DemoteF64,
                                      begin, cur_);
                 if (consume(MOZ_UTF16("div")))
@@ -1516,22 +1526,32 @@ WasmTokenStream::next()
                 if (consume(MOZ_UTF16("add")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::F64Add, begin, cur_);
                 break;
               case 'c':
                 if (consume(MOZ_UTF16("ceil")))
                     return WasmToken(WasmToken::UnaryOpcode, Expr::F64Ceil, begin, cur_);
                 if (consume(MOZ_UTF16("const")))
                     return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
-                if (consume(MOZ_UTF16("convert_s/i32")))
+                if (consume(MOZ_UTF16("convert_s/i32"))) {
                     return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertSI32,
                                      begin, cur_);
-                if (consume(MOZ_UTF16("convert_u/i32")))
+                }
+                if (consume(MOZ_UTF16("convert_u/i32"))) {
                     return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertUI32,
                                      begin, cur_);
+                }
+                if (consume(MOZ_UTF16("convert_s/i64"))) {
+                    return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertSI64,
+                                     begin, cur_);
+                }
+                if (consume(MOZ_UTF16("convert_u/i64"))) {
+                    return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertUI64,
+                                     begin, cur_);
+                }
                 if (consume(MOZ_UTF16("copysign")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::F64CopySign, begin, cur_);
                 break;
               case 'd':
                 if (consume(MOZ_UTF16("div")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::F64Div, begin, cur_);
                 break;
               case 'e':
--- a/js/src/jit-test/tests/wasm/basic-conversion.js
+++ b/js/src/jit-test/tests/wasm/basic-conversion.js
@@ -60,16 +60,44 @@ if (getBuildConfiguration().x64) {
 
     testConversion('i64', 'extend_u', 'i32', 0, 0);
     testConversion('i64', 'extend_u', 'i32', 1234, 1234);
     testConversion('i64', 'extend_u', 'i32', -567, "0x00000000fffffdc9");
     testConversion('i64', 'extend_u', 'i32', -1, "0x00000000ffffffff");
     testConversion('i64', 'extend_u', 'i32', 0x7fffffff, "0x000000007fffffff");
     testConversion('i64', 'extend_u', 'i32', 0x80000000, "0x0000000080000000");
 
+    testConversion('f32', 'convert_s', 'i64', 1, 1.0);
+    testConversion('f32', 'convert_s', 'i64', -1, -1.0);
+    testConversion('f32', 'convert_s', 'i64', 0, 0.0);
+    testConversion('f32', 'convert_s', 'i64', "9223372036854775807", 9223372036854775807.0);
+    testConversion('f32', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
+    testConversion('f32', 'convert_s', 'i64', "314159265358979", 314159275180032.0);
+
+    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', "9223372036854775807", 9223372036854775807.0);
+    testConversion('f64', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
+    testConversion('f64', 'convert_s', 'i64', "4669201609102990", 4669201609102990);
+
+    testConversion('f32', 'convert_u', 'i64', 1, 1.0);
+    testConversion('f32', 'convert_u', 'i64', 0, 0.0);
+    testConversion('f32', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
+    testConversion('f32', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+    testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
+    testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
+
+    testConversion('f64', 'convert_u', 'i64', 1, 1.0);
+    testConversion('f64', 'convert_u', 'i64', 0, 0.0);
+    testConversion('f64', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
+    testConversion('f64', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+    testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
+    testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
+
     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);
     testConversion('i64', 'trunc_s', 'f64', -1.0, -1);
@@ -161,27 +189,19 @@ if (getBuildConfiguration().x64) {
 }
 
 testConversion('i32', 'trunc_s', 'f32', 40.1, 40);
 testConversion('i32', 'trunc_u', 'f32', 40.1, 40);
 testConversion('i32', 'trunc_s', 'f64', 40.1, 40);
 testConversion('i32', 'trunc_u', 'f64', 40.1, 40);
 //testConversion('i32', 'reinterpret', 'f32', 40.1, 1109419622); // TODO: NYI
 
-//testConversion('i64', 'trunc_s', 'f32', 40.1, 40); // TODO: NYI
-//testConversion('i64', 'trunc_u', 'f32', 40.1, 40); // TODO: NYI
-//testConversion('i64', 'trunc_s', 'f64', 40.1, 40); // TODO: NYI
-//testConversion('i64', 'trunc_u', 'f64', 40.1, 40); // TODO: NYI
 //testConversion('i64', 'reinterpret', 'f64', 40.1, 1109419622); // TODO: NYI
 
 testConversion('f32', 'convert_s', 'i32', 40, 40);
 testConversion('f32', 'convert_u', 'i32', 40, 40);
-//testConversion('f32', 'convert_s', 'i64', 40, 40); // TODO: NYI
-//testConversion('f32', 'convert_u', 'i64', 40, 40); // TODO: NYI
 testConversion('f32', 'demote', 'f64', 40.1, 40.099998474121094);
 //testConversion('f32', 'reinterpret', 'i32', 40, 5.605193857299268e-44); // TODO: NYI
 
 testConversion('f64', 'convert_s', 'i32', 40, 40);
 testConversion('f64', 'convert_u', 'i32', 40, 40);
-//testConversion('f64', 'convert_s', 'i64', 40, 40); // TODO: NYI
-//testConversion('f64', 'convert_u', 'i64', 40, 40); // TODO: NYI
 testConversion('f64', 'promote', 'f32', 40.1, 40.099998474121094);
 //testConversion('f64', 'reinterpret', 'i64', 40.1, 4630840390592548045); // TODO: NYI
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5336,16 +5336,53 @@ class MTruncateToInt64
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
+class MInt64ToFloatingPoint
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isUnsigned_;
+
+    MInt64ToFloatingPoint(MDefinition* def, MIRType type, bool isUnsigned)
+      : MUnaryInstruction(def),
+        isUnsigned_(isUnsigned)
+    {
+        MOZ_ASSERT(IsFloatingPointType(type));
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Int64ToFloatingPoint)
+    static MInt64ToFloatingPoint* NewAsmJS(TempAllocator& alloc, MDefinition* def, MIRType type,
+                                           bool isUnsigned)
+    {
+        return new(alloc) MInt64ToFloatingPoint(def, type, isUnsigned);
+    }
+
+    bool isUnsigned() const { return isUnsigned_; }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isInt64ToFloatingPoint())
+            return false;
+        if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_)
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
 // Converts a primitive (either typed or untyped) to an int32. If the input is
 // not primitive at runtime, a bailout occurs. If the input cannot be converted
 // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
 class MToInt32
   : public MUnaryInstruction,
     public ToInt32Policy::Data
 {
     bool canBeNegativeZero_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -116,16 +116,17 @@ namespace jit {
     _(AssertRange)                                                          \
     _(ToDouble)                                                             \
     _(ToFloat32)                                                            \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
     _(TruncateToInt64)                                                      \
     _(WrapInt64ToInt32)                                                     \
     _(ExtendInt32ToInt64)                                                   \
+    _(Int64ToFloatingPoint)                                                 \
     _(ToString)                                                             \
     _(ToObjectOrNull)                                                       \
     _(NewArray)                                                             \
     _(NewArrayCopyOnWrite)                                                  \
     _(NewArrayDynamicLength)                                                \
     _(NewObject)                                                            \
     _(NewTypedObject)                                                       \
     _(NewDeclEnvObject)                                                     \
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -781,8 +781,14 @@ LIRGeneratorARM::visitRandom(MRandom* in
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
 LIRGeneratorARM::visitTruncateToInt64(MTruncateToInt64* ins)
 {
     MOZ_CRASH("NY");
 }
+
+void
+LIRGeneratorARM::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+{
+    MOZ_CRASH("NY");
+}
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -108,16 +108,17 @@ class LIRGeneratorARM : public LIRGenera
     void visitSimdSplatX4(MSimdSplatX4* ins);
     void visitSimdValueX4(MSimdValueX4* ins);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
     void visitSubstr(MSubstr* ins);
     void visitRandom(MRandom* ins);
     void visitTruncateToInt64(MTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 typedef LIRGeneratorARM LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_Lowering_arm_h */
--- a/js/src/jit/arm64/Lowering-arm64.cpp
+++ b/js/src/jit/arm64/Lowering-arm64.cpp
@@ -336,8 +336,14 @@ LIRGeneratorARM64::visitRandom(MRandom* 
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
 LIRGeneratorARM64::visitTruncateToInt64(MTruncateToInt64* ins)
 {
     MOZ_CRASH("NY");
 }
+
+void
+LIRGeneratorARM64::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+{
+    MOZ_CRASH("NY");
+}
--- a/js/src/jit/arm64/Lowering-arm64.h
+++ b/js/src/jit/arm64/Lowering-arm64.h
@@ -111,16 +111,17 @@ class LIRGeneratorARM64 : public LIRGene
     void visitSimdSplatX4(MSimdSplatX4* ins);
     void visitSimdValueX4(MSimdValueX4* ins);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
     void visitSubstr(MSubstr* ins);
     void visitRandom(MRandom* ins);
     void visitTruncateToInt64(MTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 typedef LIRGeneratorARM64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm64_Lowering_arm64_h */
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -582,8 +582,14 @@ LIRGeneratorMIPSShared::visitAtomicTyped
     define(lir, ins);
 }
 
 void
 LIRGeneratorMIPSShared::visitTruncateToInt64(MTruncateToInt64* ins)
 {
     MOZ_CRASH("NY");
 }
+
+void
+LIRGeneratorMIPSShared::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+{
+    MOZ_CRASH("NY");
+}
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -92,14 +92,15 @@ class LIRGeneratorMIPSShared : public LI
     void visitSimdSelect(MSimdSelect* ins);
     void visitSimdSplatX4(MSimdSplatX4* ins);
     void visitSimdValueX4(MSimdValueX4* ins);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
     void visitSubstr(MSubstr* ins);
     void visitTruncateToInt64(MTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips_shared_Lowering_mips_shared_h */
--- a/js/src/jit/none/Lowering-none.h
+++ b/js/src/jit/none/Lowering-none.h
@@ -90,16 +90,17 @@ class LIRGeneratorNone : public LIRGener
     LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
     void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); }
     void visitSimdSplatX4(MSimdSplatX4* ins) { MOZ_CRASH(); }
     void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); }
     void visitSubstr(MSubstr*) { MOZ_CRASH(); }
     void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
     void visitRandom(js::jit::MRandom*) { MOZ_CRASH(); }
     void visitTruncateToInt64(MTruncateToInt64*) { MOZ_CRASH(); }
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint*) { MOZ_CRASH(); }
 };
 
 typedef LIRGeneratorNone LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_none_Lowering_none_h */
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -1115,25 +1115,24 @@ CodeGeneratorX64::visitExtendInt32ToInt6
 
 void
 CodeGeneratorX64::visitTruncateToInt64(LTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
 
     MIRType inputType = lir->mir()->input()->type();
-    bool isUnsigned = lir->mir()->isUnsigned();
 
     // We should trap on invalid inputs, but for now we just return
     // 0x8000000000000000. Note that we can remove some unnecessary jumps
     // once we get rid of this trap Label.
     Label trap;
 
     Label done;
-    if (isUnsigned) {
+    if (lir->mir()->isUnsigned()) {
         FloatRegister tempDouble = ToFloatRegister(lir->temp());
 
         // 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.
         if (inputType == MIRType_Double) {
             Label isLarge;
             masm.loadConstantDouble(double(0x8000000000000000), ScratchDoubleReg);
@@ -1182,8 +1181,62 @@ CodeGeneratorX64::visitTruncateToInt64(L
         }
     }
 
     masm.bind(&trap);
     masm.movePtr(ImmWord(0x8000000000000000), output);
 
     masm.bind(&done);
 }
+
+void
+CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
+{
+    Register input = ToRegister(lir->input());
+    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);
+
+    Label done;
+    if (lir->mir()->isUnsigned()) {
+        // If the input is unsigned, we use cvtsq2sd or vcvtsq2ss directly.
+        // Else, we divide by 2, convert to double or float, and multiply the
+        // result by 2.
+        if (outputType == MIRType_Double) {
+            Label isSigned;
+            masm.branchTestPtr(Assembler::Signed, input, input, &isSigned);
+            masm.vcvtsq2sd(input, output, output);
+            masm.jump(&done);
+
+            masm.bind(&isSigned);
+            ScratchRegisterScope scratch(masm);
+            masm.mov(input, scratch);
+            masm.rshiftPtr(Imm32(1), scratch);
+            masm.vcvtsq2sd(scratch, output, output);
+            masm.vaddsd(output, output, output);
+        } else {
+            Label isSigned;
+            masm.branchTestPtr(Assembler::Signed, input, input, &isSigned);
+            masm.vcvtsq2ss(input, output, output);
+            masm.jump(&done);
+
+            masm.bind(&isSigned);
+            ScratchRegisterScope scratch(masm);
+            masm.mov(input, scratch);
+            masm.rshiftPtr(Imm32(1), scratch);
+            masm.vcvtsq2ss(scratch, output, output);
+            masm.vaddss(output, output, output);
+        }
+    } else {
+        if (outputType == MIRType_Double)
+            masm.vcvtsq2sd(input, output, output);
+        else
+            masm.vcvtsq2ss(input, output, output);
+    }
+    masm.bind(&done);
+}
--- a/js/src/jit/x64/CodeGenerator-x64.h
+++ b/js/src/jit/x64/CodeGenerator-x64.h
@@ -51,16 +51,17 @@ class CodeGeneratorX64 : public CodeGene
     void visitMulI64(LMulI64* lir);
     void visitDivOrModI64(LDivOrModI64* lir);
     void visitUDivOrMod64(LUDivOrMod64* lir);
     void visitTruncateDToInt32(LTruncateDToInt32* ins);
     void visitTruncateFToInt32(LTruncateFToInt32* ins);
     void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
     void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
     void visitTruncateToInt64(LTruncateToInt64* lir);
+    void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir);
     void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
     void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
     void visitAsmJSCall(LAsmJSCall* ins);
     void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
     void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
     void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
     void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins);
     void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
--- a/js/src/jit/x64/LIR-x64.h
+++ b/js/src/jit/x64/LIR-x64.h
@@ -178,12 +178,30 @@ class LTruncateToInt64 : public LInstruc
         return mir_->toTruncateToInt64();
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
+class LInt64ToFloatingPoint : public LInstructionHelper<1, INT64_PIECES, 0>
+{
+  public:
+    LIR_HEADER(Int64ToFloatingPoint);
+
+    explicit LInt64ToFloatingPoint(const LInt64Allocation& in) {
+        setInt64Operand(0, in);
+    }
+
+    MInt64ToFloatingPoint* mir() const {
+        return mir_->toInt64ToFloatingPoint();
+    }
+
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_LIR_x64_h */
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -9,14 +9,15 @@
 
 #include "jit/shared/LOpcodes-shared.h"
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(DivOrModConstantI)            \
     _(DivOrModI64)                  \
     _(UDivOrMod64)                  \
     _(TruncateToInt64)              \
+    _(Int64ToFloatingPoint)         \
     _(SimdValueInt32x4)             \
     _(SimdValueFloat32x4)           \
     _(UDivOrMod)                    \
     _(UDivOrModConstant)
 
 #endif /* jit_x64_LOpcodes_x64_h */
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -390,8 +390,18 @@ void
 LIRGeneratorX64::visitTruncateToInt64(MTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType_Double || opd->type() == MIRType_Float32);
 
     LDefinition maybeTemp = ins->isUnsigned() ? tempDouble() : LDefinition::BogusTemp();
     defineInt64(new(alloc()) LTruncateToInt64(useRegister(opd), maybeTemp), ins);
 }
+
+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)), ins);
+}
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -55,16 +55,17 @@ class LIRGeneratorX64 : public LIRGenera
     void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins);
     void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins);
     void visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins);
     void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins);
     void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
     void visitSubstr(MSubstr* ins);
     void visitRandom(MRandom* ins);
     void visitTruncateToInt64(MTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
 };
 
 typedef LIRGeneratorX64 LIRGeneratorSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_Lowering_x64_h */
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -459,8 +459,14 @@ LIRGeneratorX86::visitRandom(MRandom* in
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
 LIRGeneratorX86::visitTruncateToInt64(MTruncateToInt64* ins)
 {
     MOZ_CRASH("NY");
 }
+
+void
+LIRGeneratorX86::visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins)
+{
+    MOZ_CRASH("NY");
+}
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -59,16 +59,17 @@ class LIRGeneratorX86 : public LIRGenera
     void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins);
     void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins);
     void visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins);
     void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins);
     void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins);
     void visitSubstr(MSubstr* ins);
     void visitRandom(MRandom* ins);
     void visitTruncateToInt64(MTruncateToInt64* ins);
+    void visitInt64ToFloatingPoint(MInt64ToFloatingPoint* ins);
     void lowerPhi(MPhi* phi);
 
     static bool allowTypedElementHoleCheck() {
         return true;
     }
 
     static bool allowStaticTypedArrayAccesses() {
         return true;