Remove uses of RangeCanInclude() in flooring division by power of 2.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Mar 2014 07:58:58 +0000 (07:58 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Mar 2014 07:58:58 +0000 (07:58 +0000)
Drive-By-Fix: Improve ARM code generation for flooring division by
power of 2.

BUG=v8:3204
LOG=y
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/196653009

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

src/a64/lithium-a64.cc
src/a64/lithium-codegen-a64.cc
src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/hydrogen-instructions.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 1b7ceb6..ab76044 100644 (file)
@@ -1749,12 +1749,13 @@ LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
   ASSERT(instr->right()->representation().Equals(instr->representation()));
   LOperand* dividend = UseRegisterAtStart(instr->left());
   int32_t divisor = instr->right()->GetInteger32Constant();
-  LInstruction* result =
-      DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
-  bool can_deopt =
-      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
-      (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
-  return can_deopt ? AssignEnvironment(result) : result;
+  LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
index a9c1b22..651f579 100644 (file)
@@ -3839,37 +3839,37 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
 
 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
   Register dividend = ToRegister32(instr->dividend());
+  Register result = ToRegister32(instr->result());
   int32_t divisor = instr->divisor();
-  ASSERT(dividend.is(ToRegister32(instr->result())));
 
   // If the divisor is positive, things are easy: There can be no deopts and we
   // can simply do an arithmetic right shift.
   if (divisor == 1) return;
   int32_t shift = WhichPowerOf2Abs(divisor);
   if (divisor > 1) {
-    __ Mov(dividend, Operand(dividend, ASR, shift));
+    __ Mov(result, Operand(dividend, ASR, shift));
     return;
   }
 
   // If the divisor is negative, we have to negate and handle edge cases.
   Label not_kmin_int, done;
-  __ Negs(dividend, dividend);
+  __ Negs(result, dividend);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     DeoptimizeIf(eq, instr->environment());
   }
-  if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
+  if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
     // Note that we could emit branch-free code, but that would need one more
     // register.
-    __ B(vc, &not_kmin_int);
     if (divisor == -1) {
-      Deoptimize(instr->environment());
+      DeoptimizeIf(vs, instr->environment());
     } else {
-      __ Mov(dividend, kMinInt / divisor);
+      __ B(vc, &not_kmin_int);
+      __ Mov(result, kMinInt / divisor);
       __ B(&done);
     }
   }
   __ bind(&not_kmin_int);
-  __ Mov(dividend, Operand(dividend, ASR, shift));
+  __ Mov(result, Operand(dividend, ASR, shift));
   __ bind(&done);
 }
 
index 360f919..fac89e4 100644 (file)
@@ -1316,13 +1316,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
   LOperand* dividend = UseRegisterAtStart(instr->left());
   int32_t divisor = instr->right()->GetInteger32Constant();
-  LInstruction* result =
-      DefineSameAsFirst(
-          new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
-  bool can_deopt =
-      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
-      (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
-  return can_deopt ? AssignEnvironment(result) : result;
+  LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
index 0c05252..2b6c0a8 100644 (file)
@@ -1458,38 +1458,36 @@ void LCodeGen::DoMultiplySubD(LMultiplySubD* instr) {
 
 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
   Register dividend = ToRegister(instr->dividend());
+  Register result = ToRegister(instr->result());
   int32_t divisor = instr->divisor();
-  ASSERT(dividend.is(ToRegister(instr->result())));
 
   // If the divisor is positive, things are easy: There can be no deopts and we
   // can simply do an arithmetic right shift.
   if (divisor == 1) return;
   int32_t shift = WhichPowerOf2Abs(divisor);
   if (divisor > 1) {
-    __ mov(dividend, Operand(dividend, ASR, shift));
+    __ mov(result, Operand(dividend, ASR, shift));
     return;
   }
 
   // If the divisor is negative, we have to negate and handle edge cases.
-  Label not_kmin_int, done;
-  __ rsb(dividend, dividend, Operand::Zero(), SetCC);
+  __ rsb(result, dividend, Operand::Zero(), SetCC);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     DeoptimizeIf(eq, instr->environment());
   }
-  if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
+  if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
     // Note that we could emit branch-free code, but that would need one more
     // register.
-    __ b(vc, &not_kmin_int);
     if (divisor == -1) {
-      DeoptimizeIf(al, instr->environment());
+      DeoptimizeIf(vs, instr->environment());
+      __ mov(result, Operand(dividend, ASR, shift));
     } else {
-      __ mov(dividend, Operand(kMinInt / divisor));
-      __ b(&done);
+      __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs);
+      __ mov(result, Operand(dividend, ASR, shift), LeaveCC, vc);
     }
+  } else {
+    __ mov(result, Operand(dividend, ASR, shift));
   }
-  __ bind(&not_kmin_int);
-  __ mov(dividend, Operand(dividend, ASR, shift));
-  __ bind(&done);
 }
 
 
