mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[JAEGER] Fast-path for MOD with integers (bug 579466).
This commit is contained in:
parent
0a43327d9f
commit
26f3429eb7
@ -958,7 +958,9 @@ public:
|
||||
|
||||
void idivl_r(RegisterID dst)
|
||||
{
|
||||
FIXME_INSN_PRINTING;
|
||||
js::JaegerSpew(js::JSpew_Insns,
|
||||
IPFX "idivl %s\n", MAYBE_PAD,
|
||||
nameIReg(4, dst));
|
||||
m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst);
|
||||
}
|
||||
|
||||
@ -1285,7 +1287,8 @@ public:
|
||||
|
||||
void cdq()
|
||||
{
|
||||
FIXME_INSN_PRINTING;
|
||||
js::JaegerSpew(js::JSpew_Insns,
|
||||
IPFX "cdq \n", MAYBE_PAD);
|
||||
m_formatter.oneByteOp(OP_CDQ);
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,13 @@ class BaseAssembler : public JSC::MacroAssembler
|
||||
return Address(reg, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
}
|
||||
|
||||
#ifdef JS_CPU_X86
|
||||
void idiv(RegisterID reg) {
|
||||
m_assembler.cdq();
|
||||
m_assembler.idivl_r(reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prepares for a stub call.
|
||||
*/
|
||||
|
@ -600,7 +600,7 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_DIV)
|
||||
|
||||
BEGIN_CASE(JSOP_MOD)
|
||||
jsop_binary(op, stubs::Mod);
|
||||
jsop_mod();
|
||||
END_CASE(JSOP_MOD)
|
||||
|
||||
BEGIN_CASE(JSOP_NOT)
|
||||
|
@ -269,6 +269,7 @@ class Compiler
|
||||
void jsop_bitop(JSOp op);
|
||||
void jsop_globalinc(JSOp op, uint32 index);
|
||||
void jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
void jsop_mod();
|
||||
void jsop_neg();
|
||||
void jsop_bitnot();
|
||||
void jsop_objtostr();
|
||||
|
@ -410,31 +410,26 @@ FrameState::tempRegForData(FrameEntry *fe)
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::RegisterID
|
||||
FrameState::tempRegForData(FrameEntry *fe, RegisterID reg)
|
||||
FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
RegisterID reg;
|
||||
if (fe->data.inRegister()) {
|
||||
RegisterID old = fe->data.reg();
|
||||
if (old == reg)
|
||||
return reg;
|
||||
if (Registers::maskReg(old) & mask)
|
||||
return old;
|
||||
|
||||
/* Keep the old register pinned. */
|
||||
regstate[old].fe = NULL;
|
||||
if (!freeRegs.hasReg(reg))
|
||||
evictReg(reg);
|
||||
else
|
||||
freeRegs.takeReg(reg);
|
||||
reg = allocReg(mask);
|
||||
masm.move(old, reg);
|
||||
freeReg(old);
|
||||
} else {
|
||||
if (!freeRegs.hasReg(reg))
|
||||
evictReg(reg);
|
||||
else
|
||||
freeRegs.takeReg(reg);
|
||||
reg = allocReg(mask);
|
||||
masm.loadPayload(addressOf(fe), reg);
|
||||
}
|
||||
regstate[reg] = RegisterState(fe, RematInfo::DATA);
|
||||
|
@ -112,8 +112,8 @@ FrameState::takeReg(RegisterID reg)
|
||||
} else {
|
||||
JS_ASSERT(regstate[reg].fe);
|
||||
evictReg(reg);
|
||||
regstate[reg].fe = NULL;
|
||||
}
|
||||
regstate[reg].fe = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -492,6 +492,38 @@ FrameState::copyDataIntoReg(FrameEntry *fe)
|
||||
return copyDataIntoReg(this->masm, fe);
|
||||
}
|
||||
|
||||
void
|
||||
FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint)
|
||||
{
|
||||
JS_ASSERT(!fe->data.isConstant());
|
||||
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
if (!fe->data.inRegister())
|
||||
tempRegForData(fe);
|
||||
|
||||
RegisterID reg = fe->data.reg();
|
||||
if (reg == hint) {
|
||||
if (freeRegs.empty()) {
|
||||
if (!fe->data.synced())
|
||||
syncData(fe, addressOf(fe), masm);
|
||||
fe->data.setMemory();
|
||||
} else {
|
||||
reg = allocReg();
|
||||
masm.move(hint, reg);
|
||||
fe->data.setRegister(reg);
|
||||
regstate[reg] = regstate[hint];
|
||||
}
|
||||
regstate[hint].fe = NULL;
|
||||
} else {
|
||||
pinReg(reg);
|
||||
takeReg(hint);
|
||||
unpinReg(reg);
|
||||
masm.move(reg, hint);
|
||||
}
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::RegisterID
|
||||
FrameState::copyDataIntoReg(Assembler &masm, FrameEntry *fe)
|
||||
{
|
||||
|
@ -304,7 +304,7 @@ class FrameState
|
||||
/*
|
||||
* Same as above, except register must match identically.
|
||||
*/
|
||||
inline RegisterID tempRegForData(FrameEntry *fe, RegisterID reg);
|
||||
inline RegisterID tempRegInMaskForData(FrameEntry *fe, uint32 mask);
|
||||
|
||||
/*
|
||||
* Forcibly loads the type tag for the specified FrameEntry
|
||||
@ -352,6 +352,7 @@ class FrameState
|
||||
* can modify it in-place. The actual FE is not modified.
|
||||
*/
|
||||
RegisterID copyDataIntoReg(FrameEntry *fe);
|
||||
void copyDataIntoReg(FrameEntry *fe, RegisterID exact);
|
||||
RegisterID copyDataIntoReg(Assembler &masm, FrameEntry *fe);
|
||||
|
||||
/*
|
||||
|
@ -48,6 +48,7 @@
|
||||
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
using namespace JSC;
|
||||
|
||||
typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
|
||||
|
||||
@ -764,3 +765,108 @@ mjit::Compiler::jsop_neg()
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_mod()
|
||||
{
|
||||
#if defined(JS_CPU_X86)
|
||||
FrameEntry *lhs = frame.peek(-2);
|
||||
FrameEntry *rhs = frame.peek(-1);
|
||||
if ((lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_INT32) ||
|
||||
(rhs->isTypeKnown() && rhs->getKnownType() != JSVAL_TYPE_INT32))
|
||||
#endif
|
||||
{
|
||||
prepareStubCall(Uses(2));
|
||||
stubCall(stubs::Mod);
|
||||
frame.popn(2);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(JS_CPU_X86)
|
||||
if (!lhs->isTypeKnown()) {
|
||||
Jump j = frame.testInt32(Assembler::NotEqual, lhs);
|
||||
stubcc.linkExit(j, Uses(2));
|
||||
}
|
||||
if (!rhs->isTypeKnown()) {
|
||||
Jump j = frame.testInt32(Assembler::NotEqual, rhs);
|
||||
stubcc.linkExit(j, Uses(2));
|
||||
}
|
||||
|
||||
/* LHS must be in EAX:EDX */
|
||||
if (!lhs->isConstant()) {
|
||||
frame.copyDataIntoReg(lhs, X86Registers::eax);
|
||||
} else {
|
||||
frame.takeReg(X86Registers::eax);
|
||||
masm.move(Imm32(lhs->getValue().toInt32()), X86Registers::eax);
|
||||
}
|
||||
|
||||
/* Get RHS into anything but EDX - could avoid more spilling? */
|
||||
MaybeRegisterID temp;
|
||||
RegisterID rhsReg;
|
||||
if (!rhs->isConstant()) {
|
||||
uint32 mask = Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx);
|
||||
rhsReg = frame.tempRegInMaskForData(rhs, mask);
|
||||
JS_ASSERT(rhsReg != X86Registers::edx);
|
||||
} else {
|
||||
rhsReg = frame.allocReg(Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx));
|
||||
JS_ASSERT(rhsReg != X86Registers::edx);
|
||||
masm.move(Imm32(rhs->getValue().toInt32()), rhsReg);
|
||||
temp = rhsReg;
|
||||
}
|
||||
frame.takeReg(X86Registers::edx);
|
||||
frame.freeReg(X86Registers::eax);
|
||||
|
||||
if (temp.isSet())
|
||||
frame.freeReg(temp.reg());
|
||||
|
||||
bool slowPath = !(lhs->isTypeKnown() && rhs->isTypeKnown());
|
||||
if (rhs->isConstant() && rhs->getValue().toInt32() != 0) {
|
||||
if (rhs->getValue().toInt32() == -1) {
|
||||
/* Guard against -1 / INT_MIN which throws a hardware exception. */
|
||||
Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax,
|
||||
Imm32(0x80000000));
|
||||
stubcc.linkExit(checkDivExc, Uses(2));
|
||||
slowPath = true;
|
||||
}
|
||||
} else {
|
||||
Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax, Imm32(0x80000000));
|
||||
stubcc.linkExit(checkDivExc, Uses(2));
|
||||
Jump checkZero = masm.branchTest32(Assembler::Zero, rhsReg, rhsReg);
|
||||
stubcc.linkExit(checkZero, Uses(2));
|
||||
slowPath = true;
|
||||
}
|
||||
|
||||
/* Perform division. */
|
||||
masm.idiv(rhsReg);
|
||||
|
||||
/* Test for negative 0. */
|
||||
RegisterID lhsData = frame.tempRegForData(lhs);
|
||||
Jump negZero1 = masm.branchTest32(Assembler::NonZero, X86Registers::edx);
|
||||
Jump negZero2 = masm.branchTest32(Assembler::Zero, lhsData, Imm32(0x80000000));
|
||||
|
||||
/* Darn, negative 0. */
|
||||
jsval_layout jv;
|
||||
jv.asDouble = -0.0;
|
||||
masm.storeLayout(jv, frame.addressOf(lhs));
|
||||
|
||||
Jump done = masm.jump();
|
||||
negZero1.linkTo(masm.label(), &masm);
|
||||
negZero2.linkTo(masm.label(), &masm);
|
||||
|
||||
/* Better - integer. */
|
||||
masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), frame.addressOf(lhs));
|
||||
|
||||
done.linkTo(masm.label(), &masm);
|
||||
|
||||
if (slowPath) {
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::Mod);
|
||||
}
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushNumber(X86Registers::edx);
|
||||
|
||||
if (slowPath)
|
||||
stubcc.rejoin(Changes(1));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ mjit::Compiler::jsop_bitop(JSOp op)
|
||||
} else {
|
||||
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
|
||||
/* Grosssssss! RHS _must_ be in ECX, on x86 */
|
||||
RegisterID rr = frame.tempRegForData(rhs, JSC::X86Registers::ecx);
|
||||
RegisterID rr = frame.tempRegInMaskForData(rhs, Registers::maskReg(JSC::X86Registers::ecx));
|
||||
#else
|
||||
RegisterID rr = frame.tempRegForData(rhs);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user