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) 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) if (imm == 1)
m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
else { else {
@ -983,6 +985,8 @@ public:
void shrl_CLr(RegisterID dst) 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); 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 // Shift operation, taking two 32-bit integers as inputs and returning
// a 32-bit integer result as an output. // a 32-bit integer result as an output.
class LShiftI : public LInstructionHelper<1, 2, 0> class LShiftI : public LBinaryMath<0>
{ {
JSOp op_; JSOp op_;

View File

@ -680,67 +680,66 @@ CodeGeneratorARM::visitBitOpI(LBitOpI *ins)
bool bool
CodeGeneratorARM::visitShiftI(LShiftI *ins) CodeGeneratorARM::visitShiftI(LShiftI *ins)
{ {
const LAllocation *lhs = ins->getOperand(0); Register lhs = ToRegister(ins->lhs());
const LAllocation *rhs = ins->getOperand(1); const LAllocation *rhs = ins->rhs();
const LDefinition *dest = ins->getDef(0); Register dest = ToRegister(ins->output());
// The shift amounts should be AND'ed into the 0-31 range since arm shifts if (rhs->isConstant()) {
// by the lower byte of the register (it will attempt to shift by 250 if you int32_t shift = ToInt32(rhs) & 0x1F;
// ask it to, and the result will probably not be what you want. switch (ins->bitop()) {
if (!rhs->isConstant()) { case JSOP_LSH:
masm.ma_and(Imm32(0x1f), ToRegister(rhs), ToRegister(dest)); if (shift)
rhs = dest->output(); masm.ma_lsl(Imm32(shift), lhs, dest);
else
masm.ma_mov(lhs, dest);
break;
case JSOP_RSH:
if (shift)
masm.ma_asr(Imm32(shift), lhs, dest);
else
masm.ma_mov(lhs, dest);
break;
case JSOP_URSH:
if (shift) {
masm.ma_lsr(Imm32(shift), lhs, dest);
} else {
// 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()) { switch (ins->bitop()) {
case JSOP_LSH: case JSOP_LSH:
if (rhs->isConstant()) { masm.ma_lsl(dest, lhs, dest);
masm.ma_lsl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs), ToRegister(dest));
} else {
masm.ma_lsl(ToRegister(rhs), ToRegister(lhs), ToRegister(dest));
}
break; break;
case JSOP_RSH: case JSOP_RSH:
if (rhs->isConstant()) { masm.ma_asr(dest, lhs, dest);
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));
}
break; break;
case JSOP_URSH: { case JSOP_URSH:
MUrsh *ursh = ins->mir()->toUrsh(); masm.ma_lsr(dest, lhs, dest);
if (rhs->isConstant()) { if (ins->mir()->toUrsh()->canOverflow()) {
if ((ToInt32(rhs) & 0x1f) != 0) { // x >>> 0 can overflow.
masm.ma_lsr(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs), ToRegister(dest)); masm.ma_cmp(dest, Imm32(0));
} else { if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
masm.ma_mov(ToRegister(lhs), ToRegister(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; return false;
} }
}
break; break;
}
default: default:
JS_NOT_REACHED("unexpected shift opcode"); JS_NOT_REACHED("Unexpected shift op");
return false; }
} }
return true; return true;
@ -756,12 +755,13 @@ CodeGeneratorARM::visitUrshD(LUrshD *ins)
FloatRegister out = ToFloatRegister(ins->output()); FloatRegister out = ToFloatRegister(ins->output());
if (rhs->isConstant()) { if (rhs->isConstant()) {
if ((ToInt32(rhs) & 0x1f) != 0) int32_t shift = ToInt32(rhs) & 0x1F;
masm.ma_lsr(Imm32(ToInt32(rhs) & 0x1F), lhs, temp); if (shift)
masm.ma_lsr(Imm32(shift), lhs, temp);
else else
masm.ma_mov(lhs, temp); masm.ma_mov(lhs, temp);
} else { } else {
masm.ma_and(Imm32(0x1f), ToRegister(rhs), temp); masm.ma_and(Imm32(0x1F), ToRegister(rhs), temp);
masm.ma_lsr(temp, lhs, 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(0, useRegister(lhs));
ins->setOperand(1, useRegisterOrConstant(rhs)); ins->setOperand(1, useRegisterOrConstant(rhs));
return define(ins, mir, return define(ins, mir);
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
} }
bool bool

View File

@ -808,45 +808,54 @@ CodeGeneratorX86Shared::visitBitOpI(LBitOpI *ins)
bool bool
CodeGeneratorX86Shared::visitShiftI(LShiftI *ins) CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
{ {
const LAllocation *lhs = ins->getOperand(0); Register lhs = ToRegister(ins->lhs());
const LAllocation *rhs = ins->getOperand(1); const LAllocation *rhs = ins->rhs();
if (rhs->isConstant()) {
int32_t shift = ToInt32(rhs) & 0x1F;
switch (ins->bitop()) { switch (ins->bitop()) {
case JSOP_LSH: case JSOP_LSH:
if (rhs->isConstant()) if (shift)
masm.shll(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs)); masm.shll(Imm32(shift), lhs);
else
masm.shll_cl(ToRegister(lhs));
break; break;
case JSOP_RSH: case JSOP_RSH:
if (rhs->isConstant()) if (shift)
masm.sarl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs)); masm.sarl(Imm32(shift), lhs);
else
masm.sarl_cl(ToRegister(lhs));
break; break;
case JSOP_URSH: { case JSOP_URSH:
MUrsh *ursh = ins->mir()->toUrsh(); if (shift) {
if (rhs->isConstant()) masm.shrl(Imm32(shift), lhs);
masm.shrl(Imm32(ToInt32(rhs) & 0x1F), ToRegister(lhs)); } else if (ins->mir()->toUrsh()->canOverflow()) {
else // x >>> 0 can overflow.
masm.shrl_cl(ToRegister(lhs)); masm.testl(lhs, lhs);
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
// 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()))
return false; return false;
} }
break; break;
}
default: default:
JS_NOT_REACHED("unexpected shift opcode"); 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");
}
} }
return true; return true;
@ -862,7 +871,9 @@ CodeGeneratorX86Shared::visitUrshD(LUrshD *ins)
FloatRegister out = ToFloatRegister(ins->output()); FloatRegister out = ToFloatRegister(ins->output());
if (rhs->isConstant()) { if (rhs->isConstant()) {
masm.shrl(Imm32(ToInt32(rhs) & 0x1F), lhs); int32_t shift = ToInt32(rhs) & 0x1F;
if (shift)
masm.shrl(Imm32(shift), lhs);
} else { } else {
JS_ASSERT(ToRegister(rhs) == ecx); JS_ASSERT(ToRegister(rhs) == ecx);
masm.shrl_cl(lhs); masm.shrl_cl(lhs);