index 58d3de2..45112fa 100644 (file)
@@ -1799,7 +1799,7 @@ Range* HMul::InferRange(Zone* zone) {
 }
 
 
-Range* HBinaryOperation::InferRangeForDiv(Zone* zone) {
+Range* HDiv::InferRange(Zone* zone) {
   if (representation().IsInteger32()) {
     Range* a = left()->range();
     Range* b = right()->range();
@@ -1821,13 +1821,29 @@ Range* HBinaryOperation::InferRangeForDiv(Zone* zone) {
 }
 
 
-Range* HDiv::InferRange(Zone* zone) {
-  return InferRangeForDiv(zone);
-}
+Range* HMathFloorOfDiv::InferRange(Zone* zone) {
+  if (representation().IsInteger32()) {
+    Range* a = left()->range();
+    Range* b = right()->range();
+    Range* result = new(zone) Range();
+    result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) &&
+                                  (a->CanBeMinusZero() ||
+                                   (a->CanBeZero() && b->CanBeNegative())));
+    if (!a->Includes(kMinInt)) {
+      ClearFlag(kLeftCanBeMinInt);
+    }
 
+    if (!a->Includes(kMinInt) || !b->Includes(-1)) {
+      ClearFlag(kCanOverflow);
+    }
 
-Range* HMathFloorOfDiv::InferRange(Zone* zone) {
-  return InferRangeForDiv(zone);
+    if (!b->CanBeZero()) {
+      ClearFlag(kCanBeDivByZero);
+    }
+    return result;
+  } else {
+    return HValue::InferRange(zone);
+  }
 }
 
 
index c532bd5..2097641 100644 (file)
@@ -622,6 +622,7 @@ class HValue : public ZoneObject {
     kCanOverflow,
     kBailoutOnMinusZero,
     kCanBeDivByZero,
+    kLeftCanBeMinInt,
     kAllowUndefinedAsNaN,
     kIsArguments,
     kTruncatingToInt32,
@@ -855,9 +856,6 @@ class HValue : public ZoneObject {
   // TODO(svenpanne) We should really use the null object pattern here.
   bool HasRange() const { return range_ != NULL; }
   bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); }
-  bool RangeCanInclude(int value) const {
-    return !HasRange() || range()->Includes(value);
-  }
   void AddNewRange(Range* r, Zone* zone);
   void RemoveLastAddedRange();
   void ComputeInitialRange(Zone* zone);
@@ -3765,9 +3763,6 @@ class HBinaryOperation : public HTemplateInstruction<3> {
 
   DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
 
- protected:
-  Range* InferRangeForDiv(Zone* zone);
-
  private:
   bool IgnoreObservedOutputRepresentation(Representation current_rep);
 
@@ -4109,6 +4104,7 @@ class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
     SetFlag(kUseGVN);
     SetFlag(kCanOverflow);
     SetFlag(kCanBeDivByZero);
+    SetFlag(kLeftCanBeMinInt);
     SetFlag(kAllowUndefinedAsNaN);
   }
 
index d8f5721..addac81 100644 (file)
@@ -1637,13 +1637,13 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     DeoptimizeIf(zero, instr->environment());
   }
-  if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
+  if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
     // Note that we could emit branch-free code, but that would need one more
     // register.
-    __ j(no_overflow, &not_kmin_int, Label::kNear);
     if (divisor == -1) {
-      DeoptimizeIf(no_condition, instr->environment());
+      DeoptimizeIf(overflow, instr->environment());
     } else {
+      __ j(no_overflow, &not_kmin_int, Label::kNear);
       __ mov(dividend, Immediate(kMinInt / divisor));
       __ jmp(&done, Label::kNear);
     }
index 2435174..930b7ed 100644 (file)
@@ -1409,12 +1409,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
   LOperand* dividend = UseRegisterAtStart(instr->left());
   int32_t divisor = instr->right()->GetInteger32Constant();
-  LInstruction* result =
-      DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
-  bool can_deopt =
-      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
-      (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
-  return can_deopt ? AssignEnvironment(result) : result;
+  LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
index c66348c..51acede 100644 (file)
@@ -1129,7 +1129,7 @@ void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     DeoptimizeIf(zero, instr->environment());
   }
-  if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
+  if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
     // Note that we could emit branch-free code, but that would need one more
     // register.
     __ j(no_overflow, &not_kmin_int, Label::kNear);
index 3739564..625b4f4 100644 (file)
@@ -1330,12 +1330,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
   LOperand* dividend = UseRegisterAtStart(instr->left());
   int32_t divisor = instr->right()->GetInteger32Constant();
-  LInstruction* result =
-      DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(dividend, divisor));
-  bool can_deopt =
-      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
-      (instr->left()->RangeCanInclude(kMinInt) && divisor == -1);
-  return can_deopt ? AssignEnvironment(result) : result;
+  LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }