Reduce strength of ModI for power-of-2 divisor.
This is ia32 only. I will port it to other platforms if this looks good to you. Review URL: http://codereview.chromium.org/6665006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7158 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4dc80f788a
commit
9b311c21b1
@ -1350,10 +1350,21 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
|
||||
// when we provide a native implementation.
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* value = UseFixed(instr->left(), r0);
|
||||
LOperand* divisor = UseFixed(instr->right(), r1);
|
||||
LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
|
||||
result = AssignEnvironment(AssignPointerMap(result));
|
||||
|
||||
LInstruction* result;
|
||||
if (instr->HasPowerOf2Divisor()) {
|
||||
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||
LOperand* value = UseRegisterAtStart(instr->left());
|
||||
LModI* mod = new LModI(value, UseOrConstant(instr->right()));
|
||||
result = DefineSameAsFirst(mod);
|
||||
result = AssignEnvironment(result);
|
||||
} else {
|
||||
LOperand* value = UseFixed(instr->left(), r0);
|
||||
LOperand* divisor = UseFixed(instr->right(), r1);
|
||||
result = DefineFixed(new LModI(value, divisor), r0);
|
||||
result = AssignEnvironment(AssignPointerMap(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
} else if (instr->representation().IsTagged()) {
|
||||
return DoArithmeticT(Token::MOD, instr);
|
||||
|
@ -796,6 +796,30 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoModI(LModI* instr) {
|
||||
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||
Register dividend = ToRegister(instr->InputAt(0));
|
||||
|
||||
int32_t divisor =
|
||||
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||
|
||||
if (divisor < 0) divisor = -divisor;
|
||||
|
||||
Label positive_dividend, done;
|
||||
__ tst(dividend, Operand(dividend));
|
||||
__ b(pl, &positive_dividend);
|
||||
__ rsb(dividend, dividend, Operand(0));
|
||||
__ and_(dividend, dividend, Operand(divisor - 1));
|
||||
__ rsb(dividend, dividend, Operand(0), SetCC);
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
__ b(ne, &done);
|
||||
DeoptimizeIf(al, instr->environment());
|
||||
}
|
||||
__ bind(&positive_dividend);
|
||||
__ and_(dividend, dividend, Operand(divisor - 1));
|
||||
__ bind(&done);
|
||||
return;
|
||||
}
|
||||
|
||||
class DeferredModI: public LDeferredCode {
|
||||
public:
|
||||
DeferredModI(LCodeGen* codegen, LModI* instr)
|
||||
@ -856,6 +880,7 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
__ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
|
||||
// Perform modulo operation (scratch contains right - 1).
|
||||
__ and_(result, scratch, Operand(left));
|
||||
__ b(&done);
|
||||
|
||||
__ bind(&call_stub);
|
||||
// Call the stub. The numbers in r0 and r1 have
|
||||
|
@ -2567,6 +2567,16 @@ class HMod: public HArithmeticBinaryOperation {
|
||||
SetFlag(kCanBeDivByZero);
|
||||
}
|
||||
|
||||
bool HasPowerOf2Divisor() {
|
||||
if (right()->IsConstant() &&
|
||||
HConstant::cast(right())->HasInteger32Value()) {
|
||||
int32_t value = HConstant::cast(right())->Integer32Value();
|
||||
return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
|
||||
|
@ -781,41 +781,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoModI(LModI* instr) {
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(ToRegister(instr->result()).is(edx));
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(eax));
|
||||
ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
|
||||
ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
|
||||
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||
Register dividend = ToRegister(instr->InputAt(0));
|
||||
|
||||
Register right_reg = ToRegister(right);
|
||||
int32_t divisor =
|
||||
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||
|
||||
// Check for x % 0.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
||||
__ test(right_reg, ToOperand(right));
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
if (divisor < 0) divisor = -divisor;
|
||||
|
||||
// Sign extend to edx.
|
||||
__ cdq();
|
||||
|
||||
// Check for (0 % -x) that will produce negative zero.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
NearLabel positive_left;
|
||||
NearLabel done;
|
||||
__ test(eax, Operand(eax));
|
||||
__ j(not_sign, &positive_left);
|
||||
__ idiv(right_reg);
|
||||
|
||||
// Test the remainder for 0, because then the result would be -0.
|
||||
__ test(edx, Operand(edx));
|
||||
__ j(not_zero, &done);
|
||||
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
__ bind(&positive_left);
|
||||
__ idiv(right_reg);
|
||||
NearLabel positive_dividend, done;
|
||||
__ test(dividend, Operand(dividend));
|
||||
__ j(not_sign, &positive_dividend);
|
||||
__ neg(dividend);
|
||||
__ and_(dividend, divisor - 1);
|
||||
__ neg(dividend);
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
__ j(not_zero, &done);
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
}
|
||||
__ bind(&positive_dividend);
|
||||
__ and_(dividend, divisor - 1);
|
||||
__ bind(&done);
|
||||
} else {
|
||||
__ idiv(right_reg);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(eax));
|
||||
ASSERT(ToRegister(instr->result()).is(edx));
|
||||
|
||||
Register right_reg = ToRegister(right);
|
||||
ASSERT(!right_reg.is(eax));
|
||||
ASSERT(!right_reg.is(edx));
|
||||
|
||||
// Check for x % 0.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
||||
__ test(right_reg, ToOperand(right));
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
|
||||
// Sign extend to edx.
|
||||
__ cdq();
|
||||
|
||||
// Check for (0 % -x) that will produce negative zero.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
NearLabel positive_left;
|
||||
NearLabel done;
|
||||
__ test(eax, Operand(eax));
|
||||
__ j(not_sign, &positive_left);
|
||||
__ idiv(right_reg);
|
||||
|
||||
// Test the remainder for 0, because then the result would be -0.
|
||||
__ test(edx, Operand(edx));
|
||||
__ j(not_zero, &done);
|
||||
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
__ bind(&positive_left);
|
||||
__ idiv(right_reg);
|
||||
__ bind(&done);
|
||||
} else {
|
||||
__ idiv(right_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1366,13 +1366,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
// The temporary operand is necessary to ensure that right is not allocated
|
||||
// into edx.
|
||||
LOperand* temp = FixedTemp(edx);
|
||||
LOperand* value = UseFixed(instr->left(), eax);
|
||||
LOperand* divisor = UseRegister(instr->right());
|
||||
LModI* mod = new LModI(value, divisor, temp);
|
||||
LInstruction* result = DefineFixed(mod, edx);
|
||||
|
||||
LInstruction* result;
|
||||
if (instr->HasPowerOf2Divisor()) {
|
||||
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||
LOperand* value = UseRegisterAtStart(instr->left());
|
||||
LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
|
||||
result = DefineSameAsFirst(mod);
|
||||
} else {
|
||||
// The temporary operand is necessary to ensure that right is
|
||||
// not allocated into edx.
|
||||
LOperand* temp = FixedTemp(edx);
|
||||
LOperand* value = UseFixed(instr->left(), eax);
|
||||
LOperand* divisor = UseRegister(instr->right());
|
||||
LModI* mod = new LModI(value, divisor, temp);
|
||||
result = DefineFixed(mod, edx);
|
||||
}
|
||||
|
||||
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
||||
instr->CheckFlag(HValue::kCanBeDivByZero))
|
||||
? AssignEnvironment(result)
|
||||
|
@ -752,41 +752,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoModI(LModI* instr) {
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(ToRegister(instr->result()).is(rdx));
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(rax));
|
||||
ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
|
||||
ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
|
||||
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||
Register dividend = ToRegister(instr->InputAt(0));
|
||||
|
||||
Register right_reg = ToRegister(right);
|
||||
int32_t divisor =
|
||||
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||
|
||||
// Check for x % 0.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
||||
__ testl(right_reg, right_reg);
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
if (divisor < 0) divisor = -divisor;
|
||||
|
||||
// Sign extend eax to edx. (We are using only the low 32 bits of the values.)
|
||||
__ cdq();
|
||||
|
||||
// Check for (0 % -x) that will produce negative zero.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
NearLabel positive_left;
|
||||
NearLabel done;
|
||||
__ testl(rax, rax);
|
||||
__ j(not_sign, &positive_left);
|
||||
__ idivl(right_reg);
|
||||
|
||||
// Test the remainder for 0, because then the result would be -0.
|
||||
__ testl(rdx, rdx);
|
||||
__ j(not_zero, &done);
|
||||
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
__ bind(&positive_left);
|
||||
__ idivl(right_reg);
|
||||
NearLabel positive_dividend, done;
|
||||
__ testl(dividend, dividend);
|
||||
__ j(not_sign, &positive_dividend);
|
||||
__ negl(dividend);
|
||||
__ andl(dividend, Immediate(divisor - 1));
|
||||
__ negl(dividend);
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
__ j(not_zero, &done);
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
}
|
||||
__ bind(&positive_dividend);
|
||||
__ andl(dividend, Immediate(divisor - 1));
|
||||
__ bind(&done);
|
||||
} else {
|
||||
__ idivl(right_reg);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
Register right_reg = ToRegister(right);
|
||||
|
||||
ASSERT(ToRegister(instr->result()).is(rdx));
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(rax));
|
||||
ASSERT(!right_reg.is(rax));
|
||||
ASSERT(!right_reg.is(rdx));
|
||||
|
||||
// Check for x % 0.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
||||
__ testl(right_reg, right_reg);
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
|
||||
// Sign extend eax to edx. (We are using only the low 32 bits of the values.)
|
||||
__ cdq();
|
||||
|
||||
// Check for (0 % -x) that will produce negative zero.
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
NearLabel positive_left;
|
||||
NearLabel done;
|
||||
__ testl(rax, rax);
|
||||
__ j(not_sign, &positive_left);
|
||||
__ idivl(right_reg);
|
||||
|
||||
// Test the remainder for 0, because then the result would be -0.
|
||||
__ testl(rdx, rdx);
|
||||
__ j(not_zero, &done);
|
||||
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
__ bind(&positive_left);
|
||||
__ idivl(right_reg);
|
||||
__ bind(&done);
|
||||
} else {
|
||||
__ idivl(right_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1347,13 +1347,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
// The temporary operand is necessary to ensure that right is not allocated
|
||||
// into edx.
|
||||
LOperand* temp = FixedTemp(rdx);
|
||||
LOperand* value = UseFixed(instr->left(), rax);
|
||||
LOperand* divisor = UseRegister(instr->right());
|
||||
LModI* mod = new LModI(value, divisor, temp);
|
||||
LInstruction* result = DefineFixed(mod, rdx);
|
||||
|
||||
LInstruction* result;
|
||||
if (instr->HasPowerOf2Divisor()) {
|
||||
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||
LOperand* value = UseRegisterAtStart(instr->left());
|
||||
LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
|
||||
result = DefineSameAsFirst(mod);
|
||||
} else {
|
||||
// The temporary operand is necessary to ensure that right is not allocated
|
||||
// into edx.
|
||||
LOperand* temp = FixedTemp(rdx);
|
||||
LOperand* value = UseFixed(instr->left(), rax);
|
||||
LOperand* divisor = UseRegister(instr->right());
|
||||
LModI* mod = new LModI(value, divisor, temp);
|
||||
result = DefineFixed(mod, rdx);
|
||||
}
|
||||
|
||||
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
||||
instr->CheckFlag(HValue::kCanBeDivByZero))
|
||||
? AssignEnvironment(result)
|
||||
|
Loading…
Reference in New Issue
Block a user