Commit 6d5451d6 authored by kasperl@chromium.org's avatar kasperl@chromium.org

Add inlining of binary smi operations in the full codegens on IA32

and x64 (on IA32 we even fold constants into the instructions for
a more compact representation) and prepare the ARM full codegen for
the doing the same there.
Review URL: http://codereview.chromium.org/3195028

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5351 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7672338b
......@@ -246,6 +246,13 @@ void FullCodeGenerator::EmitReturnSequence() {
}
FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
Token::Value op, Expression* left, Expression* right) {
ASSERT(ShouldInlineSmiCase(op));
return kNoConstants;
}
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
......@@ -1144,10 +1151,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty();
if (prop != NULL) {
assign_type =
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
Property* property = expr->target()->AsProperty();
if (property != NULL) {
assign_type = (property->key()->IsPropertyName())
? NAMED_PROPERTY
: KEYED_PROPERTY;
}
// Evaluate LHS expression.
......@@ -1158,61 +1166,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY:
if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator);
VisitForValue(property->obj(), kAccumulator);
__ push(result_register());
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(property->obj(), kStack);
}
break;
case KEYED_PROPERTY:
// We need the key and receiver on both the stack and in r0 and r1.
if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator);
VisitForValue(property->obj(), kStack);
VisitForValue(property->key(), kAccumulator);
__ ldr(r1, MemOperand(sp, 0));
__ push(r0);
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
VisitForValue(property->obj(), kStack);
VisitForValue(property->key(), kStack);
}
break;
}
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
if (expr->is_compound()) {
Location saved_location = location_;
location_ = kStack;
location_ = kAccumulator;
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop);
__ push(result_register());
EmitNamedPropertyLoad(property);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(prop);
__ push(result_register());
EmitKeyedPropertyLoad(property);
break;
}
location_ = saved_location;
}
// Evaluate RHS expression.
Expression* rhs = expr->value();
VisitForValue(rhs, kAccumulator);
Token::Value op = expr->binary_op();
ConstantOperand constant = ShouldInlineSmiCase(op)
? GetConstantOperand(op, expr->target(), expr->value())
: kNoConstants;
ASSERT(constant == kRightConstant || constant == kNoConstants);
if (constant == kNoConstants) {
__ push(r0); // Left operand goes on the stack.
VisitForValue(expr->value(), kAccumulator);
}
// If we have a compound assignment: Apply operator.
if (expr->is_compound()) {
Location saved_location = location_;
location_ = kAccumulator;
OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
? OVERWRITE_RIGHT
: NO_OVERWRITE;
EmitBinaryOp(expr->binary_op(), Expression::kValue, mode);
SetSourcePosition(expr->position() + 1);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr,
op,
Expression::kValue,
mode,
expr->target(),
expr->value(),
constant);
} else {
EmitBinaryOp(op, Expression::kValue, mode);
}
location_ = saved_location;
} else {
VisitForValue(expr->value(), kAccumulator);
}
// Record source position before possible IC call.
......@@ -1253,6 +1270,18 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
ConstantOperand constant) {
ASSERT(constant == kNoConstants); // Only handled case.
EmitBinaryOp(op, context, mode);
}
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context,
OverwriteMode mode) {
......
......@@ -205,6 +205,9 @@ class Expression: public AstNode {
// False for operations that can return one of their operands.
virtual bool ResultOverwriteAllowed() { return false; }
// True iff the expression is a literal represented as a smi.
virtual bool IsSmiLiteral() { return false; }
// Static type information for this expression.
StaticType* type() { return &type_; }
......@@ -775,6 +778,7 @@ class Literal: public Expression {
virtual void Accept(AstVisitor* v);
virtual bool IsTrivial() { return true; }
virtual bool IsSmiLiteral() { return handle_->IsSmi(); }
// Type testing & conversion.
virtual Literal* AsLiteral() { return this; }
......
......@@ -516,18 +516,21 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
OverwriteMode overwrite_mode = NO_OVERWRITE;
if (expr->left()->ResultOverwriteAllowed()) {
overwrite_mode = OVERWRITE_LEFT;
} else if (expr->right()->ResultOverwriteAllowed()) {
overwrite_mode = OVERWRITE_RIGHT;
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
OverwriteMode mode = NO_OVERWRITE;
if (left->ResultOverwriteAllowed()) {
mode = OVERWRITE_LEFT;
} else if (right->ResultOverwriteAllowed()) {
mode = OVERWRITE_RIGHT;
}
switch (expr->op()) {
switch (op) {
case Token::COMMA:
VisitForEffect(expr->left());
Visit(expr->right());
VisitForEffect(left);
Visit(right);
break;
case Token::OR:
......@@ -545,12 +548,31 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
case Token::BIT_XOR:
case Token::SHL:
case Token::SHR:
case Token::SAR:
VisitForValue(expr->left(), kStack);
VisitForValue(expr->right(), kAccumulator);
case Token::SAR: {
// Figure out if either of the operands is a constant.
ConstantOperand constant = ShouldInlineSmiCase(op)
? GetConstantOperand(op, left, right)
: kNoConstants;
// Load only the operands that we need to materialize.
if (constant == kNoConstants) {
VisitForValue(left, kStack);
VisitForValue(right, kAccumulator);
} else if (constant == kRightConstant) {
VisitForValue(left, kAccumulator);
} else {
ASSERT(constant == kLeftConstant);
VisitForValue(right, kAccumulator);
}
SetSourcePosition(expr->position());
EmitBinaryOp(expr->op(), context_, overwrite_mode);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
} else {
EmitBinaryOp(op, context_, mode);
}
break;
}
default:
UNREACHABLE();
......
......@@ -237,6 +237,12 @@ class FullCodeGenerator: public AstVisitor {
kStack
};
enum ConstantOperand {
kNoConstants,
kLeftConstant,
kRightConstant
};
// Compute the frame pointer relative offset for a given local or
// parameter slot.
int SlotOffset(Slot* slot);
......@@ -245,6 +251,11 @@ class FullCodeGenerator: public AstVisitor {
// operation.
bool ShouldInlineSmiCase(Token::Value op);
// Compute which (if any) of the operands is a compile-time constant.
ConstantOperand GetConstantOperand(Token::Value op,
Expression* left,
Expression* right);
// Emit code to convert a pure value (in a register, slot, as a literal,
// or on top of the stack) into the result expected according to an
// expression context.
......@@ -361,7 +372,6 @@ class FullCodeGenerator: public AstVisitor {
void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode);
// Platform-specific code for inline runtime calls.
void EmitInlineRuntimeCall(CallRuntime* expr);
......@@ -393,6 +403,47 @@ class FullCodeGenerator: public AstVisitor {
Expression::Context context,
OverwriteMode mode);
// Helper functions for generating inlined smi code for certain
// binary operations.
void EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
ConstantOperand constant);
void EmitConstantSmiBinaryOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
void EmitConstantSmiBitOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
Smi* value);
void EmitConstantSmiShiftOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
Smi* value);
void EmitConstantSmiAdd(Expression* expr,
Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
void EmitConstantSmiSub(Expression* expr,
Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
// Assign to the given expression as if via '='. The right-hand-side value
// is expected in the accumulator.
void EmitAssignment(Expression* expr);
......
This diff is collapsed.
......@@ -248,6 +248,10 @@ class Token {
return op == INC || op == DEC;
}
static bool IsShiftOp(Value op) {
return (SHL <= op) && (op <= SHR);
}
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER).
......
......@@ -230,6 +230,13 @@ void FullCodeGenerator::EmitReturnSequence() {
}
FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
Token::Value op, Expression* left, Expression* right) {
ASSERT(ShouldInlineSmiCase(op));
return kNoConstants;
}
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
......@@ -1156,10 +1163,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty();
if (prop != NULL) {
assign_type =
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
Property* property = expr->target()->AsProperty();
if (property != NULL) {
assign_type = (property->key()->IsPropertyName())
? NAMED_PROPERTY
: KEYED_PROPERTY;
}
// Evaluate LHS expression.
......@@ -1170,60 +1178,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY:
if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator);
VisitForValue(property->obj(), kAccumulator);
__ push(result_register());
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(property->obj(), kStack);
}
break;
case KEYED_PROPERTY:
if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kAccumulator);
VisitForValue(property->obj(), kStack);
VisitForValue(property->key(), kAccumulator);
__ movq(rdx, Operand(rsp, 0));
__ push(rax);
} else {
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
VisitForValue(property->obj(), kStack);
VisitForValue(property->key(), kStack);
}
break;
}
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
if (expr->is_compound()) {
Location saved_location = location_;
location_ = kStack;
location_ = kAccumulator;
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop);
__ push(result_register());
EmitNamedPropertyLoad(property);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(prop);
__ push(result_register());
EmitKeyedPropertyLoad(property);
break;
}
location_ = saved_location;
}
// Evaluate RHS expression.
Expression* rhs = expr->value();
VisitForValue(rhs, kAccumulator);
Token::Value op = expr->binary_op();
ConstantOperand constant = ShouldInlineSmiCase(op)
? GetConstantOperand(op, expr->target(), expr->value())
: kNoConstants;
ASSERT(constant == kRightConstant || constant == kNoConstants);
if (constant == kNoConstants) {
__ push(rax); // Left operand goes on the stack.
VisitForValue(expr->value(), kAccumulator);
}
// If we have a compound assignment: Apply operator.
if (expr->is_compound()) {
Location saved_location = location_;
location_ = kAccumulator;
OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
? OVERWRITE_RIGHT
: NO_OVERWRITE;
EmitBinaryOp(expr->binary_op(), Expression::kValue, mode);
SetSourcePosition(expr->position() + 1);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr,
op,
Expression::kValue,
mode,
expr->target(),
expr->value(),
constant);
} else {
EmitBinaryOp(op, Expression::kValue, mode);
}
location_ = saved_location;
} else {
VisitForValue(expr->value(), kAccumulator);
}
// Record source position before possible IC call.
......@@ -1264,6 +1282,74 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
ConstantOperand constant) {
ASSERT(constant == kNoConstants); // Only handled case.
// Do combined smi check of the operands. Left operand is on the
// stack (popped into rdx). Right operand is in rax but moved into
// rcx to make the shifts easier.
Label done, stub_call, smi_case;
__ pop(rdx);
__ movq(rcx, rax);
Condition smi = __ CheckBothSmi(rdx, rax);
__ j(smi, &smi_case);
__ bind(&stub_call);
GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
if (stub.ArgsInRegistersSupported()) {
stub.GenerateCall(masm_, rdx, rcx);
} else {
__ push(rdx);
__ push(rcx);
__ CallStub(&stub);
}
__ jmp(&done);
__ bind(&smi_case);
switch (op) {
case Token::SAR:
__ SmiShiftArithmeticRight(rax, rdx, rcx);
break;
case Token::SHL:
__ SmiShiftLeft(rax, rdx, rcx);
break;
case Token::SHR:
__ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
break;
case Token::ADD:
__ SmiAdd(rax, rdx, rcx, &stub_call);
break;
case Token::SUB:
__ SmiSub(rax, rdx, rcx, &stub_call);
break;
case Token::MUL:
__ SmiMul(rax, rdx, rcx, &stub_call);
break;
case Token::BIT_OR:
__ SmiOr(rax, rdx, rcx);
break;
case Token::BIT_AND:
__ SmiAnd(rax, rdx, rcx);
break;
case Token::BIT_XOR:
__ SmiXor(rax, rdx, rcx);
break;
default:
UNREACHABLE();
break;
}
__ bind(&done);
Apply(context, rax);
}
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context,
OverwriteMode mode) {
......@@ -1971,8 +2057,8 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// ArgumentsAccessStub expects the key in edx and the formal
// parameter count in eax.
// ArgumentsAccessStub expects the key in rdx and the formal
// parameter count in rax.
VisitForValue(args->at(0), kAccumulator);
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(scope()->num_parameters()));
......@@ -2176,7 +2262,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
VisitForValue(args->at(0), kStack); // Load the object.
VisitForValue(args->at(1), kAccumulator); // Load the value.
__ pop(rbx); // rax = value. ebx = object.
__ pop(rbx); // rax = value. rbx = object.
Label done;
// If the object is a smi, return the value.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment