Revision: 5351
Author: [email protected]
Date: Thu Aug 26 01:50:38 2010
Log: Add inlining of binary smi operations in the full codegens on IA32
and x64 (on IA32 we even fold constants into the instructions for
a more compact representation) and prepare the ARM full codegen for
the doing the same there.
Review URL: http://codereview.chromium.org/3195028
http://code.google.com/p/v8/source/detail?r=5351

Modified:
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/full-codegen.cc
 /branches/bleeding_edge/src/full-codegen.h
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/token.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Aug 25 07:22:03 2010 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Aug 26 01:50:38 2010
@@ -244,6 +244,13 @@
 #endif
   }
 }
+
+
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+    Token::Value op, Expression* left, Expression* right) {
+  ASSERT(ShouldInlineSmiCase(op));
+  return kNoConstants;
+}


 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
@@ -1144,10 +1151,11 @@
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
   LhsKind assign_type = VARIABLE;
-  Property* prop = expr->target()->AsProperty();
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+  Property* property = expr->target()->AsProperty();
+  if (property != NULL) {
+    assign_type = (property->key()->IsPropertyName())
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
   }

   // Evaluate LHS expression.
@@ -1158,61 +1166,70 @@
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the accumulator.
-        VisitForValue(prop->obj(), kAccumulator);
+        VisitForValue(property->obj(), kAccumulator);
         __ push(result_register());
       } else {
-        VisitForValue(prop->obj(), kStack);
+        VisitForValue(property->obj(), kStack);
       }
       break;
     case KEYED_PROPERTY:
-      // We need the key and receiver on both the stack and in r0 and r1.
       if (expr->is_compound()) {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kAccumulator);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kAccumulator);
         __ ldr(r1, MemOperand(sp, 0));
         __ push(r0);
       } else {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kStack);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kStack);
       }
       break;
   }

-  // If we have a compound assignment: Get value of LHS expression and
-  // store in on top of the stack.
   if (expr->is_compound()) {
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     switch (assign_type) {
       case VARIABLE:
         EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
                          Expression::kValue);
         break;
       case NAMED_PROPERTY:
-        EmitNamedPropertyLoad(prop);
-        __ push(result_register());
+        EmitNamedPropertyLoad(property);
         break;
       case KEYED_PROPERTY:
-        EmitKeyedPropertyLoad(prop);
-        __ push(result_register());
+        EmitKeyedPropertyLoad(property);
         break;
     }
-    location_ = saved_location;
-  }
-
-  // Evaluate RHS expression.
-  Expression* rhs = expr->value();
-  VisitForValue(rhs, kAccumulator);
-
-  // If we have a compound assignment: Apply operator.
-  if (expr->is_compound()) {
-    Location saved_location = location_;
-    location_ = kAccumulator;
+
+    Token::Value op = expr->binary_op();
+    ConstantOperand constant = ShouldInlineSmiCase(op)
+        ? GetConstantOperand(op, expr->target(), expr->value())
+        : kNoConstants;
+    ASSERT(constant == kRightConstant || constant == kNoConstants);
+    if (constant == kNoConstants) {
+      __ push(r0);  // Left operand goes on the stack.
+      VisitForValue(expr->value(), kAccumulator);
+    }
+
     OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
         ? OVERWRITE_RIGHT
         : NO_OVERWRITE;
-    EmitBinaryOp(expr->binary_op(), Expression::kValue, mode);
+    SetSourcePosition(expr->position() + 1);
+    if (ShouldInlineSmiCase(op)) {
+      EmitInlineSmiBinaryOp(expr,
+                            op,
+                            Expression::kValue,
+                            mode,
+                            expr->target(),
+                            expr->value(),
+                            constant);
+    } else {
+      EmitBinaryOp(op, Expression::kValue, mode);
+    }
     location_ = saved_location;
+
+  } else {
+    VisitForValue(expr->value(), kAccumulator);
   }

   // Record source position before possible IC call.
@@ -1251,6 +1268,18 @@
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   __ Call(ic, RelocInfo::CODE_TARGET);
 }
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+                                              Token::Value op,
+                                              Expression::Context context,
+                                              OverwriteMode mode,
+                                              Expression* left,
+                                              Expression* right,
+                                              ConstantOperand constant) {
+  ASSERT(constant == kNoConstants);  // Only handled case.
+  EmitBinaryOp(op, context, mode);
+}


 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
