Bug 578517: JM: double >> int fast path. (r=dvander)

This commit is contained in:
Chris Leary 2010-07-28 15:40:31 -07:00
parent d1269a00d4
commit 8089ea803d
5 changed files with 269 additions and 46 deletions

View File

@ -621,8 +621,11 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_GE)
BEGIN_CASE(JSOP_LSH)
BEGIN_CASE(JSOP_RSH)
jsop_bitop(op);
END_CASE(JSOP_LSH)
BEGIN_CASE(JSOP_RSH)
jsop_rsh();
END_CASE(JSOP_RSH)
BEGIN_CASE(JSOP_URSH)

View File

@ -296,6 +296,16 @@ class Compiler
/* Fast opcodes. */
void jsop_bitop(JSOp op);
void jsop_rsh();
RegisterID rightRegForShift(FrameEntry *rhs);
void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs);
void jsop_rsh_unknown_unknown(FrameEntry *lhs, FrameEntry *rhs);
void jsop_globalinc(JSOp op, uint32 index);
void jsop_mod();
void jsop_neg();

View File

@ -51,6 +51,221 @@
using namespace js;
using namespace js::mjit;
typedef JSC::MacroAssembler::RegisterID RegisterID;
RegisterID
mjit::Compiler::rightRegForShift(FrameEntry *rhs)
{
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
/*
* Gross: RHS _must_ be in ECX, on x86.
* Note that we take this first so that we can't up with other register
* allocations (below) owning ecx before rhs.
*/
RegisterID reg = JSC::X86Registers::ecx;
if (!rhs->isConstant())
frame.copyDataIntoReg(rhs, reg);
return reg;
#else
if (rhs->isConstant())
return frame.allocReg();
return frame.copyDataIntoReg(rhs);
#endif
}
void
mjit::Compiler::jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs)
{
RegisterID rhsData = rightRegForShift(rhs);
RegisterID result = frame.allocReg();
masm.move(Imm32(lhs->getValue().toInt32()), result);
masm.rshift32(rhsData, result);
frame.freeReg(rhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, result);
}
void
mjit::Compiler::jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs)
{
RegisterID rhsData = rightRegForShift(rhs);
RegisterID lhsData = frame.copyDataIntoReg(lhs);
masm.rshift32(rhsData, lhsData);
frame.freeReg(rhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
}
void
mjit::Compiler::jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs)
{
int32 shiftAmount = rhs->getValue().toInt32();
if (!shiftAmount) {
frame.pop();
return;
}
RegisterID result = frame.copyDataIntoReg(lhs);
masm.rshift32(Imm32(shiftAmount), result);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, result);
}
void
mjit::Compiler::jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs)
{
int32 shiftAmount = rhs->getValue().toInt32();
RegisterID lhsType = frame.tempRegForType(lhs);
frame.pinReg(lhsType);
RegisterID lhsData = frame.copyDataIntoReg(lhs);
frame.unpinReg(lhsType);
Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType);
stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label());
Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType);
frame.loadDouble(lhs, FPRegisters::First, stubcc.masm);
Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData);
stubcc.crossJump(stubcc.masm.jump(), masm.label());
lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
frame.sync(stubcc.masm, Uses(2));
stubcc.call(stubs::Rsh);
if (shiftAmount)
masm.rshift32(Imm32(shiftAmount), lhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
stubcc.rejoin(Changes(1));
}
void
mjit::Compiler::jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs)
{
RegisterID rhsData = rightRegForShift(rhs);
RegisterID rhsType = frame.tempRegForType(rhs);
frame.pinReg(rhsType);
RegisterID result = frame.allocReg();
frame.unpinReg(rhsType);
Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType);
stubcc.linkExit(rhsIntGuard, Uses(2));
stubcc.leave();
stubcc.call(stubs::Rsh);
masm.move(Imm32(lhs->getValue().toInt32()), result);
masm.rshift32(rhsData, result);
frame.freeReg(rhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, result);
stubcc.rejoin(Changes(1));
}
void
mjit::Compiler::jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs)
{
RegisterID rhsData = rightRegForShift(rhs);
RegisterID rhsType = frame.tempRegForType(rhs);
frame.pinReg(rhsType);
RegisterID lhsData = frame.copyDataIntoReg(lhs);
frame.unpinReg(rhsType);
Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType);
stubcc.linkExit(rhsIntGuard, Uses(2));
stubcc.leave();
stubcc.call(stubs::Rsh);
masm.rshift32(rhsData, lhsData);
frame.freeReg(rhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
stubcc.rejoin(Changes(1));
}
void
mjit::Compiler::jsop_rsh_unknown_unknown(FrameEntry *lhs, FrameEntry *rhs)
{
RegisterID rhsData = rightRegForShift(rhs);
RegisterID rhsType = frame.tempRegForType(rhs);
frame.pinReg(rhsType);
RegisterID lhsType = frame.tempRegForType(lhs);
frame.pinReg(lhsType);
RegisterID lhsData = frame.copyDataIntoReg(lhs);
frame.unpinReg(lhsType);
frame.unpinReg(rhsType);
Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType);
Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType);
stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label());
Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType);
frame.loadDouble(lhs, FPRegisters::First, stubcc.masm);
Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData);
stubcc.crossJump(stubcc.masm.jump(), masm.label());
lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm);
stubcc.linkExitDirect(rhsIntGuard, stubcc.masm.label());
frame.sync(stubcc.masm, Uses(2));
stubcc.call(stubs::Rsh);
masm.rshift32(rhsData, lhsData);
frame.freeReg(rhsData);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData);
stubcc.rejoin(Changes(1));
}
void
mjit::Compiler::jsop_rsh()
{
FrameEntry *rhs = frame.peek(-1);
FrameEntry *lhs = frame.peek(-2);
if (lhs->isNotType(JSVAL_TYPE_INT32) || rhs->isNotType(JSVAL_TYPE_INT32)) {
prepareStubCall(Uses(2));
stubCall(stubs::Rsh);
frame.popn(2);
frame.pushSyncedType(JSVAL_TYPE_INT32);
return;
}
if (lhs->isConstant() && rhs->isConstant()) {
int32 L = lhs->getValue().toInt32();
int32 R = lhs->getValue().toInt32();
frame.popn(2);
frame.push(Int32Value(L >> R));
} else if (lhs->isConstant()) {
if (rhs->isType(JSVAL_TYPE_INT32))
jsop_rsh_const_int(lhs, rhs);
else
jsop_rsh_const_unknown(lhs, rhs);
} else if (rhs->isConstant()) {
if (lhs->isType(JSVAL_TYPE_INT32))
jsop_rsh_int_const(lhs, rhs);
else
jsop_rsh_unknown_const(lhs, rhs);
} else {
if (lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32))
jsop_rsh_int_int(lhs, rhs);
else if (lhs->isType(JSVAL_TYPE_INT32))
jsop_rsh_int_unknown(lhs, rhs);
else
jsop_rsh_unknown_unknown(lhs, rhs);
}
}
void
mjit::Compiler::jsop_bitnot()
{
@ -108,9 +323,6 @@ mjit::Compiler::jsop_bitop(JSOp op)
case JSOP_LSH:
stub = stubs::Lsh;
break;
case JSOP_RSH:
stub = stubs::Rsh;
break;
default:
JS_NOT_REACHED("wat");
return;
@ -163,9 +375,6 @@ mjit::Compiler::jsop_bitop(JSOp op)
case JSOP_LSH:
frame.push(Int32Value(L << R));
return;
case JSOP_RSH:
frame.push(Int32Value(L >> R));
return;
default:
JS_NOT_REACHED("say wat");
}
@ -215,13 +424,11 @@ mjit::Compiler::jsop_bitop(JSOp op)
}
case JSOP_LSH:
case JSOP_RSH:
{
/* Not commutative. */
if (rhs->isConstant()) {
int32 shift = rhs->getValue().toInt32() & 0x1F;
reg = frame.ownRegForData(lhs);
RegisterID reg = frame.ownRegForData(lhs);
int shift = rhs->getValue().toInt32() & 0x1F;
if (!shift) {
/*
@ -235,20 +442,16 @@ mjit::Compiler::jsop_bitop(JSOp op)
return;
}
switch (op) {
case JSOP_LSH:
masm.lshift32(Imm32(shift), reg);
break;
case JSOP_RSH:
masm.rshift32(Imm32(shift), reg);
break;
default:
JS_NOT_REACHED("NYI");
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
return;
}
} else {
#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
/* Grosssssss! RHS _must_ be in ECX, on x86 */
RegisterID rr = frame.tempRegInMaskForData(rhs, Registers::maskReg(JSC::X86Registers::ecx));
RegisterID rr = frame.tempRegInMaskForData(rhs,
Registers::maskReg(JSC::X86Registers::ecx));
#else
RegisterID rr = frame.tempRegForData(rhs);
#endif
@ -262,18 +465,8 @@ mjit::Compiler::jsop_bitop(JSOp op)
}
frame.unpinReg(rr);
switch (op) {
case JSOP_LSH:
masm.lshift32(rr, reg);
break;
case JSOP_RSH:
masm.rshift32(rr, reg);
break;
default:
JS_NOT_REACHED("NYI");
}
}
break;
}
default:

View File

@ -0,0 +1,17 @@
/* Unknown types. */
function rsh(lhs, rhs) { return lhs >> rhs; }
assertEq(rsh(1024, 2), 256)
assertEq(rsh(1024.5, 2), 256)
assertEq(rsh(1024.5, 2.0), 256)
/* Constant rhs. */
var lhs = 1024;
assertEq(lhs >> 2, 256);
lhs = 1024.5;
assertEq(lhs >> 2, 256);
/* Constant lhs. */
var rhs = 2;
assertEq(256, 1024 >> rhs);
var rhs = 2.0;
assertEq(256, 1024 >> rhs);