Add binary operations to fast compiler.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Oct 2009 11:55:03 +0000 (11:55 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Oct 2009 11:55:03 +0000 (11:55 +0000)
Review URL: http://codereview.chromium.org/342019

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

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/fast-codegen.h
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc

index 49b2574..a500753 100644 (file)
@@ -607,7 +607,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
   for (int i = 0; i < arg_count; i++) {
     Visit(args->at(i));
     ASSERT(args->at(i)->location().is_value());
-    // If location is temporary, it is already on the stack,
+    // If location is value, it is already on the stack,
     // so nothing to do here.
   }
 
@@ -648,11 +648,57 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
 
 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
-  // Compile a short-circuited boolean or operation in a non-test
-  // context.
-  ASSERT(expr->op() == Token::OR);
+  switch (expr->op()) {
+    case Token::COMMA:
+      ASSERT(expr->left()->location().is_effect());
+      ASSERT_EQ(expr->right()->location().type(), expr->location().type());
+      Visit(expr->left());
+      Visit(expr->right());
+      break;
+
+    case Token::OR:
+    case Token::AND:
+      EmitLogicalOperation(expr);
+      break;
+
+    case Token::ADD:
+    case Token::SUB:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      ASSERT(expr->left()->location().is_value());
+      ASSERT(expr->right()->location().is_value());
+
+      Visit(expr->left());
+      Visit(expr->right());
+      __ pop(r0);
+      __ pop(r1);
+      GenericBinaryOpStub stub(expr->op(),
+                               NO_OVERWRITE);
+      __ CallStub(&stub);
+      Move(expr->location(), r0);
+
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
+  // Compile a short-circuited boolean operation in a non-test context.
+
   // Compile (e0 || e1) as if it were
   // (let (temp = e0) temp ? temp : e1).
+  // Compile (e0 && e1) as if it were
+  // (let (temp = e0) !temp ? temp : e1).
 
   Label done;
   Location destination = expr->location();
@@ -675,9 +721,13 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
     }
   }
   // The left-hand value is in on top of the stack.  It is duplicated on the
-  // stack iff the destination location is temporary.
+  // stack iff the destination location is value.
   __ CallRuntime(Runtime::kToBool, 1);
-  __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+  if (expr->op() == Token::OR) {
+    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+  } else {
+    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+  }
   __ cmp(r0, ip);
   __ b(eq, &done);
 
index 63bf2ec..129f1aa 100644 (file)
@@ -849,6 +849,12 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
 
 void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
   switch (expr->op()) {
+    case Token::COMMA:
+      VisitAsEffect(expr->left());
+      CHECK_BAILOUT;
+      Visit(expr->right());  // Location is the same as the parent location.
+      break;
+
     case Token::OR:
       VisitAsValue(expr->left());
       CHECK_BAILOUT;
@@ -857,6 +863,22 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
       Visit(expr->right());
       break;
 
+    case Token::ADD:
+    case Token::SUB:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR:
+      VisitAsValue(expr->left());
+      CHECK_BAILOUT;
+      VisitAsValue(expr->right());
+      break;
+
     default:
       BAILOUT("Unsupported binary operation");
   }
index a718157..33e6b9b 100644 (file)
@@ -78,6 +78,9 @@ class FastCodeGenerator: public AstVisitor {
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
+  // Handles the shortcutted logical binary operations in VisitBinaryOperation.
+  void EmitLogicalOperation(BinaryOperation* expr);
+
   MacroAssembler* masm_;
   FunctionLiteral* function_;
   Handle<Script> script_;
index 520fd07..9f7f623 100644 (file)
@@ -590,7 +590,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
   for (int i = 0; i < arg_count; i++) {
     Visit(args->at(i));
     ASSERT(args->at(i)->location().is_value());
-    // If location is temporary, it is already on the stack,
+    // If location is value, it is already on the stack,
     // so nothing to do here.
   }
 
@@ -631,13 +631,64 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
 
 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
-  // Compile a short-circuited boolean or operation in a non-test
-  // context.
-  ASSERT(expr->op() == Token::OR);
-  // Compile (e0 || e1) as if it were
-  // (let (temp = e0) temp ? temp : e1).
+  switch (expr->op()) {
+    case Token::COMMA:
+      ASSERT(expr->left()->location().is_effect());
+      ASSERT_EQ(expr->right()->location().type(), expr->location().type());
+      Visit(expr->left());
+      Visit(expr->right());
+      break;
+
+    case Token::OR:
+    case Token::AND:
+      EmitLogicalOperation(expr);
+      break;
+
+    case Token::ADD:
+    case Token::SUB:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      ASSERT(expr->left()->location().is_value());
+      ASSERT(expr->right()->location().is_value());
+
+      Visit(expr->left());
+      Visit(expr->right());
+      GenericBinaryOpStub stub(expr->op(),
+                               NO_OVERWRITE,
+                               NO_GENERIC_BINARY_FLAGS);
+      __ CallStub(&stub);
+      Move(expr->location(), eax);
+
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
+  // Compile a short-circuited boolean operation in a non-test context.
+
+  // Compile (e0 || e1) or (e0 && e1) as if it were
+  // (let (temp = e0) temp [or !temp, for &&] ? temp : e1).
 
   Label eval_right, done;
+  Label *left_true, *left_false;  // Where to branch to if lhs has that value.
+  if (expr->op() == Token::OR) {
+    left_true = &done;
+    left_false = &eval_right;
+  } else {
+    left_true = &eval_right;
+    left_false = &done;
+  }
   Location destination = expr->location();
   Expression* left = expr->left();
   Expression* right = expr->right();
@@ -670,27 +721,31 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
     }
   }
   // The left-hand value is in eax.  It is also on the stack iff the
