Recognize in the fast-mode code generator when a subexpression is a

constant known at compile time.  Do not ever use the stack to
materialize (non-function-argument) constants.  Currently, constants
are only the non-materialized, non-function literals in the AST.

It is a known issue that there is no test coverage for the cases of
assigning a non-literal to a variable and returning a literal.  Those
code paths are unreachable and tests will be added when they become
reachable.

For the code '.result = true', we had previously on ia32:

27  push 0xf5c28161             ;; object: 0xf5c28161 <true>
32  pop [ebp+0xf4]

Now:

27  mov eax,0xf5c26161          ;; object: 0xf5c26161 <true>
32  mov [ebp+0xf4],eax

======== We had previously on x64:

25  movq r10,0x7fb8c2f78199    ;; object: 0x7fb8c2f78199 <true>
35  push r10
37  pop [rbp-0x18]

Now:

25  movq r10,0x7fb131386199    ;; object: 0x7fb131386199 <true>
35  movq [rbp-0x18],r10

The generated code for ARM did not include the extra memory traffic.
It was already eliminated by the ARM assembler's push/pop elimination.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3088 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2009-10-19 10:36:42 +00:00
parent 7324ec0f83
commit 846688f825
6 changed files with 139 additions and 57 deletions

View File

@ -114,8 +114,19 @@ void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt); SetStatementPosition(stmt);
Visit(stmt->expression()); Expression* expr = stmt->expression();
__ pop(r0); Visit(expr);
// Complete the statement based on the location of the subexpression.
Location source = expr->location();
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
__ pop(r0);
} else {
ASSERT(source.is_constant());
ASSERT(expr->AsLiteral() != NULL);
__ mov(r0, Operand(expr->AsLiteral()->handle()));
}
__ RecordJSReturn(); __ RecordJSReturn();
__ mov(sp, fp); __ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit()); __ ldm(ia_w, sp, fp.bit() | lr.bit());
@ -143,33 +154,46 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
} }
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
if (expr->location().is_temporary()) {
__ mov(ip, Operand(expr->handle()));
__ push(ip);
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) { void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
Expression* rhs = expr->value();
Visit(rhs);
Visit(expr->value()); // Left-hand side is always a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && var->slot() != NULL); ASSERT(var != NULL && var->slot() != NULL);
if (expr->location().is_temporary()) { // Complete the assignment based on the location of the right-hand-side
__ ldr(ip, MemOperand(sp)); // value and the desired location of the assignment value.
Location destination = expr->location();
Location source = rhs->location();
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
if (destination.is_temporary()) {
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
// on the stack.
__ ldr(ip, MemOperand(sp));
} else {
ASSERT(destination.is_nowhere());
// Case 'var = temp'. Discard right-hand-side temporary.
__ pop(ip);
}
__ str(ip, MemOperand(fp, SlotOffset(var->slot())));
} else { } else {
ASSERT(expr->location().is_nowhere()); ASSERT(source.is_constant());
__ pop(ip); ASSERT(rhs->AsLiteral() != NULL);
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
// discarded result. Always perform the assignment.
__ mov(ip, Operand(rhs->AsLiteral()->handle()));
__ str(ip, MemOperand(fp, SlotOffset(var->slot())));
if (destination.is_temporary()) {
// Case 'temp <- (var = constant)'. Save result.
__ push(ip);
}
} }
__ str(ip, MemOperand(fp, SlotOffset(var->slot())));
} }

View File

@ -614,6 +614,7 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
void CodeGenSelector::VisitLiteral(Literal* expr) { void CodeGenSelector::VisitLiteral(Literal* expr) {
// All literals are supported. // All literals are supported.
expr->set_location(Location::Constant());
} }

View File

