[JAEGER] Fast-path for MOD with integers (bug 579466).

This commit is contained in:
David Anderson 2010-07-22 23:36:37 -07:00
parent 0a43327d9f
commit 26f3429eb7
9 changed files with 162 additions and 17 deletions

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -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)

View File

@ -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();

View File

@ -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);

View File

@ -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)
{

View File

@ -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);
/*

View File

@ -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
}

View File

@ -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