Bug 1094855: Implement SIMD.float32x4.minNum/maxNum in the JITs; r=sunfish

This commit is contained in:
Benjamin Bouvier 2014-11-21 17:27:40 +01:00
parent 9d4ff51379
commit 286105327c
4 changed files with 66 additions and 10 deletions

View File

@ -4083,7 +4083,9 @@ LIRGenerator::visitSimdBinaryArith(MSimdBinaryArith *ins)
LSimdBinaryArithFx4 *lir = new(alloc()) LSimdBinaryArithFx4(); 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()); lir->setTemp(0, needsTemp ? temp(LDefinition::FLOAT32X4) : LDefinition::BogusTemp());
return lowerForFPU(lir, ins, lhs, rhs); return lowerForFPU(lir, ins, lhs, rhs);

View File

@ -1857,17 +1857,21 @@ class MSimdBinaryArith : public MBinaryInstruction
Mul, Mul,
Div, Div,
Min, Min,
Max Max,
MinNum,
MaxNum
}; };
static const char* OperationName(Operation op) { static const char* OperationName(Operation op) {
switch (op) { switch (op) {
case Add: return "Add"; case Add: return "Add";
case Sub: return "Sub"; case Sub: return "Sub";
case Mul: return "Mul"; case Mul: return "Mul";
case Div: return "Div"; case Div: return "Div";
case Min: return "Min"; case Min: return "Min";
case Max: return "Max"; case Max: return "Max";
case MinNum: return "MinNum";
case MaxNum: return "MaxNum";
} }
MOZ_CRASH("unexpected operation"); MOZ_CRASH("unexpected operation");
} }

View File

@ -1907,6 +1907,7 @@ class AssemblerX86Shared : public AssemblerShared
} }
} }
void andnps(const Operand &src, FloatRegister dest) { void andnps(const Operand &src, FloatRegister dest) {
// Negates bits of dest and then applies AND
MOZ_ASSERT(HasSSE2()); MOZ_ASSERT(HasSSE2());
switch (src.kind()) { switch (src.kind()) {
case Operand::FPREG: case Operand::FPREG:

View File

@ -2769,6 +2769,9 @@ CodeGeneratorX86Shared::visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *ins)
// we can do max with a single instruction only if we have SSE4.1 // we can do max with a single instruction only if we have SSE4.1
// using the PMINSD instruction. // using the PMINSD instruction.
break; break;
case MSimdBinaryArith::MinNum:
case MSimdBinaryArith::MaxNum:
break;
} }
MOZ_CRASH("unexpected SIMD op"); 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 masm.orps(rhsCopy, lhs); // NaN or'd with arbitrary bits is NaN
return true; 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"); MOZ_CRASH("unexpected SIMD op");
} }
@ -2965,8 +3016,6 @@ CodeGeneratorX86Shared::visitSimdSelect(LSimdSelect *ins)
FloatRegister onFalse = ToFloatRegister(ins->rhs()); FloatRegister onFalse = ToFloatRegister(ins->rhs());
MOZ_ASSERT(onTrue == ToFloatRegister(ins->output())); 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.bitwiseAndX4(Operand(mask), onTrue);
masm.bitwiseAndNotX4(Operand(onFalse), mask); masm.bitwiseAndNotX4(Operand(onFalse), mask);
masm.bitwiseOrX4(Operand(mask), onTrue); masm.bitwiseOrX4(Operand(mask), onTrue);