@ -196,6 +196,11 @@ void FastCodeGenerator::VisitSlot(Slot* expr) {
} }
void FastCodeGenerator::VisitLiteral(Literal* expr) {
// No code is emitted (here) for simple literals.
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -104,8 +104,19 @@ void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt); SetStatementPosition(stmt);
Visit(stmt->expression()); Expression* expr = stmt->expression();
__ pop(eax); Visit(expr);
// Complete the statement based on the location of the subexpression.
Location source = expr->location();
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
__ pop(eax);
} else {
ASSERT(source.is_constant());
ASSERT(expr->AsLiteral() != NULL);
__ mov(eax, expr->AsLiteral()->handle());
}
__ RecordJSReturn(); __ RecordJSReturn();
// Do not use the leave instruction here because it is too short to // Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger. // patch with the code required by the debugger.
@ -132,30 +143,45 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
} }
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
if (expr->location().is_temporary()) {
__ push(Immediate(expr->handle()));
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) { void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
Visit(expr->value()); Expression* rhs = expr->value();
Visit(rhs);
// Left-hand side is always a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && var->slot() != NULL); ASSERT(var != NULL && var->slot() != NULL);
if (expr->location().is_temporary()) { // Complete the assignment based on the location of the right-hand-side
__ mov(eax, Operand(esp, 0)); // value and the desired location of the assignment value.
__ mov(Operand(ebp, SlotOffset(var->slot())), eax); Location destination = expr->location();
Location source = rhs->location();
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
if (destination.is_temporary()) {
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
// on the stack.
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
} else {
ASSERT(destination.is_nowhere());
// Case 'var = temp'. Discard right-hand-side temporary.
__ pop(Operand(ebp, SlotOffset(var->slot())));
}
} else { } else {
ASSERT(expr->location().is_nowhere()); ASSERT(source.is_constant());
__ pop(Operand(ebp, SlotOffset(var->slot()))); ASSERT(rhs->AsLiteral() != NULL);
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
// discarded result. Always perform the assignment.
__ mov(eax, rhs->AsLiteral()->handle());
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
if (destination.is_temporary()) {
// Case 'temp <- (var = constant)'. Save result.
__ push(eax);
}
} }
} }

View File

@ -41,6 +41,7 @@ class Location BASE_EMBEDDED {
bool is_temporary() { return type_ == TEMP; } bool is_temporary() { return type_ == TEMP; }
bool is_nowhere() { return type_ == NOWHERE; } bool is_nowhere() { return type_ == NOWHERE; }
bool is_constant() { return type_ == CONSTANT; }
private: private:
enum Type { TEMP, NOWHERE, CONSTANT }; enum Type { TEMP, NOWHERE, CONSTANT };

View File

@ -112,8 +112,19 @@ void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt); SetStatementPosition(stmt);
Visit(stmt->expression()); Expression* expr = stmt->expression();
__ pop(rax); Visit(expr);
// Complete the statement based on the location of the subexpression.
Location source = expr->location();
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
__ pop(rax);
} else {
ASSERT(source.is_constant());
ASSERT(expr->AsLiteral() != NULL);
__ Move(rax, expr->AsLiteral()->handle());
}
__ RecordJSReturn(); __ RecordJSReturn();
// Do not use the leave instruction here because it is too short to // Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger. // patch with the code required by the debugger.
@ -149,31 +160,45 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
} }
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
if (expr->location().is_temporary()) {
__ Push(expr->handle());
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) { void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
Expression* rhs = expr->value();
Visit(rhs);
Visit(expr->value()); // Left-hand side is always a (parameter or local) slot.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && var->slot() != NULL); ASSERT(var != NULL && var->slot() != NULL);
if (expr->location().is_temporary()) { // Complete the assignment based on the location of the right-hand-side
__ movq(rax, Operand(rsp, 0)); // value and the desired location of the assignment value.
__ movq(Operand(rbp, SlotOffset(var->slot())), rax); Location destination = expr->location();
Location source = rhs->location();
ASSERT(!destination.is_constant());
ASSERT(!source.is_nowhere());
if (source.is_temporary()) {
if (destination.is_temporary()) {
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side temporary
// on the stack.
__ movq(kScratchRegister, Operand(rsp, 0));
__ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
} else {
ASSERT(destination.is_nowhere());
// Case 'var = temp'. Discard right-hand-side temporary.
__ pop(Operand(rbp, SlotOffset(var->slot())));
}
} else { } else {
ASSERT(expr->location().is_nowhere()); ASSERT(source.is_constant());
__ pop(Operand(rbp, SlotOffset(var->slot()))); ASSERT(rhs->AsLiteral() != NULL);
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
// discarded result. Always perform the assignment.
__ Move(kScratchRegister, rhs->AsLiteral()->handle());
__ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
if (destination.is_temporary()) {
// Case 'temp <- (var = constant)'. Save result.
__ push(kScratchRegister);
}
} }
} }