=======================================
--- /branches/bleeding_edge/src/ast.h   Wed Aug 25 04:10:05 2010
+++ /branches/bleeding_edge/src/ast.h   Thu Aug 26 01:50:38 2010
@@ -204,6 +204,9 @@
   // True iff the result can be safely overwritten (to avoid allocation).
   // False for operations that can return one of their operands.
   virtual bool ResultOverwriteAllowed() { return false; }
+
+  // True iff the expression is a literal represented as a smi.
+  virtual bool IsSmiLiteral() { return false; }

   // Static type information for this expression.
   StaticType* type() { return &type_; }
@@ -775,6 +778,7 @@

   virtual void Accept(AstVisitor* v);
   virtual bool IsTrivial() { return true; }
+  virtual bool IsSmiLiteral() { return handle_->IsSmi(); }

   // Type testing & conversion.
   virtual Literal* AsLiteral() { return this; }
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Wed Aug 25 07:22:03 2010
+++ /branches/bleeding_edge/src/full-codegen.cc Thu Aug 26 01:50:38 2010
@@ -516,18 +516,21 @@

 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
   Comment cmnt(masm_, "[ BinaryOperation");
-
-  OverwriteMode overwrite_mode = NO_OVERWRITE;
-  if (expr->left()->ResultOverwriteAllowed()) {
-    overwrite_mode = OVERWRITE_LEFT;
-  } else if (expr->right()->ResultOverwriteAllowed()) {
-    overwrite_mode = OVERWRITE_RIGHT;
+  Token::Value op = expr->op();
+  Expression* left = expr->left();
+  Expression* right = expr->right();
+
+  OverwriteMode mode = NO_OVERWRITE;
+  if (left->ResultOverwriteAllowed()) {
+    mode = OVERWRITE_LEFT;
+  } else if (right->ResultOverwriteAllowed()) {
+    mode = OVERWRITE_RIGHT;
   }

-  switch (expr->op()) {
+  switch (op) {
     case Token::COMMA:
-      VisitForEffect(expr->left());
-      Visit(expr->right());
+      VisitForEffect(left);
+      Visit(right);
       break;

     case Token::OR:
@@ -545,12 +548,31 @@
     case Token::BIT_XOR:
     case Token::SHL:
     case Token::SHR:
-    case Token::SAR:
-      VisitForValue(expr->left(), kStack);
-      VisitForValue(expr->right(), kAccumulator);
+    case Token::SAR: {
+      // Figure out if either of the operands is a constant.
+      ConstantOperand constant = ShouldInlineSmiCase(op)
+          ? GetConstantOperand(op, left, right)
+          : kNoConstants;
+
+      // Load only the operands that we need to materialize.
+      if (constant == kNoConstants) {
+        VisitForValue(left, kStack);
+        VisitForValue(right, kAccumulator);
+      } else if (constant == kRightConstant) {
+        VisitForValue(left, kAccumulator);
+      } else {
+        ASSERT(constant == kLeftConstant);
+        VisitForValue(right, kAccumulator);
+      }
+
       SetSourcePosition(expr->position());
-      EmitBinaryOp(expr->op(), context_, overwrite_mode);
+      if (ShouldInlineSmiCase(op)) {
+ EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
+      } else {
+        EmitBinaryOp(op, context_, mode);
+      }
       break;
+    }

     default:
       UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/full-codegen.h  Wed Aug 25 04:10:05 2010
+++ /branches/bleeding_edge/src/full-codegen.h  Thu Aug 26 01:50:38 2010
@@ -237,6 +237,12 @@
     kStack
   };

+  enum ConstantOperand {
+    kNoConstants,
+    kLeftConstant,
+    kRightConstant
+  };
+
   // Compute the frame pointer relative offset for a given local or
   // parameter slot.
   int SlotOffset(Slot* slot);
@@ -245,6 +251,11 @@
   // operation.
   bool ShouldInlineSmiCase(Token::Value op);

+  // Compute which (if any) of the operands is a compile-time constant.
+  ConstantOperand GetConstantOperand(Token::Value op,
+                                     Expression* left,
+                                     Expression* right);
+
   // Emit code to convert a pure value (in a register, slot, as a literal,
   // or on top of the stack) into the result expected according to an
   // expression context.
@@ -361,7 +372,6 @@
void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode); void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode);

