Bug 1232205 - Wasm baseline: Factor out int64ToFloatingPoint and truncateToInt64, on x64. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Wed, 08 Jun 2016 12:17:17 +0200
changeset 301771 5b8a3144277a729820c941b31ca65ca29fec34aa
parent 301770 5d7856a5357f3caed90111a198406634031886d7
child 301772 6653d66ac84936566aee9d33360ca86f0dace319
push id30341
push usercbook@mozilla.com
push dateWed, 15 Jun 2016 05:24:50 +0000
treeherdermozilla-central@14c5bf11d37b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1232205
milestone50.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 1232205 - Wasm baseline: Factor out int64ToFloatingPoint and truncateToInt64, on x64. r=bbouvier
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -1198,67 +1198,33 @@ void
 CodeGeneratorX64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
 
     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);
 
-    if (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);
-            masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg, &isLarge);
-            masm.vcvttsd2sq(input, output);
-            masm.branchTestPtr(Assembler::Signed, output, output, ool->entry());
-            masm.jump(ool->rejoin());
-
-            masm.bind(&isLarge);
-            masm.moveDouble(input, tempDouble);
-            masm.subDouble(ScratchDoubleReg, tempDouble);
-            masm.vcvttsd2sq(tempDouble, output);
-            masm.branchTestPtr(Assembler::Signed, output, output, ool->entry());
-            masm.or64(Imm64(0x8000000000000000), Register64(output));
-        } else {
-            MOZ_ASSERT(inputType == MIRType::Float32);
+    FloatRegister temp = mir->isUnsigned() ? ToFloatRegister(lir->temp()) : InvalidFloatReg;
 
-            Label isLarge;
-            masm.loadConstantFloat32(float(0x8000000000000000), ScratchDoubleReg);
-            masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, input, ScratchDoubleReg, &isLarge);
-            masm.vcvttss2sq(input, output);
-            masm.branchTestPtr(Assembler::Signed, output, output, ool->entry());
-            masm.jump(ool->rejoin());
-
-            masm.bind(&isLarge);
-            masm.moveFloat32(input, tempDouble);
-            masm.vsubss(ScratchDoubleReg, tempDouble, tempDouble);
-            masm.vcvttss2sq(tempDouble, output);
-            masm.branchTestPtr(Assembler::Signed, output, output, ool->entry());
-            masm.or64(Imm64(0x8000000000000000), Register64(output));
-        }
+    if (inputType == MIRType::Double) {
+        if (mir->isUnsigned())
+            masm.wasmTruncateDoubleToUInt64(input, output, ool->entry(), ool->rejoin(), temp);
+        else
+            masm.wasmTruncateDoubleToInt64(input, output, ool->entry(), ool->rejoin(), temp);
     } else {
-        if (inputType == MIRType::Double) {
-            masm.vcvttsd2sq(input, output);
-            masm.cmpq(Imm32(1), output);
-            masm.j(Assembler::Overflow, ool->entry());
-        } else {
-            MOZ_ASSERT(inputType == MIRType::Float32);
-            masm.vcvttss2sq(input, output);
-            masm.cmpq(Imm32(1), output);
-            masm.j(Assembler::Overflow, ool->entry());
-        }
+        if (mir->isUnsigned())
+            masm.wasmTruncateFloat32ToUInt64(input, output, ool->entry(), ool->rejoin(), temp);
+        else
+            masm.wasmTruncateFloat32ToInt64(input, output, ool->entry(), ool->rejoin(), temp);
     }
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGeneratorX64::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir)
 {
@@ -1296,59 +1262,27 @@ 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);
-        }
+    if (outputType == MIRType::Double) {
+        if (lir->mir()->isUnsigned())
+            masm.convertUInt64ToDouble(input, output);
+        else
+            masm.convertInt64ToDouble(input, output);
     } else {
-        if (outputType == MIRType::Double)
-            masm.vcvtsq2sd(input, output, output);
+        if (lir->mir()->isUnsigned())
+            masm.convertUInt64ToFloat32(input, output);
         else
-            masm.vcvtsq2ss(input, output, output);
+            masm.convertInt64ToFloat32(input, output);
     }
-    masm.bind(&done);
 }
 
 void
 CodeGeneratorX64::visitNotI64(LNotI64* lir)
 {
     masm.cmpq(Imm32(0), ToRegister(lir->input()));
     masm.emitSet(Assembler::Equal, ToRegister(lir->output()));
 }
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -68,16 +68,161 @@ MacroAssemblerX64::loadConstantSimd128Fl
     SimdData* val = getSimdData(v);
     if (!val)
         return;
     JmpSrc j = masm.vmovaps_ripr(dest.encoding());
     propagateOOM(val->uses.append(CodeOffset(j.offset())));
 }
 
 void
