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:
parent
9added5953
commit
59f2b6c825
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user