-
   // Platform-specific code for inline runtime calls.
   void EmitInlineRuntimeCall(CallRuntime* expr);

@@ -393,6 +403,47 @@
                     Expression::Context context,
                     OverwriteMode mode);

+  // Helper functions for generating inlined smi code for certain
+  // binary operations.
+  void EmitInlineSmiBinaryOp(Expression* expr,
+                             Token::Value op,
+                             Expression::Context context,
+                             OverwriteMode mode,
+                             Expression* left,
+                             Expression* right,
+                             ConstantOperand constant);
+
+  void EmitConstantSmiBinaryOp(Expression* expr,
+                               Token::Value op,
+                               Expression::Context context,
+                               OverwriteMode mode,
+                               bool left_is_constant_smi,
+                               Smi* value);
+
+  void EmitConstantSmiBitOp(Expression* expr,
+                            Token::Value op,
+                            Expression::Context context,
+                            OverwriteMode mode,
+                            Smi* value);
+
+  void EmitConstantSmiShiftOp(Expression* expr,
+                              Token::Value op,
+                              Expression::Context context,
+                              OverwriteMode mode,
+                              Smi* value);
+
+  void EmitConstantSmiAdd(Expression* expr,
+                          Expression::Context context,
+                          OverwriteMode mode,
+                          bool left_is_constant_smi,
+                          Smi* value);
+
+  void EmitConstantSmiSub(Expression* expr,
+                          Expression::Context context,
+                          OverwriteMode mode,
+                          bool left_is_constant_smi,
+                          Smi* value);
+
// Assign to the given expression as if via '='. The right-hand-side value
   // is expected in the accumulator.
   void EmitAssignment(Expression* expr);
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Aug 25 07:22:03 2010 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Aug 26 01:50:38 2010
@@ -217,10 +217,26 @@
     // Check that the size of the code used for returning matches what is
     // expected by the debugger.
     ASSERT_EQ(Assembler::kJSReturnSequenceLength,
-            masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
+              masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
 #endif
   }
 }
+
+
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+    Token::Value op, Expression* left, Expression* right) {
+  ASSERT(ShouldInlineSmiCase(op));
+  if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
+    // We never generate inlined constant smi operations for these.
+    return kNoConstants;
+  } else if (right->IsSmiLiteral()) {
+    return kRightConstant;
+  } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
+    return kLeftConstant;
+  } else {
+    return kNoConstants;
+  }
+}


 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
@@ -1152,10 +1168,11 @@
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
   LhsKind assign_type = VARIABLE;
-  Property* prop = expr->target()->AsProperty();
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+  Property* property = expr->target()->AsProperty();
+  if (property != NULL) {
+    assign_type = (property->key()->IsPropertyName())
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
   }

   // Evaluate LHS expression.
@@ -1166,60 +1183,70 @@
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the accumulator.
-        VisitForValue(prop->obj(), kAccumulator);
+        VisitForValue(property->obj(), kAccumulator);
         __ push(result_register());
       } else {
-        VisitForValue(prop->obj(), kStack);
+        VisitForValue(property->obj(), kStack);
       }
       break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kAccumulator);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kAccumulator);
         __ mov(edx, Operand(esp, 0));
         __ push(eax);
       } else {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kStack);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kStack);
       }
       break;
   }

-  // If we have a compound assignment: Get value of LHS expression and
-  // store in on top of the stack.
   if (expr->is_compound()) {
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     switch (assign_type) {
       case VARIABLE:
         EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
                          Expression::kValue);
         break;
       case NAMED_PROPERTY:
-        EmitNamedPropertyLoad(prop);
-        __ push(result_register());
+        EmitNamedPropertyLoad(property);
         break;
       case KEYED_PROPERTY:
-        EmitKeyedPropertyLoad(prop);
-        __ push(result_register());
+        EmitKeyedPropertyLoad(property);
         break;
     }
