mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1053788: Implement backends for generating min/max for float32; r=sunfish
This commit is contained in:
parent
895933993b
commit
ad46b80dcb
@ -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>
|
||||
{
|
||||
|
@ -115,6 +115,7 @@
|
||||
_(EmulatesUndefinedAndBranch) \
|
||||
_(MinMaxI) \
|
||||
_(MinMaxD) \
|
||||
_(MinMaxF) \
|
||||
_(NegI) \
|
||||
_(NegD) \
|
||||
_(NegF) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user