Author: [email protected]
Date: Tue Jun  2 13:11:26 2009
New Revision: 2090

Modified:
    branches/bleeding_edge/src/ia32/codegen-ia32.cc

Log:
As a simplification, manually inline the function
DeferredInlineBinaryOperation::GenerateInlineCode and remove its
definition.  It was only called from one site and was the only
deferred code object that was split that way into fast-case inline and
slow-case stub.

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

Modified: branches/bleeding_edge/src/ia32/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.cc     (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.cc     Tue Jun  2 13:11:26 2009
@@ -776,27 +776,20 @@
  }


-// A deferred code class implementing binary operations on likely smis.
-// This class generates both inline code and deferred code.
-// The fastest path is implemented inline.  Deferred code calls
-// the GenericBinaryOpStub stub for slow cases.
+// Call the specialized stub for a binary operation.
  class DeferredInlineBinaryOperation: public DeferredCode {
   public:
    DeferredInlineBinaryOperation(Token::Value op,
-                                OverwriteMode mode,
-                                GenericBinaryFlags flags)
-      : stub_(op, mode, flags), op_(op) {
+                                OverwriteMode mode)
+      : op_(op), mode_(mode) {
      set_comment("[ DeferredInlineBinaryOperation");
    }

-  // Consumes its arguments, left and right, leaving them invalid.
-  Result GenerateInlineCode(Result* left, Result* right);
-
    virtual void Generate();

   private:
-  GenericBinaryOpStub stub_;
    Token::Value op_;
+  OverwriteMode mode_;
  };


@@ -806,7 +799,8 @@
    enter()->Bind(&left, &right);
    cgen()->frame()->Push(&left);
    cgen()->frame()->Push(&right);
-  Result answer = cgen()->frame()->CallStub(&stub_, 2);
+  GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED);
+  Result answer = cgen()->frame()->CallStub(&stub, 2);
    exit_.Jump(&answer);
  }

@@ -1007,115 +1001,445 @@
                                               Result* left,
                                               Result* right,
                                               OverwriteMode overwrite_mode)  
{
-  // Implements a binary operation using a deferred code object
-  // and some inline code to operate on smis quickly.
+  // Implements a binary operation using a deferred code object and
+  // some inline code to operate on smis quickly.
    DeferredInlineBinaryOperation* deferred =
-      new DeferredInlineBinaryOperation(op, overwrite_mode,  
SMI_CODE_INLINED);
-  // Generate the inline code that handles some smi operations,
-  // and jumps to the deferred code for everything else.
-  Result answer = deferred->GenerateInlineCode(left, right);
-  deferred->BindExit(&answer);
-  frame_->Push(&answer);
-}
+      new DeferredInlineBinaryOperation(op, overwrite_mode);