-    location_ = saved_location;
-  }
-
-  // Evaluate RHS expression.
-  Expression* rhs = expr->value();
-  VisitForValue(rhs, kAccumulator);
-
-  // If we have a compound assignment: Apply operator.
-  if (expr->is_compound()) {
-    Location saved_location = location_;
-    location_ = kAccumulator;
+
+    Token::Value op = expr->binary_op();
+    ConstantOperand constant = ShouldInlineSmiCase(op)
+        ? GetConstantOperand(op, expr->target(), expr->value())
+        : kNoConstants;
+    ASSERT(constant == kRightConstant || constant == kNoConstants);
+    if (constant == kNoConstants) {
+      __ push(eax);  // Left operand goes on the stack.
+      VisitForValue(expr->value(), kAccumulator);
+    }
+
     OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
         ? OVERWRITE_RIGHT
         : NO_OVERWRITE;
-    EmitBinaryOp(expr->binary_op(), Expression::kValue, mode);
+    SetSourcePosition(expr->position() + 1);
+    if (ShouldInlineSmiCase(op)) {
+      EmitInlineSmiBinaryOp(expr,
+                            op,
+                            Expression::kValue,
+                            mode,
+                            expr->target(),
+                            expr->value(),
+                            constant);
+    } else {
+      EmitBinaryOp(op, Expression::kValue, mode);
+    }
     location_ = saved_location;
+
+  } else {
+    VisitForValue(expr->value(), kAccumulator);
   }

   // Record source position before possible IC call.
@@ -1258,6 +1285,313 @@
   __ call(ic, RelocInfo::CODE_TARGET);
   __ nop();
 }
