X64: Made simpler version of fast-smi-loop code.

It avoids the overflow check on the increment.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4998 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2010-07-01 13:19:32 +00:00
parent 9added5953
commit 59f2b6c825
3 changed files with 129 additions and 17 deletions

View File

@ -1600,11 +1600,130 @@ void CodeGenerator::SetTypeForStackSlot(Slot* slot, TypeInfo info) {
} }
void CodeGenerator::GenerateFastSmiLoop(ForStatement* node) {
// A fast smi loop is a for loop with an initializer
// that is a simple assignment of a smi to a stack variable,
// a test that is a simple test of that variable against a smi constant,
// and a step that is a increment/decrement of the variable, and
// where the variable isn't modified in the loop body.
// This guarantees that the variable is always a smi.
Variable* loop_var = node->loop_variable();
Smi* initial_value = *Handle<Smi>::cast(node->init()
->StatementAsSimpleAssignment()->value()->AsLiteral()->handle());
Smi* limit_value = *Handle<Smi>::cast(
node->cond()->AsCompareOperation()->right()->AsLiteral()->handle());
Token::Value compare_op =
node->cond()->AsCompareOperation()->op();
bool increments =
node->next()->StatementAsCountOperation()->op() == Token::INC;
// Check that the condition isn't initially false.
bool initially_false = false;
int initial_int_value = initial_value->value();
int limit_int_value = limit_value->value();
switch (compare_op) {
case Token::LT:
initially_false = initial_int_value >= limit_int_value;
break;
case Token::LTE:
initially_false = initial_int_value > limit_int_value;
break;
case Token::GT:
initially_false = initial_int_value <= limit_int_value;
break;
case Token::GTE:
initially_false = initial_int_value < limit_int_value;
break;
default:
UNREACHABLE();
}
if (initially_false) return;
// Only check loop condition at the end.
Visit(node->init());
JumpTarget loop(JumpTarget::BIDIRECTIONAL);
IncrementLoopNesting();
loop.Bind();
// Set number type of the loop variable to smi.
CheckStack(); // TODO(1222600): ignore if body contains calls.
SetTypeForStackSlot(loop_var->slot(), TypeInfo::Smi());
Visit(node->body());
if (node->continue_target()->is_linked()) {
node->continue_target()->Bind();
}
if (has_valid_frame()) {
CodeForStatementPosition(node);
Slot* loop_var_slot = loop_var->slot();
if (loop_var_slot->type() == Slot::LOCAL) {
frame_->PushLocalAt(loop_var_slot->index());
} else {
ASSERT(loop_var_slot->type() == Slot::PARAMETER);
frame_->PushParameterAt(loop_var_slot->index());
}
Result loop_var_result = frame_->Pop();
if (!loop_var_result.is_register()) {
loop_var_result.ToRegister();
}
if (increments) {
__ SmiAddConstant(loop_var_result.reg(),
loop_var_result.reg(),
Smi::FromInt(1));
} else {
__ SmiSubConstant(loop_var_result.reg(),
loop_var_result.reg(),
Smi::FromInt(1));
}
{
__ SmiCompare(loop_var_result.reg(), limit_value);
Condition condition;
switch (compare_op) {
case Token::LT:
condition = less;
break;
case Token::LTE:
condition = less_equal;
break;
case Token::GT:
condition = greater;
break;
case Token::GTE:
condition = greater_equal;
break;
default:
condition = never;
UNREACHABLE();
}
loop.Branch(condition);
}
loop_var_result.Unuse();
}
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
}
DecrementLoopNesting();
}
void CodeGenerator::VisitForStatement(ForStatement* node) { void CodeGenerator::VisitForStatement(ForStatement* node) {
ASSERT(!in_spilled_code()); ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ ForStatement"); Comment cmnt(masm_, "[ ForStatement");
CodeForStatementPosition(node); CodeForStatementPosition(node);
if (node->is_fast_smi_loop()) {
GenerateFastSmiLoop(node);
return;
}
// Compile the init expression if present. // Compile the init expression if present.
if (node->init() != NULL) { if (node->init() != NULL) {
Visit(node->init()); Visit(node->init());
@ -1694,16 +1813,6 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
// We know that the loop index is a smi if it is not modified in the
// loop body and it is checked against a constant limit in the loop
// condition. In this case, we reset the static type information of the
// loop index to smi before compiling the body, the update expression, and
// the bottom check of the loop condition.
if (node->is_fast_smi_loop()) {
// Set number type of the loop variable to smi.
SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
}
Visit(node->body()); Visit(node->body());
// If there is an update expression, compile it if necessary. // If there is an update expression, compile it if necessary.
@ -1723,13 +1832,6 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
} }
} }
// Set the type of the loop variable to smi before compiling the test
// expression if we are in a fast smi loop condition.
if (node->is_fast_smi_loop() && has_valid_frame()) {
// Set number type of the loop variable to smi.
SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
}
// Based on the condition analysis, compile the backward jump as // Based on the condition analysis, compile the backward jump as
// necessary. // necessary.
switch (info) { switch (info) {

View File

@ -393,6 +393,9 @@ class CodeGenerator: public AstVisitor {
// target (which can not be done more than once). // target (which can not be done more than once).
void GenerateReturnSequence(Result* return_value); void GenerateReturnSequence(Result* return_value);
// Generate code for a fast smi loop.
void GenerateFastSmiLoop(ForStatement* node);
// Returns the arguments allocation mode. // Returns the arguments allocation mode.
ArgumentsAllocationMode ArgumentsMode(); ArgumentsAllocationMode ArgumentsMode();

View File

@ -388,6 +388,13 @@ class VirtualFrame : public ZoneObject {
// Duplicate the top element of the frame. // Duplicate the top element of the frame.
void Dup() { PushFrameSlotAt(element_count() - 1); } void Dup() { PushFrameSlotAt(element_count() - 1); }
// Duplicate the n'th element from the top of the frame.
// Dup(1) is equivalent to Dup().
void Dup(int n) {
ASSERT(n > 0);
PushFrameSlotAt(element_count() - n);
}
// Pop an element from the top of the expression stack. Returns a // Pop an element from the top of the expression stack. Returns a
// Result, which may be a constant or a register. // Result, which may be a constant or a register.
Result Pop(); Result Pop();