Index: src/arm/lithium-codegen-arm.cc |
=================================================================== |
--- src/arm/lithium-codegen-arm.cc (revision 13153) |
+++ src/arm/lithium-codegen-arm.cc (working copy) |
@@ -1421,25 +1421,68 @@ |
const Register remainder = ToRegister(instr->temp()); |
const Register scratch = scratch0(); |
- // We only optimize this for division by constants, because the standard |
- // integer division routine is usually slower than transitionning to VFP. |
- // This could be optimized on processors with SDIV available. |
- ASSERT(instr->right()->IsConstantOperand()); |
- int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); |
- if (divisor < 0) { |
- __ cmp(left, Operand(0)); |
+ if (!CpuFeatures::IsSupported(SUDIV)) { |
+ // If the CPU doesn't support sdiv instruction, we only optimize when we |
+ // have magic numbers for the divisor. The standard integer division routine |
+ // is usually slower than transitionning to VFP. |
+ ASSERT(instr->right()->IsConstantOperand()); |
+ int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); |
+ ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); |
+ if (divisor < 0) { |
+ __ cmp(left, Operand(0)); |
+ DeoptimizeIf(eq, instr->environment()); |
+ } |
+ EmitSignedIntegerDivisionByConstant(result, |
+ left, |
+ divisor, |
+ remainder, |
+ scratch, |
+ instr->environment()); |
+ // We performed a truncating division. Correct the result if necessary. |
+ __ cmp(remainder, Operand(0)); |
+ __ teq(remainder, Operand(divisor), ne); |
+ __ sub(result, result, Operand(1), LeaveCC, mi); |
+ } else { |
+ CpuFeatures::Scope scope(SUDIV); |
+ const Register right = ToRegister(instr->right()); |
+ |
+ // Check for x / 0. |
+ __ cmp(right, Operand(0)); |
DeoptimizeIf(eq, instr->environment()); |
+ |
+ // Check for (kMinInt / -1). |
+ if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
+ Label left_not_min_int; |
+ __ cmp(left, Operand(kMinInt)); |
+ __ b(ne, &left_not_min_int); |
+ __ cmp(right, Operand(-1)); |
+ DeoptimizeIf(eq, instr->environment()); |
+ __ bind(&left_not_min_int); |
+ } |
+ |
+ // Check for (0 / -x) that will produce negative zero. |
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
+ __ cmp(right, Operand(0)); |
+ __ cmp(left, Operand(0), mi); |
+ // "right" can't be null because the code would have already been |
+ // deoptimized. The Z flag is set only if (right < 0) and (left == 0). |
+ // In this case we need to deoptimize to produce a -0. |
+ DeoptimizeIf(eq, instr->environment()); |
+ } |
+ |
+ Label done; |
+ __ sdiv(result, left, right); |
+ // If both operands have the same sign then we are done. |
+ __ eor(remainder, left, Operand(right), SetCC); |
+ __ b(pl, &done); |
+ |
+ // Check if the result needs to be corrected. |
+ __ mls(remainder, result, right, left); |
+ __ cmp(remainder, Operand(0)); |
+ __ sub(result, result, Operand(1), LeaveCC, ne); |
+ |
+ __ bind(&done); |
} |
- EmitSignedIntegerDivisionByConstant(result, |
- left, |
- divisor, |
- remainder, |
- scratch, |
- instr->environment()); |
- // We operated a truncating division. Correct the result if necessary. |
- __ cmp(remainder, Operand(0)); |
- __ teq(remainder, Operand(divisor), ne); |
- __ sub(result, result, Operand(1), LeaveCC, mi); |
} |