-  // destination location is temporary.
+  // destination location is value.
 
   // Perform fast checks assumed by the stub.
   __ cmp(eax, Factory::undefined_value());  // The undefined value is false.
-  __ j(equal, &eval_right);
+  __ j(equal, left_false);
   __ cmp(eax, Factory::true_value());  // True is true.
-  __ j(equal, &done);
+  __ j(equal, left_true);
   __ cmp(eax, Factory::false_value());  // False is false.
-  __ j(equal, &eval_right);
+  __ j(equal, left_false);
   ASSERT(kSmiTag == 0);
   __ test(eax, Operand(eax));  // The smi zero is false.
-  __ j(zero, &eval_right);
+  __ j(zero, left_false);
   __ test(eax, Immediate(kSmiTagMask));  // All other smis are true.
-  __ j(zero, &done);
+  __ j(zero, left_true);
 
   // Call the stub for all other cases.
   __ push(eax);
   ToBooleanStub stub;
   __ CallStub(&stub);
   __ test(eax, Operand(eax));  // The stub returns nonzero for true.
-  __ j(not_zero, &done);
+  if (expr->op() == Token::OR) {
+    __ j(not_zero, &done);
+  } else {
+    __ j(zero, &done);
+  }
 
   __ bind(&eval_right);
   // Discard the left-hand value if present on the stack.
index 2c9212b..d419e40 100644 (file)
@@ -593,7 +593,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
   // Push function on the stack.
   Visit(node->expression());
   ASSERT(node->expression()->location().is_value());
-  // If location is temporary, already on the stack,
+  // If location is value, already on the stack,
 
   // Push global object (receiver).
   __ push(CodeGenerator::GlobalObject());
@@ -604,7 +604,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
   for (int i = 0; i < arg_count; i++) {
     Visit(args->at(i));
     ASSERT(args->at(i)->location().is_value());
-    // If location is temporary, it is already on the stack,
+    // If location is value, it is already on the stack,
     // so nothing to do here.
   }
 
@@ -645,13 +645,66 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
 
 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
-  // Compile a short-circuited boolean or operation in a non-test
-  // context.
-  ASSERT(expr->op() == Token::OR);
+  switch (expr->op()) {
+    case Token::COMMA:
+      ASSERT(expr->left()->location().is_effect());
+      ASSERT_EQ(expr->right()->location().type(), expr->location().type());
+      Visit(expr->left());
+      Visit(expr->right());
+      break;
+
+    case Token::OR:
+    case Token::AND:
+      EmitLogicalOperation(expr);
+      break;
+
+    case Token::ADD:
+    case Token::SUB:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      ASSERT(expr->left()->location().is_value());
+      ASSERT(expr->right()->location().is_value());
+
+      Visit(expr->left());
+      Visit(expr->right());
+      GenericBinaryOpStub stub(expr->op(),
+                               NO_OVERWRITE,
+                               NO_GENERIC_BINARY_FLAGS);
+      __ CallStub(&stub);
+      Move(expr->location(), kReturnRegister);
+
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
+  // Compile a short-circuited boolean operation in a non-test context.
+
   // Compile (e0 || e1) as if it were
   // (let (temp = e0) temp ? temp : e1).
+  // Compile (e0 && e1) as if it were
+  // (let (temp = e0) !temp ? temp : e1).
 
   Label eval_right, done;
+  Label *left_true, *left_false;  // Where to branch to if lhs has that value.
+  if (expr->op() == Token::OR) {
+    left_true = &done;
+    left_false = &eval_right;
+  } else {
+    left_true = &eval_right;
+    left_false = &done;
+  }
   Location destination = expr->location();
   Expression* left = expr->left();
   Expression* right = expr->right();
@@ -684,28 +737,32 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
     }
   }
   // The left-hand value is in rax.  It is also on the stack iff the
-  // destination location is temporary.
+  // destination location is value.
 
   // Perform fast checks assumed by the stub.
   // The undefined value is false.
   __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
-  __ j(equal, &eval_right);
+  __ j(equal, left_false);
   __ CompareRoot(rax, Heap::kTrueValueRootIndex);  // True is true.
-  __ j(equal, &done);
+  __ j(equal, left_true);
   __ CompareRoot(rax, Heap::kFalseValueRootIndex);  // False is false.
-  __ j(equal, &eval_right);
+  __ j(equal, left_false);
   ASSERT(kSmiTag == 0);
   __ SmiCompare(rax, Smi::FromInt(0));  // The smi zero is false.
-  __ j(equal, &eval_right);
+  __ j(equal, left_false);
   Condition is_smi = masm_->CheckSmi(rax);  // All other smis are true.
-  __ j(is_smi, &done);
+  __ j(is_smi, left_true);
 
   // Call the stub for all other cases.
   __ push(rax);
   ToBooleanStub stub;
   __ CallStub(&stub);
   __ testq(rax, rax);  // The stub returns nonzero for true.
-  __ j(not_zero, &done);
+  if (expr->op() == Token::OR) {
+    __ j(not_zero, &done);
+  } else {
+    __ j(zero, &done);
+  }
 
   __ bind(&eval_right);
   // Discard the left-hand value if present on the stack.