Improve modulo operation in lithium on x64.
This is the x64 porting of http://codereview.chromium.org/6816049/ Patch by: Yuqiang Xian from Intel Review URL: http://codereview.chromium.org//6901091 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7714 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
f6f5e5ce43
commit
122133e800
@ -799,11 +799,13 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
__ andl(dividend, Immediate(divisor - 1));
|
||||
__ bind(&done);
|
||||
} else {
|
||||
LOperand* right = instr->InputAt(1);
|
||||
Register right_reg = ToRegister(right);
|
||||
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());
|
||||
|
||||
ASSERT(ToRegister(instr->result()).is(rdx));
|
||||
ASSERT(ToRegister(instr->InputAt(0)).is(rax));
|
||||
ASSERT(left_reg.is(rax));
|
||||
ASSERT(result_reg.is(rdx));
|
||||
ASSERT(!right_reg.is(rax));
|
||||
ASSERT(!right_reg.is(rdx));
|
||||
|
||||
@ -813,6 +815,45 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
|
||||
__ testl(left_reg, left_reg);
|
||||
__ j(zero, &remainder_eq_dividend);
|
||||
__ j(sign, &slow);
|
||||
|
||||
__ testl(right_reg, 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.
|
||||
__ cmpl(left_reg, right_reg);
|
||||
__ j(less, &remainder_eq_dividend);
|
||||
|
||||
// Check if the divisor is a PowerOfTwo integer.
|
||||
Register scratch = ToRegister(instr->TempAt(0));
|
||||
__ movl(scratch, right_reg);
|
||||
__ subl(scratch, Immediate(1));
|
||||
__ testl(scratch, right_reg);
|
||||
__ j(not_zero, &do_subtraction);
|
||||
__ andl(left_reg, scratch);
|
||||
__ jmp(&remainder_eq_dividend);
|
||||
|
||||
__ 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);
|
||||
}
|
||||
__ movl(left_reg, scratch);
|
||||
|
||||
// Slow case, using idiv instruction.
|
||||
__ bind(&slow);
|
||||
// Sign extend eax to edx.
|
||||
// (We are using only the low 32 bits of the values.)
|
||||
__ cdq();
|
||||
@ -821,12 +862,12 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
NearLabel positive_left;
|
||||
NearLabel done;
|
||||
__ testl(rax, rax);
|
||||
__ testl(left_reg, left_reg);
|
||||
__ j(not_sign, &positive_left);
|
||||
__ idivl(right_reg);
|
||||
|
||||
// Test the remainder for 0, because then the result would be -0.
|
||||
__ testl(rdx, rdx);
|
||||
__ testl(result_reg, result_reg);
|
||||
__ j(not_zero, &done);
|
||||
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
@ -836,6 +877,12 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
} else {
|
||||
__ idivl(right_reg);
|
||||
}
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(&remainder_eq_dividend);
|
||||
__ movl(result_reg, left_reg);
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user