Reduce strength of ModI for power-of-2 divisor.
authorvegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 14 Mar 2011 14:42:14 +0000 (14:42 +0000)
committervegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 14 Mar 2011 14:42:14 +0000 (14:42 +0000)
This is ia32 only. I will port it to other platforms if this looks good to you.

Review URL: http://codereview.chromium.org/6665006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7158 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/hydrogen-instructions.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc

index c5b0c1d..fb7c103 100644 (file)
@@ -1350,10 +1350,21 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
     // when we provide a native implementation.
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
-    LOperand* value = UseFixed(instr->left(), r0);
-    LOperand* divisor = UseFixed(instr->right(), r1);
-    LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
-    result = AssignEnvironment(AssignPointerMap(result));
+
+    LInstruction* result;
+    if (instr->HasPowerOf2Divisor()) {
+      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+      LOperand* value = UseRegisterAtStart(instr->left());
+      LModI* mod = new LModI(value, UseOrConstant(instr->right()));
+      result = DefineSameAsFirst(mod);
+      result = AssignEnvironment(result);
+    } else {
+      LOperand* value = UseFixed(instr->left(), r0);
+      LOperand* divisor = UseFixed(instr->right(), r1);
+      result = DefineFixed(new LModI(value, divisor), r0);
+      result = AssignEnvironment(AssignPointerMap(result));
+    }
+
     return result;
   } else if (instr->representation().IsTagged()) {
     return DoArithmeticT(Token::MOD, instr);
index 8dd35b6..34a826e 100644 (file)
@@ -796,6 +796,30 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
 
 
 void LCodeGen::DoModI(LModI* instr) {
+  if (instr->hydrogen()->HasPowerOf2Divisor()) {
+    Register dividend = ToRegister(instr->InputAt(0));
+
+    int32_t divisor =
+        HConstant::cast(instr->hydrogen()->right())->Integer32Value();
+
+    if (divisor < 0) divisor = -divisor;
+
+    Label positive_dividend, done;
+    __ tst(dividend, Operand(dividend));
+    __ b(pl, &positive_dividend);
+    __ rsb(dividend, dividend, Operand(0));
+    __ and_(dividend, dividend, Operand(divisor - 1));
+    __ rsb(dividend, dividend, Operand(0), SetCC);
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ b(ne, &done);
+      DeoptimizeIf(al, instr->environment());
+    }
+    __ bind(&positive_dividend);
+    __ and_(dividend, dividend, Operand(divisor - 1));
+    __ bind(&done);
+    return;
+  }
+
   class DeferredModI: public LDeferredCode {
    public:
     DeferredModI(LCodeGen* codegen, LModI* instr)
@@ -856,6 +880,7 @@ void LCodeGen::DoModI(LModI* instr) {
   __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
   // Perform modulo operation (scratch contains right - 1).
   __ and_(result, scratch, Operand(left));
+  __ b(&done);
 
   __ bind(&call_stub);
   // Call the stub. The numbers in r0 and r1 have
index 6c516f2..2178184 100644 (file)
@@ -2567,6 +2567,16 @@ class HMod: public HArithmeticBinaryOperation {
     SetFlag(kCanBeDivByZero);
   }
 
+  bool HasPowerOf2Divisor() {
+    if (right()->IsConstant() &&
+        HConstant::cast(right())->HasInteger32Value()) {
+      int32_t value = HConstant::cast(right())->Integer32Value();
+      return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
+    }
+
+    return false;
+  }
+
   virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
 
   DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
index 28f4679..5e7f528 100644 (file)
@@ -781,41 +781,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
 
 
 void LCodeGen::DoModI(LModI* instr) {
-  LOperand* right = instr->InputAt(1);
-  ASSERT(ToRegister(instr->result()).is(edx));
-  ASSERT(ToRegister(instr->InputAt(0)).is(eax));
-  ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
-  ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
+  if (instr->hydrogen()->HasPowerOf2Divisor()) {
+    Register dividend = ToRegister(instr->InputAt(0));
 
-  Register right_reg = ToRegister(right);
+    int32_t divisor =
+        HConstant::cast(instr->hydrogen()->right())->Integer32Value();
 
-  // Check for x % 0.
-  if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
-    __ test(right_reg, ToOperand(right));
-    DeoptimizeIf(zero, instr->environment());
-  }
+    if (divisor < 0) divisor = -divisor;
 
-  // Sign extend to edx.
-  __ cdq();
+    NearLabel positive_dividend, done;
+    __ test(dividend, Operand(dividend));
+    __ j(not_sign, &positive_dividend);
+    __ neg(dividend);
+    __ and_(dividend, divisor - 1);
+    __ neg(dividend);
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ j(not_zero, &done);
+      DeoptimizeIf(no_condition, instr->environment());
+    }
+    __ bind(&positive_dividend);
+    __ 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));
 
-  // Check for (0 % -x) that will produce negative zero.
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    NearLabel positive_left;
-    NearLabel done;
-    __ test(eax, Operand(eax));
-    __ j(not_sign, &positive_left);
-    __ idiv(right_reg);
+    Register right_reg = ToRegister(right);
+    ASSERT(!right_reg.is(eax));
+    ASSERT(!right_reg.is(edx));
 
-    // Test the remainder for 0, because then the result would be -0.
-    __ test(edx, Operand(edx));
-    __ j(not_zero, &done);
+    // Check for x % 0.
+    if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+      __ test(right_reg, ToOperand(right));
+      DeoptimizeIf(zero, instr->environment());
+    }
 
