Revision: 3172
Author: [email protected]
Date: Thu Oct 29 04:55:03 2009
Log: Add binary operations to fast compiler.
Review URL: http://codereview.chromium.org/342019
http://code.google.com/p/v8/source/detail?r=3172
Modified:
/branches/bleeding_edge/src/arm/fast-codegen-arm.cc
/branches/bleeding_edge/src/compiler.cc
/branches/bleeding_edge/src/fast-codegen.h
/branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
/branches/bleeding_edge/src/x64/fast-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Oct 29 03:35:29
2009
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Oct 29 04:55:03
2009
@@ -607,7 +607,7 @@
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::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 @@
}
}
// 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);
=======================================
--- /branches/bleeding_edge/src/compiler.cc Thu Oct 29 03:35:29 2009
+++ /branches/bleeding_edge/src/compiler.cc Thu Oct 29 04:55:03 2009
@@ -849,6 +849,12 @@
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 @@
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");
}
=======================================
--- /branches/bleeding_edge/src/fast-codegen.h Wed Oct 28 02:56:14 2009
+++ /branches/bleeding_edge/src/fast-codegen.h Thu Oct 29 04:55:03 2009
@@ -78,6 +78,9 @@
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_;
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Thu Oct 29
03:35:29 2009
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Thu Oct 29
04:55:03 2009
@@ -590,7 +590,7 @@
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::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 @@
}
}
// 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.
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Oct 29 03:35:29
2009
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Oct 29 04:55:03
2009
@@ -593,7 +593,7 @@
// 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 @@
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::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 @@
}
}
// 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.
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---