Bug 787906 - Don't emit a shift instruction for x >>> 0. r=dvander

This commit is contained in:
Jan de Mooij 2012-09-05 11:54:33 +02:00
parent 22abc28b96
commit 84b7b334fb
5 changed files with 106 additions and 92 deletions

View File

@ -973,6 +973,8 @@ public:
void shrl_i8r(int imm, RegisterID dst)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "shrl $%d, %s\n", MAYBE_PAD, imm, nameIReg(4, dst));
if (imm == 1)
m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
else {
@ -983,6 +985,8 @@ public:
void shrl_CLr(RegisterID dst)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "shrl %%cl, %s\n", MAYBE_PAD, nameIReg(4, dst));
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst);
}

View File

@ -1198,7 +1198,7 @@ class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
// Shift operation, taking two 32-bit integers as inputs and returning
// a 32-bit integer result as an output.
class LShiftI : public LInstructionHelper<1, 2, 0>
class LShiftI : public LBinaryMath<0>
{
JSOp op_;

View File

@ -680,67 +680,66 @@ CodeGeneratorARM::visitBitOpI(LBitOpI *ins)
bool
CodeGeneratorARM::visitShiftI(LShiftI *ins)
{
const LAllocation *lhs = ins->getOperand(0);
const LAllocation *rhs = ins->getOperand(1);
const LDefinition *dest = ins->getDef(0);
Register lhs = ToRegister(ins->lhs());
const LAllocation *rhs = ins->rhs();
Register dest = ToRegister(ins->output());
// The shift amounts should be AND'ed into the 0-31 range since arm shifts
// by the lower byte of the register (it will attempt to shift by 250 if you
// ask it to, and the result will probably not be what you want.
if (!rhs->isConstant()) {
masm.ma_and(Imm32(0x1f), ToRegister(rhs), ToRegister(dest));
rhs = dest->output();
}
switch (ins->bitop()) {
case JSOP_LSH:
if (rhs->isConstant()) {
masm.ma_lsl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs), ToRegister(dest));
} else {
masm.ma_lsl(ToRegister(rhs), ToRegister(lhs), ToRegister(dest));
}
if (rhs->isConstant()) {
int32_t shift = ToInt32(rhs) & 0x1F;
switch (ins->bitop()) {
case JSOP_LSH:
if (shift)
masm.ma_lsl(Imm32(shift), lhs, dest);
else
masm.ma_mov(lhs, dest);
break;
case JSOP_RSH:
if (rhs->isConstant()) {
if ((ToInt32(rhs) & 0x1f) != 0) {
masm.ma_asr(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs), ToRegister(dest));
} else {
masm.ma_mov(ToRegister(lhs), ToRegister(dest));
}
} else {
masm.ma_asr(ToRegister(rhs), ToRegister(lhs), ToRegister(dest));
}
case JSOP_RSH:
if (shift)
masm.ma_asr(Imm32(shift), lhs, dest);
else
masm.ma_mov(lhs, dest);
break;
case JSOP_URSH: {
MUrsh *ursh = ins->mir()->toUrsh();
if (rhs->isConstant()) {
if ((ToInt32(rhs) & 0x1f) != 0) {
masm.ma_lsr(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs), ToRegister(dest));
} else {
masm.ma_mov(ToRegister(lhs), ToRegister(dest));
}
case JSOP_URSH:
if (shift) {
masm.ma_lsr(Imm32(shift), lhs, dest);
} else {
masm.ma_lsr(ToRegister(rhs), ToRegister(lhs), ToRegister(dest));
}
// Note: this is an unsigned operation.
// We don't have a UINT32 type, so we will emulate this with INT32
// The bit representation of an integer from ToInt32 and ToUint32 are the same.
// So the inputs are ok.
// But we need to bring the output back again from UINT32 to INT32.
// Both representation overlap each other in the positive numbers. (in INT32)
// So there is only a problem when solution (in INT32) is negative.
if (ursh->canOverflow()) {
masm.ma_cmp(ToRegister(dest), Imm32(0));
if (!bailoutIf(Assembler::LessThan, ins->snapshot())) {
return false;
// x >>> 0 can overflow.
masm.ma_mov(lhs, dest);
if (ins->mir()->toUrsh()->canOverflow()) {
masm.ma_cmp(dest, Imm32(0));
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
return false;
}
}
break;
default:
JS_NOT_REACHED("Unexpected shift op");
}
} else {
// The shift amounts should be AND'ed into the 0-31 range since arm
// shifts by the lower byte of the register (it will attempt to shift
// by 250 if you ask it to).
masm.ma_and(Imm32(0x1F), ToRegister(rhs), dest);
switch (ins->bitop()) {
case JSOP_LSH:
masm.ma_lsl(dest, lhs, dest);
break;
case JSOP_RSH:
masm.ma_asr(dest, lhs, dest);
break;
case JSOP_URSH:
masm.ma_lsr(dest, lhs, dest);
if (ins->mir()->toUrsh()->canOverflow()) {
// x >>> 0 can overflow.
masm.ma_cmp(dest, Imm32(0));
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
return false;
}
break;
default:
JS_NOT_REACHED("Unexpected shift op");
}
default:
JS_NOT_REACHED("unexpected shift opcode");
return false;
}
return true;
@ -756,12 +755,13 @@ CodeGeneratorARM::visitUrshD(LUrshD *ins)
FloatRegister out = ToFloatRegister(ins->output());
if (rhs->isConstant()) {
if ((ToInt32(rhs) & 0x1f) != 0)
masm.ma_lsr(Imm32(ToInt32(rhs) & 0x1F), lhs, temp);
int32_t shift = ToInt32(rhs) & 0x1F;
if (shift)
masm.ma_lsr(Imm32(shift), lhs, temp);
else
masm.ma_mov(lhs, temp);
} else {
masm.ma_and(Imm32(0x1f), ToRegister(rhs), temp);
masm.ma_and(Imm32(0x1F), ToRegister(rhs), temp);
masm.ma_lsr(temp, lhs, temp);
}

View File

@ -217,8 +217,7 @@ LIRGeneratorARM::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mi
ins->setOperand(0, useRegister(lhs));
ins->setOperand(1, useRegisterOrConstant(rhs));
return define(ins, mir,
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
return define(ins, mir);
}
bool

View File

@ -808,45 +808,54 @@ CodeGeneratorX86Shared::visitBitOpI(LBitOpI *ins)
bool
CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
{
const LAllocation *lhs = ins->getOperand(0);
const LAllocation *rhs = ins->getOperand(1);
Register lhs = ToRegister(ins->lhs());
const LAllocation *rhs = ins->rhs();
switch (ins->bitop()) {
case JSOP_LSH:
if (rhs->isConstant())
masm.shll(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs));
else
masm.shll_cl(ToRegister(lhs));
if (rhs->isConstant()) {
int32_t shift = ToInt32(rhs) & 0x1F;
switch (ins->bitop()) {
case JSOP_LSH:
if (shift)
masm.shll(Imm32(shift), lhs);
break;
case JSOP_RSH:
if (rhs->isConstant())
masm.sarl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs));
else
masm.sarl_cl(ToRegister(lhs));
case JSOP_RSH:
if (shift)
masm.sarl(Imm32(shift), lhs);
break;
case JSOP_URSH: {
MUrsh *ursh = ins->mir()->toUrsh();
if (rhs->isConstant())
masm.shrl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs));
else
masm.shrl_cl(ToRegister(lhs));
// Note: this is an unsigned operation.
// We don't have a UINT32 type, so we will emulate this with INT32
// The bit representation of an integer from ToInt32 and ToUint32 are the same.
// So the inputs are ok.
// But we need to bring the output back again from UINT32 to INT32.
// Both representation overlap each other in the positive numbers. (in INT32)
// So there is only a problem when solution (in INT32) is negative.
if (ursh->canOverflow()) {
masm.cmpl(ToOperand(lhs), Imm32(0));
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
case JSOP_URSH:
if (shift) {
masm.shrl(Imm32(shift), lhs);
} else if (ins->mir()->toUrsh()->canOverflow()) {
// x >>> 0 can overflow.
masm.testl(lhs, lhs);
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
return false;
}
break;
default:
JS_NOT_REACHED("Unexpected shift op");
}
} else {
JS_ASSERT(ToRegister(rhs) == ecx);
switch (ins->bitop()) {
case JSOP_LSH:
masm.shll_cl(lhs);
break;
case JSOP_RSH:
masm.sarl_cl(lhs);
break;
case JSOP_URSH:
masm.shrl_cl(lhs);
if (ins->mir()->toUrsh()->canOverflow()) {
// x >>> 0 can overflow.
masm.testl(lhs, lhs);
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
return false;
}
break;
default:
JS_NOT_REACHED("Unexpected shift op");
}
default:
JS_NOT_REACHED("unexpected shift opcode");
}
return true;
@ -862,7 +871,9 @@ CodeGeneratorX86Shared::visitUrshD(LUrshD *ins)
FloatRegister out = ToFloatRegister(ins->output());
if (rhs->isConstant()) {
masm.shrl(Imm32(ToInt32(rhs) & 0x1F), lhs);
int32_t shift = ToInt32(rhs) & 0x1F;
if (shift)
masm.shrl(Imm32(shift), lhs);
} else {
JS_ASSERT(ToRegister(rhs) == ecx);
masm.shrl_cl(lhs);