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:
vegorov@chromium.org 2011-03-14 14:42:14 +00:00
parent 4dc80f788a
commit 9b311c21b1
7 changed files with 190 additions and 78 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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