Do not use repeated subtractions in mod-i, it hurts performance in general.

ARM only: Check for -0 only when really necessary. Tiny code de-duplication.

R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/14499011

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14479 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0c63e8d6
...@@ -1165,14 +1165,14 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1165,14 +1165,14 @@ void LCodeGen::DoModI(LModI* instr) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Label done; Label done;
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
// Check for x % 0. // Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
__ cmp(right, Operand::Zero()); __ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment()); DeoptimizeIf(eq, instr->environment());
} }
if (CpuFeatures::IsSupported(SUDIV)) {
CpuFeatureScope scope(masm(), SUDIV);
// Check for (kMinInt % -1). // Check for (kMinInt % -1).
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
Label left_not_min_int; Label left_not_min_int;
...@@ -1189,12 +1189,12 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1189,12 +1189,12 @@ void LCodeGen::DoModI(LModI* instr) {
__ sdiv(result, left, right); __ sdiv(result, left, right);
__ mls(result, result, right, left); __ mls(result, result, right, left);
__ cmp(result, Operand::Zero());
__ b(ne, &done);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cmp(left, Operand::Zero()); __ cmp(result, Operand::Zero());
DeoptimizeIf(lt, instr->environment()); __ b(ne, &done);
__ cmp(left, Operand::Zero());
DeoptimizeIf(lt, instr->environment());
} }
} else { } else {
Register scratch = scratch0(); Register scratch = scratch0();
...@@ -1210,13 +1210,7 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1210,13 +1210,7 @@ void LCodeGen::DoModI(LModI* instr) {
ASSERT(!scratch.is(right)); ASSERT(!scratch.is(right));
ASSERT(!scratch.is(result)); ASSERT(!scratch.is(result));
Label vfp_modulo, both_positive, right_negative; Label vfp_modulo, right_negative;
// Check for x % 0.
if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
__ cmp(right, Operand::Zero());
DeoptimizeIf(eq, instr->environment());
}
__ Move(result, left); __ Move(result, left);
...@@ -1234,7 +1228,7 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1234,7 +1228,7 @@ void LCodeGen::DoModI(LModI* instr) {
__ JumpIfNotPowerOfTwoOrZeroAndNeg(right, __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
scratch, scratch,
&right_negative, &right_negative,
&both_positive); &vfp_modulo);
// 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); __ b(&done);
...@@ -1243,23 +1237,6 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1243,23 +1237,6 @@ void LCodeGen::DoModI(LModI* instr) {
// Negate right. The sign of the divisor does not matter. // Negate right. The sign of the divisor does not matter.
__ rsb(right, right, Operand::Zero()); __ rsb(right, right, Operand::Zero());
__ bind(&both_positive);
const int kUnfolds = 3;
// If the right hand side is smaller than the (nonnegative)
// left hand side, the left hand side is the result.
// Else try a few subtractions of the left hand side.
__ mov(scratch, left);
for (int i = 0; i < kUnfolds; i++) {
// Check if the left hand side is less or equal than the
// the right hand side.
__ cmp(scratch, Operand(right));
__ mov(result, scratch, LeaveCC, lt);
__ b(lt, &done);
// If not, reduce the left hand side by the right hand
// side and check again.
if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
}
__ bind(&vfp_modulo); __ bind(&vfp_modulo);
// Load the arguments in VFP registers. // Load the arguments in VFP registers.
// The divisor value is preloaded before. Be careful that 'right' // The divisor value is preloaded before. Be careful that 'right'
......
...@@ -1234,7 +1234,7 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1234,7 +1234,7 @@ void LCodeGen::DoModI(LModI* instr) {
__ and_(dividend, divisor - 1); __ and_(dividend, divisor - 1);
__ bind(&done); __ bind(&done);
} else { } else {
Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; Label done, remainder_eq_dividend, slow, both_positive;
Register left_reg = ToRegister(instr->left()); Register left_reg = ToRegister(instr->left());
Register right_reg = ToRegister(instr->right()); Register right_reg = ToRegister(instr->right());
Register result_reg = ToRegister(instr->result()); Register result_reg = ToRegister(instr->result());
...@@ -1270,23 +1270,10 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1270,23 +1270,10 @@ void LCodeGen::DoModI(LModI* instr) {
__ mov(scratch, right_reg); __ mov(scratch, right_reg);
__ sub(Operand(scratch), Immediate(1)); __ sub(Operand(scratch), Immediate(1));
__ test(scratch, Operand(right_reg)); __ test(scratch, Operand(right_reg));
__ j(not_zero, &do_subtraction, Label::kNear); __ j(not_zero, &slow, Label::kNear);
__ and_(left_reg, Operand(scratch)); __ and_(left_reg, Operand(scratch));
__ jmp(&remainder_eq_dividend, Label::kNear); __ jmp(&remainder_eq_dividend, Label::kNear);
__ bind(&do_subtraction);
const int kUnfolds = 3;
// Try a few subtractions of the dividend.
__ mov(scratch, left_reg);
for (int i = 0; i < kUnfolds; i++) {
// Reduce the dividend by the divisor.
__ sub(left_reg, Operand(right_reg));
// Check if the dividend is less than the divisor.
__ cmp(left_reg, Operand(right_reg));
__ j(less, &remainder_eq_dividend, Label::kNear);
}
__ mov(left_reg, scratch);
// Slow case, using idiv instruction. // Slow case, using idiv instruction.
__ bind(&slow); __ bind(&slow);
......
...@@ -1037,7 +1037,7 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1037,7 +1037,7 @@ void LCodeGen::DoModI(LModI* instr) {
__ andl(dividend, Immediate(divisor - 1)); __ andl(dividend, Immediate(divisor - 1));
__ bind(&done); __ bind(&done);
} else { } else {
Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; Label done, remainder_eq_dividend, slow, both_positive;
Register left_reg = ToRegister(instr->left()); Register left_reg = ToRegister(instr->left());
Register right_reg = ToRegister(instr->right()); Register right_reg = ToRegister(instr->right());
Register result_reg = ToRegister(instr->result()); Register result_reg = ToRegister(instr->result());
...@@ -1073,23 +1073,10 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1073,23 +1073,10 @@ void LCodeGen::DoModI(LModI* instr) {
__ movl(scratch, right_reg); __ movl(scratch, right_reg);
__ subl(scratch, Immediate(1)); __ subl(scratch, Immediate(1));
__ testl(scratch, right_reg); __ testl(scratch, right_reg);
__ j(not_zero, &do_subtraction, Label::kNear); __ j(not_zero, &slow, Label::kNear);
__ andl(left_reg, scratch); __ andl(left_reg, scratch);
__ jmp(&remainder_eq_dividend, Label::kNear); __ jmp(&remainder_eq_dividend, Label::kNear);
__ bind(&do_subtraction);
const int kUnfolds = 3;
// Try a few subtractions of the dividend.
__ movl(scratch, left_reg);
for (int i = 0; i < kUnfolds; i++) {
// Reduce the dividend by the divisor.
__ subl(left_reg, right_reg);
// Check if the dividend is less than the divisor.
__ cmpl(left_reg, right_reg);
__ j(less, &remainder_eq_dividend, Label::kNear);
}
__ movl(left_reg, scratch);
// Slow case, using idiv instruction. // Slow case, using idiv instruction.
__ bind(&slow); __ bind(&slow);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment