diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h index 647b20b8595..0e7ac0cdf4b 100644 --- a/js/src/assembler/assembler/X86Assembler.h +++ b/js/src/assembler/assembler/X86Assembler.h @@ -287,6 +287,7 @@ private: OP2_XORPD_VpdWpd = 0x57, OP2_MOVD_VdEd = 0x6E, OP2_PSRLDQ_Vd = 0x73, + OP2_PCMPEQW = 0x75, OP2_MOVD_EdVd = 0x7E, OP2_JCC_rel32 = 0x80, OP_SETCC = 0x90, @@ -675,7 +676,7 @@ public: void fstp_m(int offset, RegisterID base) { - m_formatter.oneByteOp(OP_FPU6, FPU6_OP_FSTP, base, offset); + m_formatter.oneByteOp(OP_FPU6, FPU6_OP_FSTP, base, offset); } void negl_r(RegisterID dst) @@ -2049,6 +2050,15 @@ public: // SSE operations: + void pcmpeqw_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "pcmpeqw %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_PCMPEQW, (RegisterID)dst, (RegisterID)src); /* right order ? */ + } + void addsd_rr(XMMRegisterID src, XMMRegisterID dst) { js::JaegerSpew(js::JSpew_Insns, @@ -2185,13 +2195,33 @@ public: void psrldq_rr(XMMRegisterID dest, int shift) { js::JaegerSpew(js::JSpew_Insns, - IPFX "pslldq %s, %d\n", MAYBE_PAD, + IPFX "psrldq %s, %d\n", MAYBE_PAD, nameFPReg(dest), shift); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)3, (RegisterID)dest); m_formatter.immediate8(shift); } + void psllq_rr(XMMRegisterID dest, int shift) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "psllq %s, %d\n", MAYBE_PAD, + nameFPReg(dest), shift); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)6, (RegisterID)dest); + m_formatter.immediate8(shift); + } + + void psrlq_rr(XMMRegisterID dest, int shift) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "psrlq %s, %d\n", MAYBE_PAD, + nameFPReg(dest), shift); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)2, (RegisterID)dest); + m_formatter.immediate8(shift); + } + void movmskpd_rr(XMMRegisterID src, RegisterID dst) { js::JaegerSpew(js::JSpew_Insns, diff --git a/js/src/ion/shared/Assembler-x86-shared.h b/js/src/ion/shared/Assembler-x86-shared.h index 006b2559c6e..676eab6d20b 100644 --- a/js/src/ion/shared/Assembler-x86-shared.h +++ b/js/src/ion/shared/Assembler-x86-shared.h @@ -1007,9 +1007,15 @@ class AssemblerX86Shared JS_NOT_REACHED("unexpected operand kind"); } } - void psrlq(Imm32 shift, const FloatRegister &dest) { + void psrldq(Imm32 shift, const FloatRegister &dest) { masm.psrldq_rr(dest.code(), shift.value); } + void psllq(Imm32 shift, const FloatRegister &dest) { + masm.psllq_rr(dest.code(), shift.value); + } + void psrlq(Imm32 shift, const FloatRegister &dest) { + masm.psrlq_rr(dest.code(), shift.value); + } void cvtsi2sd(const Operand &src, const FloatRegister &dest) { switch (src.kind()) { @@ -1042,6 +1048,9 @@ class AssemblerX86Shared void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) { masm.ucomisd_rr(rhs.code(), lhs.code()); } + void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) { + masm.pcmpeqw_rr(rhs.code(), lhs.code()); + } void movd(const Register &src, const FloatRegister &dest) { masm.movd_rr(src.code(), dest.code()); } diff --git a/js/src/ion/shared/MacroAssembler-x86-shared.h b/js/src/ion/shared/MacroAssembler-x86-shared.h index a383292e9a4..0dd735d5a55 100644 --- a/js/src/ion/shared/MacroAssembler-x86-shared.h +++ b/js/src/ion/shared/MacroAssembler-x86-shared.h @@ -323,6 +323,43 @@ class MacroAssemblerX86Shared : public Assembler bind(&done); } + bool maybeInlineDouble(uint64_t u, const FloatRegister &dest) { + // This implements parts of "13.4 Generating constants" of + // "2. Optimizing subroutines in assembly language" by Agner Fog. + switch (u) { + case 0: + xorpd(dest, dest); + break; + case 0x3fe0000000000000: // 0.5 + pcmpeqw(dest, dest); + psllq(Imm32(55), dest); + psrlq(Imm32(2), dest); + break; + case 0x3ff0000000000000: // 1.0 + pcmpeqw(dest, dest); + psllq(Imm32(54), dest); + psrlq(Imm32(2), dest); + break; + case 0x3ff8000000000000: // 1.5 + pcmpeqw(dest, dest); + psllq(Imm32(53), dest); + psrlq(Imm32(2), dest); + break; + case 0x4000000000000000: // 2.0 + pcmpeqw(dest, dest); + psllq(Imm32(63), dest); + psrlq(Imm32(1), dest); + break; + case 0xc000000000000000: // -2.0 + pcmpeqw(dest, dest); + psllq(Imm32(62), dest); + break; + default: + return false; + } + return true; + } + // Emit a JMP that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp(). CodeOffsetLabel toggledJump(Label *label) { CodeOffsetLabel offset(size()); diff --git a/js/src/ion/x64/MacroAssembler-x64.h b/js/src/ion/x64/MacroAssembler-x64.h index 1780565e3ca..7e296e26885 100644 --- a/js/src/ion/x64/MacroAssembler-x64.h +++ b/js/src/ion/x64/MacroAssembler-x64.h @@ -704,9 +704,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared double d; } pun; pun.d = d; - if (pun.u == 0) { - xorpd(dest, dest); - } else { + if (!maybeInlineDouble(pun.u, dest)) { movq(ImmWord(pun.u), ScratchReg); movqsd(ScratchReg, dest); } diff --git a/js/src/ion/x86/CodeGenerator-x86.cpp b/js/src/ion/x86/CodeGenerator-x86.cpp index d95a54afc34..d6fa169060e 100644 --- a/js/src/ion/x86/CodeGenerator-x86.cpp +++ b/js/src/ion/x86/CodeGenerator-x86.cpp @@ -199,10 +199,8 @@ CodeGeneratorX86::visitDouble(LDouble *ins) } dpun; dpun.d = v.toDouble(); - if (dpun.u == 0) { - masm.xorpd(ToFloatRegister(out), ToFloatRegister(out)); + if (masm.maybeInlineDouble(dpun.u, ToFloatRegister(out))) return true; - } DeferredDouble *d = new DeferredDouble(cindex->index()); if (!deferredDoubles_.append(d)) diff --git a/js/src/ion/x86/MacroAssembler-x86.h b/js/src/ion/x86/MacroAssembler-x86.h index 6aaddda8946..e42220a056b 100644 --- a/js/src/ion/x86/MacroAssembler-x86.h +++ b/js/src/ion/x86/MacroAssembler-x86.h @@ -542,7 +542,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared // Note: this function clobbers the source register. void boxDouble(const FloatRegister &src, const ValueOperand &dest) { movd(src, dest.payloadReg()); - psrlq(Imm32(4), src); + psrldq(Imm32(4), src); movd(src, dest.typeReg()); } void unboxInt32(const ValueOperand &src, const Register &dest) { diff --git a/js/src/jit-test/tests/ion/inline-doubles.js b/js/src/jit-test/tests/ion/inline-doubles.js new file mode 100644 index 00000000000..34fc6ad15ac --- /dev/null +++ b/js/src/jit-test/tests/ion/inline-doubles.js @@ -0,0 +1,35 @@ +function add0_5 (n) { + return n + 0.5; +} + +function add1_0 (n) { + return n + 1; +} + +function add1_5 (n) { + return n + 1.5; +} + +function add2_0 (n) { + return n + 2; +} + +function sub2_0 (n) { + return n - 2; +} + + +var num = 1.5; + +function main () { + for (var i = 0; i < 10000; i++) { + assertEq(add0_5(num), 2); + assertEq(add1_0(num), 2.5); + assertEq(add1_5(num), 3); + assertEq(add2_0(num), 3.5); + assertEq(sub2_0(num), -0.5); + } +} + +for (var i = 0; i < 1000; i++) + main(); \ No newline at end of file