Bug 1053788: Implement backends for generating min/max for float32; r=sunfish

This commit is contained in:
Benjamin Bouvier 2014-09-19 14:39:27 +02:00
parent 895933993b
commit ad46b80dcb
9 changed files with 148 additions and 0 deletions

View File

@ -2699,6 +2699,14 @@ class LMinMaxD : public LMinMaxBase
{}
};
class LMinMaxF : public LMinMaxBase
{
public:
LIR_HEADER(MinMaxF)
LMinMaxF(const LAllocation &first, const LAllocation &second) : LMinMaxBase(first, second)
{}
};
// Negative of an integer
class LNegI : public LInstructionHelper<1, 1, 0>
{

View File

@ -115,6 +115,7 @@
_(EmulatesUndefinedAndBranch) \
_(MinMaxI) \
_(MinMaxD) \
_(MinMaxF) \
_(NegI) \
_(NegD) \
_(NegF) \

View File

@ -1288,6 +1288,12 @@ LIRGenerator::visitMinMax(MMinMax *ins)
return defineReuseInput(lir, ins, 0);
}
if (ins->specialization() == MIRType_Float32) {
LMinMaxF *lir = new(alloc()) LMinMaxF(useRegisterAtStart(first), useRegister(second));
return defineReuseInput(lir, ins, 0);
}
MOZ_ASSERT(ins->specialization() == MIRType_Double);
LMinMaxD *lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second));
return defineReuseInput(lir, ins, 0);
}

View File

@ -290,6 +290,55 @@ CodeGeneratorARM::visitMinMaxD(LMinMaxD *ins)
return true;
}
bool
CodeGeneratorARM::visitMinMaxF(LMinMaxF *ins)
{
FloatRegister first = ToFloatRegister(ins->first());
FloatRegister second = ToFloatRegister(ins->second());
FloatRegister output = ToFloatRegister(ins->output());
JS_ASSERT(first == output);
Assembler::Condition cond = ins->mir()->isMax()
? Assembler::VFP_LessThanOrEqual
: Assembler::VFP_GreaterThanOrEqual;
Label nan, equal, returnSecond, done;
masm.compareFloat(first, second);
// First or second is NaN, result is NaN.
masm.ma_b(&nan, Assembler::VFP_Unordered);
// Make sure we handle -0 and 0 right.
masm.ma_b(&equal, Assembler::VFP_Equal);
masm.ma_b(&returnSecond, cond);
masm.ma_b(&done);
// Check for zero.
masm.bind(&equal);
masm.compareFloat(first, NoVFPRegister);
// First wasn't 0 or -0, so just return it.
masm.ma_b(&done, Assembler::VFP_NotEqualOrUnordered);
// So now both operands are either -0 or 0.
if (ins->mir()->isMax()) {
// -0 + -0 = -0 and -0 + 0 = 0.
masm.ma_vadd_f32(second, first, first);
} else {
masm.ma_vneg_f32(first, first);
masm.ma_vsub_f32(first, second, first);
masm.ma_vneg_f32(first, first);
}
masm.ma_b(&done);
masm.bind(&nan);
masm.loadConstantFloat32(GenericNaN(), output);
masm.ma_b(&done);
masm.bind(&returnSecond);
masm.ma_vmov_f32(second, output);
masm.bind(&done);
return true;
}
bool
CodeGeneratorARM::visitAbsD(LAbsD *ins)
{

View File

@ -102,6 +102,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
public:
// Instruction visitors.
virtual bool visitMinMaxD(LMinMaxD *ins);
virtual bool visitMinMaxF(LMinMaxF *ins);
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitAbsF(LAbsF *ins);
virtual bool visitSqrtD(LSqrtD *ins);

View File

@ -1931,6 +1931,10 @@ class AssemblerX86Shared : public AssemblerShared
JS_ASSERT(HasSSE2());
masm.orpd_rr(src.code(), dest.code());
}
void orps(FloatRegister src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.orps_rr(src.code(), dest.code());
}
void andpd(FloatRegister src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.andpd_rr(src.code(), dest.code());
@ -1976,6 +1980,10 @@ class AssemblerX86Shared : public AssemblerShared
MOZ_CRASH("unexpected operand kind");
}
}
void minss(FloatRegister src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.minss_rr(src.code(), dest.code());
}
void maxsd(FloatRegister src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.maxsd_rr(src.code(), dest.code());
@ -1993,6 +2001,10 @@ class AssemblerX86Shared : public AssemblerShared
MOZ_CRASH("unexpected operand kind");
}
}
void maxss(FloatRegister src, FloatRegister dest) {
JS_ASSERT(HasSSE2());
masm.maxss_rr(src.code(), dest.code());
}
void fisttp(const Operand &dest) {
JS_ASSERT(HasSSE3());
switch (dest.kind()) {

View File

@ -308,10 +308,12 @@ private:
OP2_SUBSD_VsdWsd = 0x5C,
OP2_SUBPS_VpsWps = 0x5C,
OP2_MINSD_VsdWsd = 0x5D,
OP2_MINSS_VssWss = 0x5D,
OP2_MINPS_VpsWps = 0x5D,
OP2_DIVSD_VsdWsd = 0x5E,
OP2_DIVPS_VpsWps = 0x5E,
OP2_MAXSD_VsdWsd = 0x5F,
OP2_MAXSS_VssWss = 0x5F,
OP2_MAXPS_VpsWps = 0x5F,
OP2_SQRTSD_VsdWsd = 0x51,
OP2_SQRTSS_VssWss = 0x51,
@ -3639,6 +3641,14 @@ public:
m_formatter.twoByteOp(OP2_MINSD_VsdWsd, (RegisterID)dst, base, offset);
}
void minss_rr(XMMRegisterID src, XMMRegisterID dst)
{
spew("minss %s, %s",
nameFPReg(src), nameFPReg(dst));
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_MINSS_VssWss, (RegisterID)dst, (RegisterID)src);
}
void maxsd_rr(XMMRegisterID src, XMMRegisterID dst)
{
spew("maxsd %s, %s",
@ -3655,6 +3665,14 @@ public:
m_formatter.twoByteOp(OP2_MAXSD_VsdWsd, (RegisterID)dst, base, offset);
}
void maxss_rr(XMMRegisterID src, XMMRegisterID dst)
{
spew("maxss %s, %s",
nameFPReg(src), nameFPReg(dst));
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_MAXSS_VssWss, (RegisterID)dst, (RegisterID)src);
}
// Misc instructions:
void int3()

View File

@ -536,6 +536,58 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
return true;
}
bool
CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
{
FloatRegister first = ToFloatRegister(ins->first());
FloatRegister second = ToFloatRegister(ins->second());
#ifdef DEBUG
FloatRegister output = ToFloatRegister(ins->output());
JS_ASSERT(first == output);
#endif
Label done, nan, minMaxInst;
// Do a ucomiss 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.ucomiss(first, second);
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.andps(second, first);
else
masm.orps(second, 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.ucomiss(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.maxss(second, first);
else
masm.minss(second, first);
masm.bind(&done);
return true;
}
bool
CodeGeneratorX86Shared::visitAbsD(LAbsD *ins)
{

View File

@ -151,6 +151,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual bool visitDouble(LDouble *ins);
virtual bool visitFloat32(LFloat32 *ins);
virtual bool visitMinMaxD(LMinMaxD *ins);
virtual bool visitMinMaxF(LMinMaxF *ins);
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitAbsF(LAbsF *ins);
virtual bool visitClzI(LClzI *ins);