From 8ec23c07dd09da1e46bf17f05ecad83f8aa12e4e Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Thu, 2 Jun 2016 16:54:09 +0200 Subject: [PATCH] Bug 1232205 - Wasm baseline: Factor out floating min and max, on x86-shared. r=bbouvier --HG-- extra : rebase_source : d6a672b57f12fc7c848cdd040bb4129c23ee3cb9 --- .../x86-shared/CodeGenerator-x86-shared.cpp | 82 ++--------------- .../x86-shared/MacroAssembler-x86-shared.cpp | 88 +++++++++++++++++++ .../x86-shared/MacroAssembler-x86-shared.h | 5 ++ 3 files changed, 99 insertions(+), 76 deletions(-) diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index ec4beafc85a7..0edd7a1f5618 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -663,45 +663,10 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD* ins) MOZ_ASSERT(first == output); #endif - Label done, nan, minMaxInst; + bool specialHandling = !ins->mir()->range() || ins->mir()->range()->canBeNaN(); + bool isMax = ins->mir()->isMax(); - // Do a vucomisd to catch equality and NaNs, which both require special - // handling. If the operands are ordered and inequal, we branch straight to - // the min/max instruction. If we wanted, we could also branch for less-than - // or greater-than here instead of using min/max, however these conditions - // will sometimes be hard on the branch predictor. - masm.vucomisd(second, first); - masm.j(Assembler::NotEqual, &minMaxInst); - if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) - masm.j(Assembler::Parity, &nan); - - // Ordered and equal. The operands are bit-identical unless they are zero - // and negative zero. These instructions merge the sign bits in that - // case, and are no-ops otherwise. - if (ins->mir()->isMax()) - masm.vandpd(second, first, first); - else - masm.vorpd(second, first, first); - masm.jump(&done); - - // x86's min/max are not symmetric; if either operand is a NaN, they return - // the read-only operand. We need to return a NaN if either operand is a - // NaN, so we explicitly check for a NaN in the read-write operand. - if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) { - masm.bind(&nan); - masm.vucomisd(first, first); - masm.j(Assembler::Parity, &done); - } - - // When the values are inequal, or second is NaN, x86's min and max will - // return the value we need. - masm.bind(&minMaxInst); - if (ins->mir()->isMax()) - masm.vmaxsd(second, first, first); - else - masm.vminsd(second, first, first); - - masm.bind(&done); + masm.minMaxDouble(first, second, specialHandling, isMax); } void @@ -714,45 +679,10 @@ CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF* ins) MOZ_ASSERT(first == output); #endif - Label done, nan, minMaxInst; + bool specialHandling = !ins->mir()->range() || ins->mir()->range()->canBeNaN(); + bool isMax = ins->mir()->isMax(); - // Do a vucomiss to catch equality and NaNs, which both require special - // handling. If the operands are ordered and inequal, we branch straight to - // the min/max instruction. If we wanted, we could also branch for less-than - // or greater-than here instead of using min/max, however these conditions - // will sometimes be hard on the branch predictor. - masm.vucomiss(second, first); - masm.j(Assembler::NotEqual, &minMaxInst); - if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) - masm.j(Assembler::Parity, &nan); - - // Ordered and equal. The operands are bit-identical unless they are zero - // and negative zero. These instructions merge the sign bits in that - // case, and are no-ops otherwise. - if (ins->mir()->isMax()) - masm.vandps(second, first, first); - else - masm.vorps(second, first, first); - masm.jump(&done); - - // x86's min/max are not symmetric; if either operand is a NaN, they return - // the read-only operand. We need to return a NaN if either operand is a - // NaN, so we explicitly check for a NaN in the read-write operand. - if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) { - masm.bind(&nan); - masm.vucomiss(first, first); - masm.j(Assembler::Parity, &done); - } - - // When the values are inequal, or second is NaN, x86's min and max will - // return the value we need. - masm.bind(&minMaxInst); - if (ins->mir()->isMax()) - masm.vmaxss(second, first, first); - else - masm.vminss(second, first, first); - - masm.bind(&done); + masm.minMaxFloat32(first, second, specialHandling, isMax); } void diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index ac4638685a5e..62ccdd7f4a44 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -315,6 +315,94 @@ MacroAssemblerX86Shared::asmMergeWith(const MacroAssemblerX86Shared& other) return true; } +void +MacroAssemblerX86Shared::minMaxDouble(FloatRegister first, FloatRegister second, bool handleNaN, bool isMax) +{ + Label done, nan, minMaxInst; + + // Do a vucomisd to catch equality and NaNs, which both require special + // handling. If the operands are ordered and inequal, we branch straight to + // the min/max instruction. If we wanted, we could also branch for less-than + // or greater-than here instead of using min/max, however these conditions + // will sometimes be hard on the branch predictor. + vucomisd(second, first); + j(Assembler::NotEqual, &minMaxInst); + if (handleNaN) + j(Assembler::Parity, &nan); + + // Ordered and equal. The operands are bit-identical unless they are zero + // and negative zero. These instructions merge the sign bits in that + // case, and are no-ops otherwise. + if (isMax) + vandpd(second, first, first); + else + vorpd(second, first, first); + jump(&done); + + // x86's min/max are not symmetric; if either operand is a NaN, they return + // the read-only operand. We need to return a NaN if either operand is a + // NaN, so we explicitly check for a NaN in the read-write operand. + if (handleNaN) { + bind(&nan); + vucomisd(first, first); + j(Assembler::Parity, &done); + } + + // When the values are inequal, or second is NaN, x86's min and max will + // return the value we need. + bind(&minMaxInst); + if (isMax) + vmaxsd(second, first, first); + else + vminsd(second, first, first); + + bind(&done); +} + +void +MacroAssemblerX86Shared::minMaxFloat32(FloatRegister first, FloatRegister second, bool handleNaN, bool isMax) +{ + Label done, nan, minMaxInst; + + // Do a vucomiss to catch equality and NaNs, which both require special + // handling. If the operands are ordered and inequal, we branch straight to + // the min/max instruction. If we wanted, we could also branch for less-than + // or greater-than here instead of using min/max, however these conditions + // will sometimes be hard on the branch predictor. + vucomiss(second, first); + j(Assembler::NotEqual, &minMaxInst); + if (handleNaN) + j(Assembler::Parity, &nan); + + // Ordered and equal. The operands are bit-identical unless they are zero + // and negative zero. These instructions merge the sign bits in that + // case, and are no-ops otherwise. + if (isMax) + vandps(second, first, first); + else + vorps(second, first, first); + jump(&done); + + // x86's min/max are not symmetric; if either operand is a NaN, they return + // the read-only operand. We need to return a NaN if either operand is a + // NaN, so we explicitly check for a NaN in the read-write operand. + if (handleNaN) { + bind(&nan); + vucomiss(first, first); + j(Assembler::Parity, &done); + } + + // When the values are inequal, or second is NaN, x86's min and max will + // return the value we need. + bind(&minMaxInst); + if (isMax) + vmaxss(second, first, first); + else + vminss(second, first, first); + + bind(&done); +} + //{{{ check_macroassembler_style // =============================================================== // MacroAssembler high-level usage. diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index b5e50b5c1fdd..aee5861c95f4 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -102,6 +102,11 @@ class MacroAssemblerX86Shared : public Assembler bool asmMergeWith(const MacroAssemblerX86Shared& other); + // Evaluate first = minmax(first, second). + // Handle NaN specially if handleNaN is true. + void minMaxDouble(FloatRegister first, FloatRegister second, bool handleNaN, bool isMax); + void minMaxFloat32(FloatRegister first, FloatRegister second, bool handleNaN, bool isMax); + void compareDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) { if (cond & DoubleConditionBitInvert) vucomisd(lhs, rhs);