Revision: 7714
Author:   [email protected]
Date:     Fri Apr 29 00:22:39 2011
Log:      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
http://code.google.com/p/v8/source/detail?r=7714

Modified:
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Apr 27 04:41:42 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Apr 29 00:22:39 2011
@@ -799,11 +799,13 @@
     __ andl(dividend, Immediate(divisor - 1));
     __ bind(&done);
   } else {
-    LOperand* right = instr->InputAt(1);
-    Register right_reg = ToRegister(right);
-
-    ASSERT(ToRegister(instr->result()).is(rdx));
-    ASSERT(ToRegister(instr->InputAt(0)).is(rax));
+ 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(left_reg.is(rax));
+    ASSERT(result_reg.is(rdx));
     ASSERT(!right_reg.is(rax));
     ASSERT(!right_reg.is(rdx));

@@ -813,6 +815,45 @@
       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 @@
     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 @@
     } else {
       __ idivl(right_reg);
     }
+    __ jmp(&done);
+
+    __ bind(&remainder_eq_dividend);
+    __ movl(result_reg, left_reg);
+
+    __ bind(&done);
   }
 }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to