+
+
+void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
+                                           Expression::Context context,
+                                           OverwriteMode mode,
+                                           bool left_is_constant_smi,
+                                           Smi* value) {
+  Label call_stub, done;
+  __ add(Operand(eax), Immediate(value));
+  __ j(overflow, &call_stub);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &done);
+
+  // Undo the optimistic add operation and call the shared stub.
+  __ bind(&call_stub);
+  __ sub(Operand(eax), Immediate(value));
+  Token::Value op = Token::ADD;
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  if (left_is_constant_smi) {
+    __ push(Immediate(value));
+    __ push(eax);
+  } else {
+    __ push(eax);
+    __ push(Immediate(value));
+  }
+  __ CallStub(&stub);
+  __ bind(&done);
+  Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
+                                           Expression::Context context,
+                                           OverwriteMode mode,
+                                           bool left_is_constant_smi,
+                                           Smi* value) {
+  Label call_stub, done;
+  if (left_is_constant_smi) {
+    __ mov(ecx, eax);
+    __ mov(eax, Immediate(value));
+    __ sub(Operand(eax), ecx);
+  } else {
+    __ sub(Operand(eax), Immediate(value));
+  }
+  __ j(overflow, &call_stub);
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &done);
+
+  __ bind(&call_stub);
+  if (left_is_constant_smi)  {
+    __ push(Immediate(value));
+    __ push(ecx);
+  } else {
+    // Undo the optimistic sub operation.
+    __ add(Operand(eax), Immediate(value));
+
+    __ push(eax);
+    __ push(Immediate(value));
+  }
+
+  Token::Value op = Token::SUB;
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  __ CallStub(&stub);
+  __ bind(&done);
+  Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
+                                               Token::Value op,
+                                               Expression::Context context,
+                                               OverwriteMode mode,
+                                               Smi* value) {
+  Label call_stub, smi_case, done;
+  int shift_value = value->value() & 0x1f;
+
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &smi_case);
+
+  __ bind(&call_stub);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  __ push(eax);
+  __ push(Immediate(value));
+  __ CallStub(&stub);
+  __ jmp(&done);
+
+  __ bind(&smi_case);
+  switch (op) {
+    case Token::SHL:
+      if (shift_value != 0) {
+        __ mov(edx, eax);
+        if (shift_value > 1) {
+          __ shl(edx, shift_value - 1);
+        }
+        // Convert int result to smi, checking that it is in int range.
+        ASSERT(kSmiTagSize == 1);  // Adjust code if not the case.
+        __ add(edx, Operand(edx));
+        __ j(overflow, &call_stub);
+        __ mov(eax, edx);  // Put result back into eax.
+      }
+      break;
+    case Token::SAR:
+      if (shift_value != 0) {
+        __ sar(eax, shift_value);
+        __ and_(eax, ~kSmiTagMask);
+      }
+      break;
+    case Token::SHR:
+      if (shift_value < 2) {
+        __ mov(edx, eax);
+        __ SmiUntag(edx);
+        __ shr(edx, shift_value);
+        __ test(edx, Immediate(0xc0000000));
+        __ j(not_zero, &call_stub);
+        __ SmiTag(edx);
+        __ mov(eax, edx);  // Put result back into eax.
+      } else {
+        __ SmiUntag(eax);
+        __ shr(eax, shift_value);
+        __ SmiTag(eax);
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  __ bind(&done);
+  Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
+                                             Token::Value op,
+                                             Expression::Context context,
+                                             OverwriteMode mode,
+                                             Smi* value) {
+  Label smi_case, done;
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &smi_case);
+
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  // The order of the arguments does not matter for bit-ops with a
+  // constant operand.
+  __ push(Immediate(value));
+  __ push(eax);
+  __ CallStub(&stub);
+  __ jmp(&done);
+
+  __ bind(&smi_case);
+  switch (op) {
+    case Token::BIT_OR:
+      __ or_(Operand(eax), Immediate(value));
+      break;
+    case Token::BIT_XOR:
+      __ xor_(Operand(eax), Immediate(value));
+      break;
+    case Token::BIT_AND:
+      __ and_(Operand(eax), Immediate(value));
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  __ bind(&done);
+  Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
+                                                Token::Value op,
+ Expression::Context context,
+                                                OverwriteMode mode,
+                                                bool left_is_constant_smi,
+                                                Smi* value) {
+  switch (op) {
+    case Token::BIT_OR:
+    case Token::BIT_XOR:
+    case Token::BIT_AND:
+      EmitConstantSmiBitOp(expr, op, context, mode, value);
+      break;
+    case Token::SHL:
+    case Token::SAR:
+    case Token::SHR:
+      ASSERT(!left_is_constant_smi);
+      EmitConstantSmiShiftOp(expr, op, context, mode, value);
+      break;
+    case Token::ADD:
+      EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value);
+      break;
+    case Token::SUB:
+      EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+                                              Token::Value op,
+                                              Expression::Context context,
+                                              OverwriteMode mode,
+                                              Expression* left,
+                                              Expression* right,
+                                              ConstantOperand constant) {
+  if (constant == kRightConstant) {
+    Smi* value =  Smi::cast(*right->AsLiteral()->handle());
+    EmitConstantSmiBinaryOp(expr, op, context, mode, false, value);
+    return;
+  } else if (constant == kLeftConstant) {
+    Smi* value =  Smi::cast(*left->AsLiteral()->handle());
+    EmitConstantSmiBinaryOp(expr, op, context, mode, true, value);
+    return;
+  }
+
+  // Do combined smi check of the operands. Left operand is on the
+  // stack. Right operand is in eax.
+  Label done, stub_call, smi_case;
+  __ pop(edx);
+  __ mov(ecx, eax);
+  __ or_(eax, Operand(edx));
+  __ test(eax, Immediate(kSmiTagMask));
+  __ j(zero, &smi_case);
+
+  __ bind(&stub_call);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  if (stub.ArgsInRegistersSupported()) {
+    stub.GenerateCall(masm_, edx, ecx);
+  } else {
+    __ push(edx);
+    __ push(ecx);
+    __ CallStub(&stub);
+  }
+  __ jmp(&done);
+
+  __ bind(&smi_case);
+  __ mov(eax, edx);  // Copy left operand in case of a stub call.
+
+  switch (op) {
+    case Token::SAR:
+      __ SmiUntag(eax);
+      __ SmiUntag(ecx);
+      __ sar_cl(eax);  // No checks of result necessary
+      __ SmiTag(eax);
+      break;
+    case Token::SHL: {
+      Label result_ok;
+      __ SmiUntag(eax);
+      __ SmiUntag(ecx);
+      __ shl_cl(eax);
+      // Check that the *signed* result fits in a smi.
+      __ cmp(eax, 0xc0000000);
+      __ j(positive, &result_ok);
+      __ SmiTag(ecx);
+      __ jmp(&stub_call);
+      __ bind(&result_ok);
+      __ SmiTag(eax);
+      break;
+    }
+    case Token::SHR: {
+      Label result_ok;
+      __ SmiUntag(eax);
+      __ SmiUntag(ecx);
+      __ shr_cl(eax);
+      __ test(eax, Immediate(0xc0000000));
+      __ j(zero, &result_ok);
+      __ SmiTag(ecx);
+      __ jmp(&stub_call);
+      __ bind(&result_ok);
+      __ SmiTag(eax);
+      break;
+    }
+    case Token::ADD:
+      __ add(eax, Operand(ecx));
+      __ j(overflow, &stub_call);
+      break;
+    case Token::SUB:
+      __ sub(eax, Operand(ecx));
+      __ j(overflow, &stub_call);
+      break;
+    case Token::MUL: {
+      __ SmiUntag(eax);
+      __ imul(eax, Operand(ecx));
+      __ j(overflow, &stub_call);
+      __ test(eax, Operand(eax));
+      __ j(not_zero, &done, taken);
+      __ mov(ebx, edx);
+      __ or_(ebx, Operand(ecx));
+      __ j(negative, &stub_call);
+      break;
+    }
+    case Token::BIT_OR:
+      __ or_(eax, Operand(ecx));
+      break;
+    case Token::BIT_AND:
+      __ and_(eax, Operand(ecx));
+      break;
+    case Token::BIT_XOR:
+      __ xor_(eax, Operand(ecx));
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  __ bind(&done);
+  Apply(context, eax);
+}


 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
=======================================
--- /branches/bleeding_edge/src/token.h Fri Aug  6 01:03:44 2010
+++ /branches/bleeding_edge/src/token.h Thu Aug 26 01:50:38 2010
@@ -247,6 +247,10 @@
   static bool IsCountOp(Value op) {
     return op == INC || op == DEC;
   }
+
+  static bool IsShiftOp(Value op) {
+    return (SHL <= op) && (op <= SHR);
+  }

   // Returns a string corresponding to the JS token string
   // (.e., "<" for the token LT) or NULL if the token doesn't
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Aug 25 07:22:03 2010 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Aug 26 01:50:38 2010
@@ -228,6 +228,13 @@
 #endif
   }
 }
