diff --git a/AUTHORS b/AUTHORS index 843d1d2a09..57b155fa69 100644 --- a/AUTHORS +++ b/AUTHORS @@ -39,4 +39,5 @@ Ryan Dahl Sanjoy Das Subrato K De Vlad Burlik +Yuqiang Xian Zaheer Ahmad diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 9e636f7523..07ee7d62dc 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -799,20 +799,61 @@ void LCodeGen::DoModI(LModI* instr) { __ and_(dividend, divisor - 1); __ bind(&done); } else { - LOperand* right = instr->InputAt(1); - ASSERT(ToRegister(instr->InputAt(0)).is(eax)); - ASSERT(ToRegister(instr->result()).is(edx)); + NearLabel done, remainder_eq_dividend, slow, do_subtraction, both_positive; + Register left_reg = ToRegister(instr->InputAt(0)); + Register right_reg = ToRegister(instr->InputAt(1)); + Register result_reg = ToRegister(instr->result()); - Register right_reg = ToRegister(right); + ASSERT(left_reg.is(eax)); + ASSERT(result_reg.is(edx)); 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)); + __ test(right_reg, Operand(right_reg)); DeoptimizeIf(zero, instr->environment()); } + __ test(left_reg, Operand(left_reg)); + __ j(zero, &remainder_eq_dividend); + __ j(sign, &slow); + + __ test(right_reg, Operand(right_reg)); + __ j(not_sign, &both_positive); + // The sign of the divisor doesn't matter. + __ neg(right_reg); + + __ bind(&both_positive); + // If the dividend is smaller than the nonnegative + // divisor, the dividend is the result. + __ cmp(left_reg, Operand(right_reg)); + __ j(less, &remainder_eq_dividend); + + // Check if the divisor is a PowerOfTwo integer. + Register scratch = ToRegister(instr->TempAt(0)); + __ mov(scratch, right_reg); + __ sub(Operand(scratch), Immediate(1)); + __ test(scratch, Operand(right_reg)); + __ j(not_zero, &do_subtraction); + __ and_(left_reg, Operand(scratch)); + __ jmp(&remainder_eq_dividend); + + __ 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); + } + __ mov(left_reg, scratch); + + // Slow case, using idiv instruction. + __ bind(&slow); // Sign extend to edx. __ cdq(); @@ -820,12 +861,12 @@ void LCodeGen::DoModI(LModI* instr) { if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { NearLabel positive_left; NearLabel done; - __ test(eax, Operand(eax)); + __ test(left_reg, Operand(left_reg)); __ j(not_sign, &positive_left); __ idiv(right_reg); // Test the remainder for 0, because then the result would be -0. - __ test(edx, Operand(edx)); + __ test(result_reg, Operand(result_reg)); __ j(not_zero, &done); DeoptimizeIf(no_condition, instr->environment()); @@ -835,6 +876,12 @@ void LCodeGen::DoModI(LModI* instr) { } else { __ idiv(right_reg); } + __ jmp(&done); + + __ bind(&remainder_eq_dividend); + __ mov(result_reg, left_reg); + + __ bind(&done); } }