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.
|
// when we provide a native implementation.
|
||||||
ASSERT(instr->left()->representation().IsInteger32());
|
ASSERT(instr->left()->representation().IsInteger32());
|
||||||
ASSERT(instr->right()->representation().IsInteger32());
|
ASSERT(instr->right()->representation().IsInteger32());
|
||||||
LOperand* value = UseFixed(instr->left(), r0);
|
|
||||||
LOperand* divisor = UseFixed(instr->right(), r1);
|
LInstruction* result;
|
||||||
LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
|
if (instr->HasPowerOf2Divisor()) {
|
||||||
result = AssignEnvironment(AssignPointerMap(result));
|
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;
|
return result;
|
||||||
} else if (instr->representation().IsTagged()) {
|
} else if (instr->representation().IsTagged()) {
|
||||||
return DoArithmeticT(Token::MOD, instr);
|
return DoArithmeticT(Token::MOD, instr);
|
||||||
|
@ -796,6 +796,30 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoModI(LModI* 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 {
|
class DeferredModI: public LDeferredCode {
|
||||||
public:
|
public:
|
||||||
DeferredModI(LCodeGen* codegen, LModI* instr)
|
DeferredModI(LCodeGen* codegen, LModI* instr)
|
||||||
@ -856,6 +880,7 @@ void LCodeGen::DoModI(LModI* instr) {
|
|||||||
__ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
|
__ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
|
||||||
// Perform modulo operation (scratch contains right - 1).
|
// Perform modulo operation (scratch contains right - 1).
|
||||||
__ and_(result, scratch, Operand(left));
|
__ and_(result, scratch, Operand(left));
|
||||||
|
__ b(&done);
|
||||||
|
|
||||||
__ bind(&call_stub);
|
__ bind(&call_stub);
|
||||||
// Call the stub. The numbers in r0 and r1 have
|
// Call the stub. The numbers in r0 and r1 have
|
||||||
|
@ -2567,6 +2567,16 @@ class HMod: public HArithmeticBinaryOperation {
|
|||||||
SetFlag(kCanBeDivByZero);
|
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);
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
|
DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
|
||||||
|
@ -781,41 +781,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoModI(LModI* instr) {
|
void LCodeGen::DoModI(LModI* instr) {
|
||||||
LOperand* right = instr->InputAt(1);
|
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||||
ASSERT(ToRegister(instr->result()).is(edx));
|
Register dividend = ToRegister(instr->InputAt(0));
|
||||||
ASSERT(ToRegister(instr->InputAt(0)).is(eax));
|
|
||||||
ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
|
|
||||||
ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
|
|
||||||
|
|
||||||
Register right_reg = ToRegister(right);
|
int32_t divisor =
|
||||||
|
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||||
|
|
||||||
// Check for x % 0.
|
if (divisor < 0) divisor = -divisor;
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
|
||||||
__ test(right_reg, ToOperand(right));
|
|
||||||
DeoptimizeIf(zero, instr->environment());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign extend to edx.
|
NearLabel positive_dividend, done;
|
||||||
__ cdq();
|
__ test(dividend, Operand(dividend));
|
||||||
|
__ j(not_sign, &positive_dividend);
|
||||||
// Check for (0 % -x) that will produce negative zero.
|
__ neg(dividend);
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
__ and_(dividend, divisor - 1);
|
||||||
NearLabel positive_left;
|
__ neg(dividend);
|
||||||
NearLabel done;
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
__ test(eax, Operand(eax));
|
__ j(not_zero, &done);
|
||||||
__ j(not_sign, &positive_left);
|
DeoptimizeIf(no_condition, instr->environment());
|
||||||
__ idiv(right_reg);
|
}
|
||||||
|
__ bind(&positive_dividend);
|
||||||
// Test the remainder for 0, because then the result would be -0.
|
__ and_(dividend, divisor - 1);
|
||||||
__ test(edx, Operand(edx));
|
|
||||||
__ j(not_zero, &done);
|
|
||||||
|
|
||||||
DeoptimizeIf(no_condition, instr->environment());
|
|
||||||
__ bind(&positive_left);
|
|
||||||
__ idiv(right_reg);
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
} else {
|
} 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()) {
|
if (instr->representation().IsInteger32()) {
|
||||||
ASSERT(instr->left()->representation().IsInteger32());
|
ASSERT(instr->left()->representation().IsInteger32());
|
||||||
ASSERT(instr->right()->representation().IsInteger32());
|
ASSERT(instr->right()->representation().IsInteger32());
|
||||||
// The temporary operand is necessary to ensure that right is not allocated
|
|
||||||
// into edx.
|
LInstruction* result;
|
||||||
LOperand* temp = FixedTemp(edx);
|
if (instr->HasPowerOf2Divisor()) {
|
||||||
LOperand* value = UseFixed(instr->left(), eax);
|
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||||
LOperand* divisor = UseRegister(instr->right());
|
LOperand* value = UseRegisterAtStart(instr->left());
|
||||||
LModI* mod = new LModI(value, divisor, temp);
|
LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
|
||||||
LInstruction* result = DefineFixed(mod, edx);
|
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) ||
|
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
||||||
instr->CheckFlag(HValue::kCanBeDivByZero))
|
instr->CheckFlag(HValue::kCanBeDivByZero))
|
||||||
? AssignEnvironment(result)
|
? AssignEnvironment(result)
|
||||||
|
@ -752,41 +752,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoModI(LModI* instr) {
|
void LCodeGen::DoModI(LModI* instr) {
|
||||||
LOperand* right = instr->InputAt(1);
|
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||||
ASSERT(ToRegister(instr->result()).is(rdx));
|
Register dividend = ToRegister(instr->InputAt(0));
|
||||||
ASSERT(ToRegister(instr->InputAt(0)).is(rax));
|
|
||||||
ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
|
|
||||||
ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
|
|
||||||
|
|
||||||
Register right_reg = ToRegister(right);
|
int32_t divisor =
|
||||||
|
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||||
|
|
||||||
// Check for x % 0.
|
if (divisor < 0) divisor = -divisor;
|
||||||
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.)
|
NearLabel positive_dividend, done;
|
||||||
__ cdq();
|
__ testl(dividend, dividend);
|
||||||
|
__ j(not_sign, &positive_dividend);
|
||||||
// Check for (0 % -x) that will produce negative zero.
|
__ negl(dividend);
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
__ andl(dividend, Immediate(divisor - 1));
|
||||||
NearLabel positive_left;
|
__ negl(dividend);
|
||||||
NearLabel done;
|
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||||
__ testl(rax, rax);
|
__ j(not_zero, &done);
|
||||||
__ j(not_sign, &positive_left);
|
DeoptimizeIf(no_condition, instr->environment());
|
||||||
__ idivl(right_reg);
|
}
|
||||||
|
__ bind(&positive_dividend);
|
||||||
// Test the remainder for 0, because then the result would be -0.
|
__ andl(dividend, Immediate(divisor - 1));
|
||||||
__ testl(rdx, rdx);
|
|
||||||
__ j(not_zero, &done);
|
|
||||||
|
|
||||||
DeoptimizeIf(no_condition, instr->environment());
|
|
||||||
__ bind(&positive_left);
|
|
||||||
__ idivl(right_reg);
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
} else {
|
} 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()) {
|
if (instr->representation().IsInteger32()) {
|
||||||
ASSERT(instr->left()->representation().IsInteger32());
|
ASSERT(instr->left()->representation().IsInteger32());
|
||||||
ASSERT(instr->right()->representation().IsInteger32());
|
ASSERT(instr->right()->representation().IsInteger32());
|
||||||
// The temporary operand is necessary to ensure that right is not allocated
|
|
||||||
// into edx.
|
LInstruction* result;
|
||||||
LOperand* temp = FixedTemp(rdx);
|
if (instr->HasPowerOf2Divisor()) {
|
||||||
LOperand* value = UseFixed(instr->left(), rax);
|
ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||||
LOperand* divisor = UseRegister(instr->right());
|
LOperand* value = UseRegisterAtStart(instr->left());
|
||||||
LModI* mod = new LModI(value, divisor, temp);
|
LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
|
||||||
LInstruction* result = DefineFixed(mod, rdx);
|
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) ||
|
return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
||||||
instr->CheckFlag(HValue::kCanBeDivByZero))
|
instr->CheckFlag(HValue::kCanBeDivByZero))
|
||||||
? AssignEnvironment(result)
|
? AssignEnvironment(result)
|
||||||
|
Loading…
Reference in New Issue
Block a user