+
+
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+    Token::Value op, Expression* left, Expression* right) {
+  ASSERT(ShouldInlineSmiCase(op));
+  return kNoConstants;
+}


 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
@@ -1156,10 +1163,11 @@
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
   LhsKind assign_type = VARIABLE;
-  Property* prop = expr->target()->AsProperty();
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+  Property* property = expr->target()->AsProperty();
+  if (property != NULL) {
+    assign_type = (property->key()->IsPropertyName())
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
   }

   // Evaluate LHS expression.
@@ -1170,60 +1178,70 @@
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the accumulator.
-        VisitForValue(prop->obj(), kAccumulator);
+        VisitForValue(property->obj(), kAccumulator);
         __ push(result_register());
       } else {
-        VisitForValue(prop->obj(), kStack);
+        VisitForValue(property->obj(), kStack);
       }
       break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kAccumulator);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kAccumulator);
         __ movq(rdx, Operand(rsp, 0));
         __ push(rax);
       } else {
-        VisitForValue(prop->obj(), kStack);
-        VisitForValue(prop->key(), kStack);
+        VisitForValue(property->obj(), kStack);
+        VisitForValue(property->key(), kStack);
       }
       break;
   }

-  // If we have a compound assignment: Get value of LHS expression and
-  // store in on top of the stack.
   if (expr->is_compound()) {
     Location saved_location = location_;
-    location_ = kStack;
+    location_ = kAccumulator;
     switch (assign_type) {
       case VARIABLE:
         EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
                          Expression::kValue);
         break;
       case NAMED_PROPERTY:
-        EmitNamedPropertyLoad(prop);
-        __ push(result_register());
+        EmitNamedPropertyLoad(property);
         break;
       case KEYED_PROPERTY:
-        EmitKeyedPropertyLoad(prop);
-        __ push(result_register());
+        EmitKeyedPropertyLoad(property);
         break;
     }