-    DeoptimizeIf(no_condition, instr->environment());
-    __ bind(&positive_left);
-    __ idiv(right_reg);
-    __ bind(&done);
-  } else {
-    __ idiv(right_reg);
+    // Sign extend to edx.
+    __ cdq();
+
+    // Check for (0 % -x) that will produce negative zero.
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      NearLabel positive_left;
+      NearLabel done;
+      __ test(eax, Operand(eax));
+      __ j(not_sign, &positive_left);
+      __ idiv(right_reg);
+
+      // Test the remainder for 0, because then the result would be -0.
+      __ test(edx, Operand(edx));
+      __ j(not_zero, &done);
+
+      DeoptimizeIf(no_condition, instr->environment());
+      __ bind(&positive_left);
+      __ idiv(right_reg);
+      __ bind(&done);
+    } else {
+      __ idiv(right_reg);
+    }
   }
 }
 
index 0ade55f..80fd71d 100644 (file)
@@ -1366,13 +1366,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
   if (instr->representation().IsInteger32()) {
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
-    // The temporary operand is necessary to ensure that right is not allocated
-    // into edx.
-    LOperand* temp = FixedTemp(edx);
-    LOperand* value = UseFixed(instr->left(), eax);
-    LOperand* divisor = UseRegister(instr->right());
-    LModI* mod = new LModI(value, divisor, temp);
-    LInstruction* result = DefineFixed(mod, edx);
+
+    LInstruction* result;
+    if (instr->HasPowerOf2Divisor()) {
+      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+      LOperand* value = UseRegisterAtStart(instr->left());
+      LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
+      result = DefineSameAsFirst(mod);
+    } else {
+      // The temporary operand is necessary to ensure that right is
+      // not allocated into edx.
+      LOperand* temp = FixedTemp(edx);
+      LOperand* value = UseFixed(instr->left(), eax);
+      LOperand* divisor = UseRegister(instr->right());
+      LModI* mod = new LModI(value, divisor, temp);
+      result = DefineFixed(mod, edx);
+    }
+
     return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
             instr->CheckFlag(HValue::kCanBeDivByZero))
         ? AssignEnvironment(result)