+  // Special handling of div and mod because they use fixed registers.
+  if (op == Token::DIV || op == Token::MOD) {
+    // We need eax as the quotient register, edx as the remainder
+    // register, neither left nor right in eax or edx, and left copied
+    // to eax.
+    Result quotient;
+    Result remainder;
+    bool left_is_in_eax = false;
+    // Step 1: get eax for quotient.
+    if ((left->is_register() && left->reg().is(eax)) ||
+        (right->is_register() && right->reg().is(eax))) {
+      // One or both is in eax.  Use a fresh non-edx register for
+      // them.
+      Result fresh = allocator_->Allocate();
+      ASSERT(fresh.is_valid());
+      if (fresh.reg().is(edx)) {
+        remainder = fresh;
+        fresh = allocator_->Allocate();
+        ASSERT(fresh.is_valid());
+      }
+      if (left->is_register() && left->reg().is(eax)) {
+        quotient = *left;
+        *left = fresh;
+        left_is_in_eax = true;
+      }
+      if (right->is_register() && right->reg().is(eax)) {
+        quotient = *right;
+        *right = fresh;
+      }
+      __ mov(fresh.reg(), eax);
+    } else {
+      // Neither left nor right is in eax.
+      quotient = allocator_->Allocate(eax);
+    }
+    ASSERT(quotient.is_register() && quotient.reg().is(eax));
+    ASSERT(!(left->is_register() && left->reg().is(eax)));
+    ASSERT(!(right->is_register() && right->reg().is(eax)));

-class DeferredInlineSmiOperation: public DeferredCode {
- public:
-  DeferredInlineSmiOperation(Token::Value op,
-                             Smi* value,
-                             OverwriteMode overwrite_mode)
-      : op_(op),
-        value_(value),
-        overwrite_mode_(overwrite_mode) {
-    set_comment("[ DeferredInlineSmiOperation");
-  }
-
-  virtual void Generate();
+    // Step 2: get edx for remainder if necessary.
+    if (!remainder.is_valid()) {
+      if ((left->is_register() && left->reg().is(edx)) ||
+          (right->is_register() && right->reg().is(edx))) {
+        Result fresh = allocator_->Allocate();
+        ASSERT(fresh.is_valid());
+        if (left->is_register() && left->reg().is(edx)) {
+          remainder = *left;
+          *left = fresh;
+        }
+        if (right->is_register() && right->reg().is(edx)) {
+          remainder = *right;
+          *right = fresh;
+        }
+        __ mov(fresh.reg(), edx);
+      } else {
+        // Neither left nor right is in edx.
+        remainder = allocator_->Allocate(edx);
+      }
+    }
+    ASSERT(remainder.is_register() && remainder.reg().is(edx));
+    ASSERT(!(left->is_register() && left->reg().is(edx)));
+    ASSERT(!(right->is_register() && right->reg().is(edx)));

- private:
-  Token::Value op_;
-  Smi* value_;
-  OverwriteMode overwrite_mode_;
-};
+    left->ToRegister();
+    right->ToRegister();
+    frame_->Spill(quotient.reg());
+    frame_->Spill(remainder.reg());

+    // Check that left and right are smi tagged.
+    if (left->reg().is(right->reg())) {
+      __ test(left->reg(), Immediate(kSmiTagMask));
+    } else {
+      // Use the quotient register as a scratch for the tag check.
+      if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
+      left_is_in_eax = false;
+      __ or_(quotient.reg(), Operand(right->reg()));
+      ASSERT(kSmiTag == 0);  // Adjust test if not the case.
+      __ test(quotient.reg(), Immediate(kSmiTagMask));
+    }
+    deferred->SetEntryFrame(left, right);
+    deferred->enter()->Branch(not_zero, left, right);

-void DeferredInlineSmiOperation::Generate() {
-  Result left;
-  enter()->Bind(&left);
-  cgen()->frame()->Push(&left);
-  cgen()->frame()->Push(value_);
-  GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
-  Result answer = cgen()->frame()->CallStub(&igostub, 2);
-  exit_.Jump(&answer);
-}
+    if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());

+    // Sign extend eax into edx:eax.
+    __ cdq();
+    // Check for 0 divisor.
+    __ test(right->reg(), Operand(right->reg()));
+    deferred->enter()->Branch(zero, left, right);
+    // Divide edx:eax by the right operand.
+    __ idiv(right->reg());

-class DeferredInlineSmiOperationReversed: public DeferredCode {
- public:
-  DeferredInlineSmiOperationReversed(Token::Value op,
-                                     Smi* value,
-                                     OverwriteMode overwrite_mode)
-      : op_(op),
-        value_(value),
-        overwrite_mode_(overwrite_mode) {
-    set_comment("[ DeferredInlineSmiOperationReversed");
+    // Complete the operation.
+    if (op == Token::DIV) {
+      // Check for negative zero result.  If result is zero, and divisor
+      // is negative, return a floating point negative zero.  The
+      // virtual frame is unchanged in this block, so local control flow
+      // can use a Label rather than a JumpTarget.
+      Label non_zero_result;
+      __ test(left->reg(), Operand(left->reg()));
+      __ j(not_zero, &non_zero_result);
+      __ test(right->reg(), Operand(right->reg()));
+      deferred->enter()->Branch(negative, left, right);
+      __ bind(&non_zero_result);
+      // Check for the corner case of dividing the most negative smi by
+      // -1. We cannot use the overflow flag, since it is not set by
+      // idiv instruction.
+      ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+      __ cmp(quotient.reg(), 0x40000000);
+      deferred->enter()->Branch(equal, left, right);
+      // Check that the remainder is zero.
+      __ test(remainder.reg(), Operand(remainder.reg()));
+      remainder.Unuse();
+      deferred->enter()->Branch(not_zero, left, right);
+      left->Unuse();
+      right->Unuse();
+      // Tag the result and store it in the quotient register.
+      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+      __ lea(quotient.reg(),
+             Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag));
+      deferred->BindExit(&quotient);
+      frame_->Push(&quotient);
+    } else {
+      ASSERT(op == Token::MOD);
+      quotient.Unuse();
+      // Check for a negative zero result.  If the result is zero, and
+      // the dividend is negative, return a floating point negative
+      // zero.  The frame is unchanged in this block, so local control
+      // flow can use a Label rather than a JumpTarget.
+      Label non_zero_result;
+      __ test(remainder.reg(), Operand(remainder.reg()));
+      __ j(not_zero, &non_zero_result, taken);
+      __ test(left->reg(), Operand(left->reg()));
+      deferred->enter()->Branch(negative, left, right);
+      left->Unuse();
+      right->Unuse();
+      __ bind(&non_zero_result);
+      deferred->BindExit(&remainder);
+      frame_->Push(&remainder);
+    }
+    return;
    }