-    location_ = saved_location;
-  }
-
-  // Evaluate RHS expression.
-  Expression* rhs = expr->value();
-  VisitForValue(rhs, kAccumulator);
-
-  // If we have a compound assignment: Apply operator.
-  if (expr->is_compound()) {
-    Location saved_location = location_;
-    location_ = kAccumulator;
+
+    Token::Value op = expr->binary_op();
+    ConstantOperand constant = ShouldInlineSmiCase(op)
+        ? GetConstantOperand(op, expr->target(), expr->value())
+        : kNoConstants;
+    ASSERT(constant == kRightConstant || constant == kNoConstants);
+    if (constant == kNoConstants) {
+      __ push(rax);  // Left operand goes on the stack.
+      VisitForValue(expr->value(), kAccumulator);
+    }
+
     OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
         ? OVERWRITE_RIGHT
         : NO_OVERWRITE;
-    EmitBinaryOp(expr->binary_op(), Expression::kValue, mode);
+    SetSourcePosition(expr->position() + 1);
+    if (ShouldInlineSmiCase(op)) {
+      EmitInlineSmiBinaryOp(expr,
+                            op,
+                            Expression::kValue,
+                            mode,
+                            expr->target(),
+                            expr->value(),
+                            constant);
+    } else {
+      EmitBinaryOp(op, Expression::kValue, mode);
+    }
     location_ = saved_location;
+
+  } else {
+    VisitForValue(expr->value(), kAccumulator);
   }

   // Record source position before possible IC call.
@@ -1262,6 +1280,74 @@
   __ Call(ic, RelocInfo::CODE_TARGET);
   __ nop();
 }
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+                                              Token::Value op,
+                                              Expression::Context context,
+                                              OverwriteMode mode,
+                                              Expression* left,
+                                              Expression* right,
+                                              ConstantOperand constant) {
+  ASSERT(constant == kNoConstants);  // Only handled case.
+
+  // Do combined smi check of the operands. Left operand is on the
+  // stack (popped into rdx). Right operand is in rax but moved into
+  // rcx to make the shifts easier.
+  Label done, stub_call, smi_case;
+  __ pop(rdx);
+  __ movq(rcx, rax);
+  Condition smi = __ CheckBothSmi(rdx, rax);
+  __ j(smi, &smi_case);
+
+  __ bind(&stub_call);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+  if (stub.ArgsInRegistersSupported()) {
+    stub.GenerateCall(masm_, rdx, rcx);
+  } else {
+    __ push(rdx);
+    __ push(rcx);
+    __ CallStub(&stub);
+  }
+  __ jmp(&done);
+
+  __ bind(&smi_case);
+  switch (op) {
+    case Token::SAR:
+      __ SmiShiftArithmeticRight(rax, rdx, rcx);
+      break;
+    case Token::SHL:
+      __ SmiShiftLeft(rax, rdx, rcx);
+      break;
+    case Token::SHR:
+      __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
+      break;
+    case Token::ADD:
+      __ SmiAdd(rax, rdx, rcx, &stub_call);
+      break;
+    case Token::SUB:
+      __ SmiSub(rax, rdx, rcx, &stub_call);
+      break;
+    case Token::MUL:
+      __ SmiMul(rax, rdx, rcx, &stub_call);
+      break;
+    case Token::BIT_OR:
+      __ SmiOr(rax, rdx, rcx);
+      break;
+    case Token::BIT_AND:
+      __ SmiAnd(rax, rdx, rcx);
+      break;
+    case Token::BIT_XOR:
+      __ SmiXor(rax, rdx, rcx);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+
+  __ bind(&done);
+  Apply(context, rax);
+}


 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
@@ -1971,8 +2057,8 @@
 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);

-  // ArgumentsAccessStub expects the key in edx and the formal
-  // parameter count in eax.
+  // ArgumentsAccessStub expects the key in rdx and the formal
+  // parameter count in rax.
   VisitForValue(args->at(0), kAccumulator);
   __ movq(rdx, rax);
   __ Move(rax, Smi::FromInt(scope()->num_parameters()));
@@ -2176,7 +2262,7 @@

   VisitForValue(args->at(0), kStack);  // Load the object.
   VisitForValue(args->at(1), kAccumulator);  // Load the value.
-  __ pop(rbx);  // rax = value. ebx = object.
+  __ pop(rbx);  // rax = value. rbx = object.

   Label done;
   // If the object is a smi, return the value.

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

Reply via email to