+MacroAssemblerX64::convertInt64ToDouble(Register input, FloatRegister output)
+{
+    // Zero the output register to break dependencies, see convertInt32ToDouble.
+    zeroDouble(output);
+
+    vcvtsq2sd(input, output, output);
+}
+
+void
+MacroAssemblerX64::convertInt64ToFloat32(Register input, FloatRegister output)
+{
+    // Zero the output register to break dependencies, see convertInt32ToDouble.
+    zeroFloat32(output);
+
+    vcvtsq2ss(input, output, output);
+}
+void
+MacroAssemblerX64::convertUInt64ToDouble(Register input, FloatRegister output)
+{
+    // 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.
+    Label done;
+    Label isSigned;
+
+    testq(input, input);
+    j(Assembler::Signed, &isSigned);
+    vcvtsq2sd(input, output, output);
+    jump(&done);
+
+    bind(&isSigned);
+
+    ScratchRegisterScope scratch(asMasm());
+    mov(input, scratch);
+    shrq(Imm32(1), scratch);
+    vcvtsq2sd(scratch, output, output);
+    vaddsd(output, output, output);
+
+    bind(&done);
+}
+
+void
+MacroAssemblerX64::convertUInt64ToFloat32(Register input, FloatRegister output)
+{
+    // 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.
+    Label done;
+    Label isSigned;
+
+    testq(input, input);
+    j(Assembler::Signed, &isSigned);
+    vcvtsq2ss(input, output, output);
+    jump(&done);
+
+    bind(&isSigned);
+
+    ScratchRegisterScope scratch(asMasm());
+    mov(input, scratch);
+    shrq(Imm32(1), scratch);
+    vcvtsq2ss(scratch, output, output);
+    vaddss(output, output, output);
+
+    bind(&done);
+}
+
+void
+MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register output, Label* oolEntry,
+                                             Label* oolRejoin, FloatRegister tempReg)
+{
+    vcvttsd2sq(input, output);
+    cmpq(Imm32(1), output);
+    j(Assembler::Overflow, oolEntry);
+}
+
+void
+MacroAssemblerX64::wasmTruncateFloat32ToInt64(FloatRegister input, Register output, Label* oolEntry,
+                                              Label* oolRejoin, FloatRegister tempReg)
+{
+    vcvttss2sq(input, output);
+    cmpq(Imm32(1), output);
+    j(Assembler::Overflow, oolEntry);
+}
+
+void
+MacroAssemblerX64::wasmTruncateDoubleToUInt64(FloatRegister input, Register 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);
+    j(Assembler::Signed, oolEntry);
+    jump(oolRejoin);
+
+    bind(&isLarge);
+
+    moveDouble(input, tempReg);
+    vsubsd(scratch, tempReg, tempReg);
+    vcvttsd2sq(tempReg, output);
+    testq(output, output);
+    j(Assembler::Signed, oolEntry);
+    asMasm().or64(Imm64(0x8000000000000000), Register64(output));
+}
+
+void
+MacroAssemblerX64::wasmTruncateFloat32ToUInt64(FloatRegister input, Register 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);
+    j(Assembler::Signed, oolEntry);
+    jump(oolRejoin);
+
+    bind(&isLarge);
+
+    moveFloat32(input, tempReg);
+    vsubss(scratch, tempReg, tempReg);
+    vcvttss2sq(tempReg, output);
+    testq(output, output);
+    j(Assembler::Signed, oolEntry);
+    asMasm().or64(Imm64(0x8000000000000000), Register64(output));
+}
+
+void
 MacroAssemblerX64::bindOffsets(const MacroAssemblerX86Shared::UsesVector& uses)
 {
     for (CodeOffset use : uses) {
         JmpDst dst(currentOffset());
         JmpSrc src(use.offset());
         // Using linkJump here is safe, as explaind in the comment in
         // loadConstantDouble.
         masm.linkJump(src, dst);
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -859,16 +859,33 @@ class MacroAssemblerX64 : public MacroAs
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
 
     void loadConstantDouble(double d, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
     void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
     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,
+                                   Label* oolRejoin, FloatRegister tempDouble);
+    void wasmTruncateDoubleToUInt64(FloatRegister input, Register output, Label* oolEntry,
+                                    Label* oolRejoin, FloatRegister tempDouble);
+
+    void wasmTruncateFloat32ToInt64(FloatRegister input, Register output, Label* oolEntry,
+                                    Label* oolRejoin, FloatRegister tempDouble);
+    void wasmTruncateFloat32ToUInt64(FloatRegister input, Register output, Label* oolEntry,
+                                     Label* oolRejoin, FloatRegister tempDouble);
+
+  public:
     Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
         test32(operand.valueReg(), operand.valueReg());
         return truthy ? NonZero : Zero;
     }
     Condition testStringTruthy(bool truthy, const ValueOperand& value) {
         ScratchRegisterScope scratch(asMasm());
         unboxString(value, scratch);
         cmp32(Operand(scratch, JSString::offsetOfLength()), Imm32(0));