index dbbbaa7..1c1addb 100644 (file)
@@ -752,41 +752,64 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
 
 
 void LCodeGen::DoModI(LModI* instr) {
-  LOperand* right = instr->InputAt(1);
-  ASSERT(ToRegister(instr->result()).is(rdx));
-  ASSERT(ToRegister(instr->InputAt(0)).is(rax));
-  ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
-  ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
+  if (instr->hydrogen()->HasPowerOf2Divisor()) {
+    Register dividend = ToRegister(instr->InputAt(0));
 
-  Register right_reg = ToRegister(right);
+    int32_t divisor =
+        HConstant::cast(instr->hydrogen()->right())->Integer32Value();
 
-  // Check for x % 0.
-  if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
-    __ testl(right_reg, right_reg);
-    DeoptimizeIf(zero, instr->environment());
-  }
+    if (divisor < 0) divisor = -divisor;
 
-  // Sign extend eax to edx. (We are using only the low 32 bits of the values.)
-  __ cdq();
+    NearLabel positive_dividend, done;
+    __ testl(dividend, dividend);
+    __ j(not_sign, &positive_dividend);
+    __ negl(dividend);
+    __ andl(dividend, Immediate(divisor - 1));
+    __ negl(dividend);
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ j(not_zero, &done);
+      DeoptimizeIf(no_condition, instr->environment());
+    }
+    __ bind(&positive_dividend);
+    __ andl(dividend, Immediate(divisor - 1));
+    __ bind(&done);
+  } else {
+    LOperand* right = instr->InputAt(1);
+    Register right_reg = ToRegister(right);
 
-  // Check for (0 % -x) that will produce negative zero.
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    NearLabel positive_left;
-    NearLabel done;
-    __ testl(rax, rax);
-    __ j(not_sign, &positive_left);
-    __ idivl(right_reg);
+    ASSERT(ToRegister(instr->result()).is(rdx));
+    ASSERT(ToRegister(instr->InputAt(0)).is(rax));
+    ASSERT(!right_reg.is(rax));
+    ASSERT(!right_reg.is(rdx));
 
-    // Test the remainder for 0, because then the result would be -0.
-    __ testl(rdx, rdx);
-    __ j(not_zero, &done);
+    // Check for x % 0.
+    if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+      __ testl(right_reg, right_reg);
+      DeoptimizeIf(zero, instr->environment());
+    }
 
-    DeoptimizeIf(no_condition, instr->environment());
-    __ bind(&positive_left);
-    __ idivl(right_reg);
-    __ bind(&done);
-  } else {
-    __ idivl(right_reg);
+    // Sign extend eax to edx. (We are using only the low 32 bits of the values.)
+    __ cdq();
+
+    // Check for (0 % -x) that will produce negative zero.
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      NearLabel positive_left;
+      NearLabel done;
+      __ testl(rax, rax);
+      __ j(not_sign, &positive_left);
+      __ idivl(right_reg);
+
+      // Test the remainder for 0, because then the result would be -0.
+      __ testl(rdx, rdx);
+      __ j(not_zero, &done);
+
+      DeoptimizeIf(no_condition, instr->environment());
+      __ bind(&positive_left);
+      __ idivl(right_reg);
+      __ bind(&done);
+    } else {
+      __ idivl(right_reg);
+    }
   }
 }
 
index a29a337..640d58e 100644 (file)
@@ -1347,13 +1347,23 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
   if (instr->representation().IsInteger32()) {
     ASSERT(instr->left()->representation().IsInteger32());
     ASSERT(instr->right()->representation().IsInteger32());
-    // The temporary operand is necessary to ensure that right is not allocated
-    // into edx.
-    LOperand* temp = FixedTemp(rdx);
-    LOperand* value = UseFixed(instr->left(), rax);
-    LOperand* divisor = UseRegister(instr->right());
-    LModI* mod = new LModI(value, divisor, temp);
-    LInstruction* result = DefineFixed(mod, rdx);
+
+    LInstruction* result;
+    if (instr->HasPowerOf2Divisor()) {
+      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
+      LOperand* value = UseRegisterAtStart(instr->left());
+      LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
+      result = DefineSameAsFirst(mod);
+    } else {
+      // The temporary operand is necessary to ensure that right is not allocated
+      // into edx.
+      LOperand* temp = FixedTemp(rdx);
+      LOperand* value = UseFixed(instr->left(), rax);
+      LOperand* divisor = UseRegister(instr->right());
+      LModI* mod = new LModI(value, divisor, temp);
+      result = DefineFixed(mod, rdx);
+    }
+
     return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
             instr->CheckFlag(HValue::kCanBeDivByZero))
         ? AssignEnvironment(result)