-  virtual void Generate();
-
- private:
-  Token::Value op_;
-  Smi* value_;
-  OverwriteMode overwrite_mode_;
-};
-
-
-void DeferredInlineSmiOperationReversed::Generate() {
-  Result right;
-  enter()->Bind(&right);
-  cgen()->frame()->Push(value_);
-  cgen()->frame()->Push(&right);
-  GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
-  Result answer = cgen()->frame()->CallStub(&igostub, 2);
-  exit_.Jump(&answer);
-}
-
+  // Handle the other binary operations.
+  left->ToRegister();
+  right->ToRegister();
+  // A newly allocated register answer is used to hold the answer.  The
+  // registers containing left and right are not modified in most cases,
+  // so they usually don't need to be spilled in the fast case.
+  Result answer = allocator_->Allocate();

-class DeferredInlineSmiAdd: public DeferredCode {
- public:
-  DeferredInlineSmiAdd(Smi* value,
-                       OverwriteMode overwrite_mode)
-      : value_(value),
-        overwrite_mode_(overwrite_mode) {
-    set_comment("[ DeferredInlineSmiAdd");
+  ASSERT(answer.is_valid());
+  // Perform the smi tag check.
+  if (left->reg().is(right->reg())) {
+    __ test(left->reg(), Immediate(kSmiTagMask));
+  } else {
+    __ mov(answer.reg(), left->reg());
+    __ or_(answer.reg(), Operand(right->reg()));
+    ASSERT(kSmiTag == 0);  // Adjust test if not the case.
+    __ test(answer.reg(), Immediate(kSmiTagMask));
    }
+  switch (op) {
+    case Token::ADD:
+      deferred->SetEntryFrame(left, right);
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      __ add(answer.reg(), Operand(right->reg()));  // Add optimistically.
+      deferred->enter()->Branch(overflow, left, right, not_taken);
+      break;

-  virtual void Generate();
-
- private:
-  Smi* value_;
-  OverwriteMode overwrite_mode_;
-};
-
+    case Token::SUB:
+      deferred->SetEntryFrame(left, right);
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      __ sub(answer.reg(), Operand(right->reg()));  // Subtract  
optimistically.
+      deferred->enter()->Branch(overflow, left, right, not_taken);
+      break;

-class DeferredInlineSmiAddReversed: public DeferredCode {
- public:
-  DeferredInlineSmiAddReversed(Smi* value,
-                               OverwriteMode overwrite_mode)
-      : value_(value),
-        overwrite_mode_(overwrite_mode) {
-    set_comment("[ DeferredInlineSmiAddReversed");
-  }
+    case Token::MUL: {
+      deferred->SetEntryFrame(left, right);
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      // If the smi tag is 0 we can just leave the tag on one operand.
+      ASSERT(kSmiTag == 0);  // Adjust code below if not the case.
+      // Remove smi tag from the left operand (but keep sign).
+      // Left-hand operand has been copied into answer.
+      __ sar(answer.reg(), kSmiTagSize);
+      // Do multiplication of smis, leaving result in answer.
+      __ imul(answer.reg(), Operand(right->reg()));
+      // Go slow on overflows.
+      deferred->enter()->Branch(overflow, left, right, not_taken);
+      // Check for negative zero result.  If product is zero, and one
+      // argument is negative, go to slow case.  The frame is unchanged
+      // in this block, so local control flow can use a Label rather
+      // than a JumpTarget.
+      Label non_zero_result;
+      __ test(answer.reg(), Operand(answer.reg()));
+      __ j(not_zero, &non_zero_result, taken);
+      __ mov(answer.reg(), left->reg());
+      __ or_(answer.reg(), Operand(right->reg()));
+      deferred->enter()->Branch(negative, left, right, not_taken);
+      __ xor_(answer.reg(), Operand(answer.reg()));  // Positive 0 is  
correct.
+      __ bind(&non_zero_result);
+      break;
+    }

-  virtual void Generate();
+    case Token::BIT_OR:
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      __ or_(answer.reg(), Operand(right->reg()));
+      break;

- private:
-  Smi* value_;
-  OverwriteMode overwrite_mode_;
-};
+    case Token::BIT_AND:
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      __ and_(answer.reg(), Operand(right->reg()));
+      break;

+    case Token::BIT_XOR:
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      __ xor_(answer.reg(), Operand(right->reg()));
+      break;

-class DeferredInlineSmiSub: public DeferredCode {
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR:
+      deferred->enter()->Branch(not_zero, left, right, not_taken);
+      __ mov(answer.reg(), left->reg());
+      // Move right into ecx.
+      // Left is in two registers already, so even if left or answer is  
ecx,
+      // we can move right to it, and use the other one.
+      // Right operand must be in register cl because x86 likes it that  
way.
+      if (right->reg().is(ecx)) {
+        // Right is already in the right place.  Left may be in the
+        // same register, which causes problems. Always use answer
+        // instead of left, even if left is not ecx, since this avoids
+        // spilling left.
+        *left = answer;
+      } else if (left->reg().is(ecx)) {
+        frame_->Spill(left->reg());
+        __ mov(left->reg(), right->reg());
+        *right = *left;
+        *left = answer;  // Use copy of left in answer as left.
+      } else if (answer.reg().is(ecx)) {
+        __ mov(answer.reg(), right->reg());
+        *right = answer;
+      } else {
+        Result reg_ecx = allocator_->Allocate(ecx);
+        ASSERT(reg_ecx.is_valid());
+        __ mov(ecx, right->reg());
+        *right = reg_ecx;
+        // Answer and left both contain the left operand.  Use answer, so
+        // left is not spilled.
+        *left = answer;
+      }
+      ASSERT(left->reg().is_valid());
+      ASSERT(!left->reg().is(ecx));
+      ASSERT(right->reg().is(ecx));
+      answer.Unuse();  // Answer may now be being used for left or right.
+      // We will modify left and right, which we do not do in any other
+      // binary operation.  The exits to slow code need to restore the
+      // original values of left and right, or at least values that give
+      // the same answer.
+
+      // We are modifying left and right.  They must be spilled!
+      frame_->Spill(left->reg());
+      frame_->Spill(right->reg());
+
+      // Remove tags from operands (but keep sign).
+      __ sar(left->reg(), kSmiTagSize);
+      __ sar(ecx, kSmiTagSize);
+      // Perform the operation.
+      switch (op) {
+        case Token::SAR:
+          __ sar(left->reg());
+          // No checks of result necessary
+          break;
+        case Token::SHR: {
+          __ shr(left->reg());
+          // Check that the *unsigned* result fits in a smi.
+          // Neither of the two high-order bits can be set:
+          // - 0x80000000: high bit would be lost when smi tagging.
+          // - 0x40000000: this number would convert to negative when
+          // Smi tagging these two cases can only happen with shifts
+          // by 0 or 1 when handed a valid smi.
+          // If the answer cannot be represented by a SMI, restore
+          // the left and right arguments, and jump to slow case.
+          // The low bit of the left argument may be lost, but only
+          // in a case where it is dropped anyway.
+          JumpTarget result_ok;
+          __ test(left->reg(), Immediate(0xc0000000));
+          result_ok.Branch(zero, left, taken);
+          __ shl(left->reg());
+          ASSERT(kSmiTag == 0);
+          __ shl(left->reg(), kSmiTagSize);
+          __ shl(right->reg(), kSmiTagSize);
+          deferred->enter()->Jump(left, right);
+          result_ok.Bind(left);
+          break;
+        }
+        case Token::SHL: {
+          __ shl(left->reg());
+          // Check that the *signed* result fits in a smi.
+          JumpTarget result_ok;
+          __ cmp(left->reg(), 0xc0000000);
+          result_ok.Branch(positive, left, taken);
+
+          __ shr(left->reg());
+          ASSERT(kSmiTag == 0);
+          __ shl(left->reg(), kSmiTagSize);
+          __ shl(right->reg(), kSmiTagSize);
+          deferred->enter()->Jump(left, right);
+          result_ok.Bind(left);
+          break;
+        }
+        default:
+          UNREACHABLE();
+      }
+      // Smi-tag the result, in left, and make answer an alias for left->
+      answer = *left;
+      answer.ToRegister();
+      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
+      __ lea(answer.reg(),
+             Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
+      break;
+
+    default:
+      UNREACHABLE();
+      break;
+  }
+  left->Unuse();
+  right->Unuse();
+  deferred->BindExit(&answer);
+  frame_->Push(&answer);
+}
+
+
+class DeferredInlineSmiOperation: public DeferredCode {
+ public:
+  DeferredInlineSmiOperation(Token::Value op,
+                             Smi* value,
+                             OverwriteMode overwrite_mode)
+      : op_(op),
+        value_(value),
+        overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlineSmiOperation");
+  }
+
+  virtual void Generate();
+
+ private:
+  Token::Value op_;
+  Smi* value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+void DeferredInlineSmiOperation::Generate() {
+  Result left;
+  enter()->Bind(&left);
+  cgen()->frame()->Push(&left);
+  cgen()->frame()->Push(value_);
+  GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
+  Result answer = cgen()->frame()->CallStub(&igostub, 2);
+  exit_.Jump(&answer);
+}
+
+
+class DeferredInlineSmiOperationReversed: public DeferredCode {
+ public:
+  DeferredInlineSmiOperationReversed(Token::Value op,
+                                     Smi* value,
+                                     OverwriteMode overwrite_mode)
+      : op_(op),
+        value_(value),
+        overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlineSmiOperationReversed");
+  }
+
+  virtual void Generate();
+
+ private:
+  Token::Value op_;
+  Smi* value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+void DeferredInlineSmiOperationReversed::Generate() {
+  Result right;
+  enter()->Bind(&right);
+  cgen()->frame()->Push(value_);
+  cgen()->frame()->Push(&right);
+  GenericBinaryOpStub igostub(op_, overwrite_mode_, SMI_CODE_INLINED);
+  Result answer = cgen()->frame()->CallStub(&igostub, 2);
+  exit_.Jump(&answer);
+}
+
+
+class DeferredInlineSmiAdd: public DeferredCode {
+ public:
+  DeferredInlineSmiAdd(Smi* value,
+                       OverwriteMode overwrite_mode)
+      : value_(value),
+        overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlineSmiAdd");
+  }
+
+  virtual void Generate();
+
+ private:
+  Smi* value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlineSmiAddReversed: public DeferredCode {
+ public:
+  DeferredInlineSmiAddReversed(Smi* value,
+                               OverwriteMode overwrite_mode)
+      : value_(value),
+        overwrite_mode_(overwrite_mode) {
+    set_comment("[ DeferredInlineSmiAddReversed");
+  }
+
+  virtual void Generate();
+
+ private:
+  Smi* value_;
+  OverwriteMode overwrite_mode_;
+};
+
+
+class DeferredInlineSmiSub: public DeferredCode {
   public:
    DeferredInlineSmiSub(Smi* value,
                         OverwriteMode overwrite_mode)
@@ -5729,341 +6053,6 @@
    __ bind(&false_result);
    __ mov(eax, 0);
    __ ret(1 * kPointerSize);
-}
-
-
-Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
-                                                         Result* right) {
-  MacroAssembler* masm = cgen()->masm();
-
-  // Special handling of div and mod because they use fixed registers.
-  if (op_ == Token::DIV || op_ == Token::MOD) {
-    // We need eax as the quotient register, edx as the remainder
-    // register, neither left nor right in eax or edx, and left copied
-    // to eax.
-    Result quotient;
-    Result remainder;
-    bool left_is_in_eax = false;
-    // Step 1: get eax for quotient.
-    if ((left->is_register() && left->reg().is(eax)) ||
-        (right->is_register() && right->reg().is(eax))) {
-      // One or both is in eax.  Use a fresh non-edx register for
-      // them.
-      Result fresh = cgen()->allocator()->Allocate();
-      ASSERT(fresh.is_valid());
-      if (fresh.reg().is(edx)) {
-        remainder = fresh;
-        fresh = cgen()->allocator()->Allocate();
-        ASSERT(fresh.is_valid());
-      }
-      if (left->is_register() && left->reg().is(eax)) {
-        quotient = *left;
-        *left = fresh;
-        left_is_in_eax = true;
-      }
-      if (right->is_register() && right->reg().is(eax)) {
-        quotient = *right;
-        *right = fresh;
-      }
-      __ mov(fresh.reg(), eax);
-    } else {
-      // Neither left nor right is in eax.
-      quotient = cgen()->allocator()->Allocate(eax);
-    }
-    ASSERT(quotient.is_register() && quotient.reg().is(eax));
-    ASSERT(!(left->is_register() && left->reg().is(eax)));
-    ASSERT(!(right->is_register() && right->reg().is(eax)));
-
-    // Step 2: get edx for remainder if necessary.
-    if (!remainder.is_valid()) {
-      if ((left->is_register() && left->reg().is(edx)) ||
-          (right->is_register() && right->reg().is(edx))) {
-        Result fresh = cgen()->allocator()->Allocate();
-        ASSERT(fresh.is_valid());
-        if (left->is_register() && left->reg().is(edx)) {
-          remainder = *left;
-          *left = fresh;
-        }
-        if (right->is_register() && right->reg().is(edx)) {
-          remainder = *right;
-          *right = fresh;
-        }
-        __ mov(fresh.reg(), edx);
-      } else {
-        // Neither left nor right is in edx.
-        remainder = cgen()->allocator()->Allocate(edx);
-      }
-    }
-    ASSERT(remainder.is_register() && remainder.reg().is(edx));
-    ASSERT(!(left->is_register() && left->reg().is(edx)));
-    ASSERT(!(right->is_register() && right->reg().is(edx)));
-
-    left->ToRegister();
-    right->ToRegister();
-    cgen()->frame()->Spill(quotient.reg());
-    cgen()->frame()->Spill(remainder.reg());
-
-    // Check that left and right are smi tagged.
-    if (left->reg().is(right->reg())) {
-      __ test(left->reg(), Immediate(kSmiTagMask));
-    } else {
-      // Use the quotient register as a scratch for the tag check.
-      if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
-      left_is_in_eax = false;
-      __ or_(quotient.reg(), Operand(right->reg()));
-      ASSERT(kSmiTag == 0);  // Adjust test if not the case.
-      __ test(quotient.reg(), Immediate(kSmiTagMask));
-    }
-    SetEntryFrame(left, right);
-    enter()->Branch(not_zero, left, right);
-
-    if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
-
-    // Sign extend eax into edx:eax.
-    __ cdq();
-    // Check for 0 divisor.
-    __ test(right->reg(), Operand(right->reg()));
-    enter()->Branch(zero, left, right);
-    // Divide edx:eax by the right operand.
-    __ idiv(right->reg());
-
-    // Complete the operation.
-    if (op_ == Token::DIV) {
-      // Check for negative zero result.  If result is zero, and divisor
-      // is negative, return a floating point negative zero.  The
-      // virtual frame is unchanged in this block, so local control flow
-      // can use a Label rather than a JumpTarget.
-      Label non_zero_result;
-      __ test(left->reg(), Operand(left->reg()));
-      __ j(not_zero, &non_zero_result);
-      __ test(right->reg(), Operand(right->reg()));
-      enter()->Branch(negative, left, right);
-      __ bind(&non_zero_result);
-      // Check for the corner case of dividing the most negative smi by
-      // -1. We cannot use the overflow flag, since it is not set by
-      // idiv instruction.
-      ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
-      __ cmp(quotient.reg(), 0x40000000);
-      enter()->Branch(equal, left, right);
-      // Check that the remainder is zero.
-      __ test(remainder.reg(), Operand(remainder.reg()));
-      enter()->Branch(not_zero, left, right);
-      left->Unuse();
-      right->Unuse();
-      // Tag the result and store it in the quotient register.
-      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
-      __ lea(quotient.reg(),
-             Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag));
-      return quotient;
-    } else {
-      ASSERT(op_ == Token::MOD);
-      // Check for a negative zero result.  If the result is zero, and
-      // the dividend is negative, return a floating point negative
-      // zero.  The frame is unchanged in this block, so local control
-      // flow can use a Label rather than a JumpTarget.
-      Label non_zero_result;
-      __ test(remainder.reg(), Operand(remainder.reg()));
-      __ j(not_zero, &non_zero_result, taken);
-      __ test(left->reg(), Operand(left->reg()));
-      enter()->Branch(negative, left, right);
-      left->Unuse();
-      right->Unuse();
-      __ bind(&non_zero_result);
-      return remainder;
-    }
-  }
-
-  // Handle the other binary operations.
-  left->ToRegister();
-  right->ToRegister();
-  // A newly allocated register answer is used to hold the answer.  The
-  // registers containing left and right are not modified in most cases,
-  // so they usually don't need to be spilled in the fast case.
-  Result answer = cgen()->allocator()->Allocate();
-
-  ASSERT(answer.is_valid());
-  // Perform the smi tag check.
-  if (left->reg().is(right->reg())) {
-    __ test(left->reg(), Immediate(kSmiTagMask));
-  } else {
-    __ mov(answer.reg(), left->reg());
-    __ or_(answer.reg(), Operand(right->reg()));
-    ASSERT(kSmiTag == 0);  // Adjust test if not the case.
-    __ test(answer.reg(), Immediate(kSmiTagMask));
-  }
-  switch (op_) {
-    case Token::ADD:
-      SetEntryFrame(left, right);
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      __ add(answer.reg(), Operand(right->reg()));  // Add optimistically.
-      enter()->Branch(overflow, left, right, not_taken);
-      break;
-
-    case Token::SUB:
-      SetEntryFrame(left, right);
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      __ sub(answer.reg(), Operand(right->reg()));  // Subtract  
optimistically.
-      enter()->Branch(overflow, left, right, not_taken);
-      break;
-
-    case Token::MUL: {
-      SetEntryFrame(left, right);
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      // If the smi tag is 0 we can just leave the tag on one operand.
-      ASSERT(kSmiTag == 0);  // Adjust code below if not the case.
-      // Remove smi tag from the left operand (but keep sign).
-      // Left-hand operand has been copied into answer.
-      __ sar(answer.reg(), kSmiTagSize);
-      // Do multiplication of smis, leaving result in answer.
-      __ imul(answer.reg(), Operand(right->reg()));
-      // Go slow on overflows.
-      enter()->Branch(overflow, left, right, not_taken);
-      // Check for negative zero result.  If product is zero, and one
-      // argument is negative, go to slow case.  The frame is unchanged
-      // in this block, so local control flow can use a Label rather
-      // than a JumpTarget.
-      Label non_zero_result;
-      __ test(answer.reg(), Operand(answer.reg()));
-      __ j(not_zero, &non_zero_result, taken);
-      __ mov(answer.reg(), left->reg());
-      __ or_(answer.reg(), Operand(right->reg()));
-      enter()->Branch(negative, left, right, not_taken);
-      __ xor_(answer.reg(), Operand(answer.reg()));  // Positive 0 is  
correct.
-      __ bind(&non_zero_result);
-      break;
-    }
-
-    case Token::BIT_OR:
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      __ or_(answer.reg(), Operand(right->reg()));
-      break;
-
-    case Token::BIT_AND:
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      __ and_(answer.reg(), Operand(right->reg()));
-      break;
-
-    case Token::BIT_XOR:
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      __ xor_(answer.reg(), Operand(right->reg()));
-      break;
-
-    case Token::SHL:
-    case Token::SHR:
-    case Token::SAR:
-      enter()->Branch(not_zero, left, right, not_taken);
-      __ mov(answer.reg(), left->reg());
-      // Move right into ecx.
-      // Left is in two registers already, so even if left or answer is  
ecx,
-      // we can move right to it, and use the other one.
-      // Right operand must be in register cl because x86 likes it that  
way.
-      if (right->reg().is(ecx)) {
-        // Right is already in the right place.  Left may be in the
-        // same register, which causes problems. Always use answer
-        // instead of left, even if left is not ecx, since this avoids
-        // spilling left.
-        *left = answer;
-      } else if (left->reg().is(ecx)) {
-        cgen()->frame()->Spill(left->reg());
-        __ mov(left->reg(), right->reg());
-        *right = *left;
-        *left = answer;  // Use copy of left in answer as left.
-      } else if (answer.reg().is(ecx)) {
-        __ mov(answer.reg(), right->reg());
-        *right = answer;
-      } else {
-        Result reg_ecx = cgen()->allocator()->Allocate(ecx);
-        ASSERT(reg_ecx.is_valid());
-        __ mov(ecx, right->reg());
-        *right = reg_ecx;
-        // Answer and left both contain the left operand.  Use answer, so
-        // left is not spilled.
-        *left = answer;
-      }
-      ASSERT(left->reg().is_valid());
-      ASSERT(!left->reg().is(ecx));
-      ASSERT(right->reg().is(ecx));
-      answer.Unuse();  // Answer may now be being used for left or right.
-      // We will modify left and right, which we do not do in any other
-      // binary operation.  The exits to slow code need to restore the
-      // original values of left and right, or at least values that give
-      // the same answer.
-
-      // We are modifying left and right.  They must be spilled!
-      cgen()->frame()->Spill(left->reg());
-      cgen()->frame()->Spill(right->reg());
-
-      // Remove tags from operands (but keep sign).
-      __ sar(left->reg(), kSmiTagSize);
-      __ sar(ecx, kSmiTagSize);
-      // Perform the operation.
-      switch (op_) {
-        case Token::SAR:
-          __ sar(left->reg());
-          // No checks of result necessary
-          break;
-        case Token::SHR: {
-          __ shr(left->reg());
-          // Check that the *unsigned* result fits in a smi.
-          // Neither of the two high-order bits can be set:
-          // - 0x80000000: high bit would be lost when smi tagging.
-          // - 0x40000000: this number would convert to negative when
-          // Smi tagging these two cases can only happen with shifts
-          // by 0 or 1 when handed a valid smi.
-          // If the answer cannot be represented by a SMI, restore
-          // the left and right arguments, and jump to slow case.
-          // The low bit of the left argument may be lost, but only
-          // in a case where it is dropped anyway.
-          JumpTarget result_ok;
-          __ test(left->reg(), Immediate(0xc0000000));
-          result_ok.Branch(zero, left, taken);
-          __ shl(left->reg());
-          ASSERT(kSmiTag == 0);
-          __ shl(left->reg(), kSmiTagSize);
-          __ shl(right->reg(), kSmiTagSize);
-          enter()->Jump(left, right);
-          result_ok.Bind(left);
-          break;
-        }
-        case Token::SHL: {
-          __ shl(left->reg());
-          // Check that the *signed* result fits in a smi.
-          JumpTarget result_ok;
-          __ cmp(left->reg(), 0xc0000000);
-          result_ok.Branch(positive, left, taken);
-
-          __ shr(left->reg());
-          ASSERT(kSmiTag == 0);
-          __ shl(left->reg(), kSmiTagSize);
-          __ shl(right->reg(), kSmiTagSize);
-          enter()->Jump(left, right);
-          result_ok.Bind(left);
-          break;
-        }
-        default:
-          UNREACHABLE();
-      }
-      // Smi-tag the result, in left, and make answer an alias for left->
-      answer = *left;
-      answer.ToRegister();
-      ASSERT(kSmiTagSize == times_2);  // adjust code if not the case
-      __ lea(answer.reg(),
-             Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
-      break;
-
-    default:
-      UNREACHABLE();
-      break;
-  }
-  left->Unuse();
-  right->Unuse();
-  return answer;
  }



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

Reply via email to