diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 8629054ae2f..5aadea08aae 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4083,7 +4083,9 @@ LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith *ins) LSimdBinaryArithFx4 *lir = new(alloc()) LSimdBinaryArithFx4(); - bool needsTemp = ins->operation() == MSimdBinaryArith::Max; + bool needsTemp = ins->operation() == MSimdBinaryArith::Max || + ins->operation() == MSimdBinaryArith::MinNum || + ins->operation() == MSimdBinaryArith::MaxNum; lir->setTemp(0, needsTemp ? temp(LDefinition::FLOAT32X4) : LDefinition::BogusTemp()); return lowerForFPU(lir, ins, lhs, rhs); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index de5cfa16c0a..4ad7fac09d4 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1857,17 +1857,21 @@ class MSimdBinaryArith : public MBinaryInstruction Mul, Div, Min, - Max + Max, + MinNum, + MaxNum }; static const char* OperationName(Operation op) { switch (op) { - case Add: return "Add"; - case Sub: return "Sub"; - case Mul: return "Mul"; - case Div: return "Div"; - case Min: return "Min"; - case Max: return "Max"; + case Add: return "Add"; + case Sub: return "Sub"; + case Mul: return "Mul"; + case Div: return "Div"; + case Min: return "Min"; + case Max: return "Max"; + case MinNum: return "MinNum"; + case MaxNum: return "MaxNum"; } MOZ_CRASH("unexpected operation"); } diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index 09452d5dd03..c9939ee672f 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -1907,6 +1907,7 @@ class AssemblerX86Shared : public AssemblerShared } } void andnps(const Operand &src, FloatRegister dest) { + // Negates bits of dest and then applies AND MOZ_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 4f0ceb70253..f28a9d6c81a 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -2769,6 +2769,9 @@ CodeGeneratorX86Shared::visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *ins) // we can do max with a single instruction only if we have SSE4.1 // using the PMINSD instruction. break; + case MSimdBinaryArith::MinNum: + case MSimdBinaryArith::MaxNum: + break; } MOZ_CRASH("unexpected SIMD op"); } @@ -2815,6 +2818,54 @@ CodeGeneratorX86Shared::visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *ins) masm.orps(rhsCopy, lhs); // NaN or'd with arbitrary bits is NaN return true; } + case MSimdBinaryArith::MinNum: { + FloatRegister tmp = ToFloatRegister(ins->temp()); + masm.loadConstantInt32x4(SimdConstant::SplatX4(int32_t(0x80000000)), ScratchSimdReg); + masm.movdqa(ScratchSimdReg, tmp); + + FloatRegister mask = ScratchSimdReg; + masm.pcmpeqd(Operand(lhs), mask); + masm.andps(tmp, mask); + + masm.movaps(lhs, tmp); + masm.minps(rhs, tmp); + masm.orps(mask, tmp); + + masm.movaps(rhs, mask); + masm.cmpneqps(Operand(mask), mask); + + // Emulates blendv + masm.andps(Operand(mask), lhs); + masm.andnps(Operand(tmp), mask); + masm.orps(Operand(mask), lhs); + return true; + } + case MSimdBinaryArith::MaxNum: { + FloatRegister mask = ScratchSimdReg; + masm.loadConstantInt32x4(SimdConstant::SplatX4(0), mask); + masm.pcmpeqd(Operand(lhs), mask); + + FloatRegister tmp = ToFloatRegister(ins->temp()); + masm.loadConstantInt32x4(SimdConstant::SplatX4(int32_t(0x80000000)), tmp); + masm.andps(tmp, mask); + + masm.movaps(lhs, tmp); + masm.maxps(rhs, tmp); + masm.andnps(Operand(tmp), mask); + + // Ensure tmp always contains the temporary result + mask = tmp; + tmp = ScratchSimdReg; + + masm.movaps(rhs, mask); + masm.cmpneqps(Operand(mask), mask); + + // Emulates blendv + masm.andps(Operand(mask), lhs); + masm.andnps(Operand(tmp), mask); + masm.orps(Operand(mask), lhs); + return true; + } } MOZ_CRASH("unexpected SIMD op"); } @@ -2965,8 +3016,6 @@ CodeGeneratorX86Shared::visitSimdSelect(LSimdSelect *ins) FloatRegister onFalse = ToFloatRegister(ins->rhs()); MOZ_ASSERT(onTrue == ToFloatRegister(ins->output())); - // The onFalse argument is not destroyed but due to limitations of the - // register allocator its life ends at the start of the operation. masm.bitwiseAndX4(Operand(mask), onTrue); masm.bitwiseAndNotX4(Operand(onFalse), mask); masm.bitwiseOrX4(Operand(mask), onTrue);