Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(482)

Unified Diff: src/ia32/full-codegen-ia32.cc

Issue 3195028: Add inlining of binary smi operations in the full codegens on IA32... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/full-codegen.cc ('k') | src/token.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ia32/full-codegen-ia32.cc
===================================================================
--- src/ia32/full-codegen-ia32.cc (revision 5348)
+++ src/ia32/full-codegen-ia32.cc (working copy)
@@ -217,12 +217,28 @@
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Assembler::kJSReturnSequenceLength,
- masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
+ masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
}
}
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+ Token::Value op, Expression* left, Expression* right) {
+ ASSERT(ShouldInlineSmiCase(op));
+ if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
+ // We never generate inlined constant smi operations for these.
+ return kNoConstants;
+ } else if (right->IsSmiLiteral()) {
+ return kRightConstant;
+ } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
+ return kLeftConstant;
+ } else {
+ return kNoConstants;
+ }
+}
+
+
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
@@ -1152,10 +1168,11 @@
// 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.
@@ -1166,60 +1183,70 @@
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);
__ mov(edx, Operand(esp, 0));
__ push(eax);
} 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(eax); // 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.
@@ -1260,6 +1287,313 @@
}
+void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
+ Expression::Context context,
+ OverwriteMode mode,
+ bool left_is_constant_smi,
+ Smi* value) {
+ Label call_stub, done;
+ __ add(Operand(eax), Immediate(value));
+ __ j(overflow, &call_stub);
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &done);
+
+ // Undo the optimistic add operation and call the shared stub.
+ __ bind(&call_stub);
+ __ sub(Operand(eax), Immediate(value));
+ Token::Value op = Token::ADD;
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ if (left_is_constant_smi) {
+ __ push(Immediate(value));
+ __ push(eax);
+ } else {
+ __ push(eax);
+ __ push(Immediate(value));
+ }
+ __ CallStub(&stub);
+ __ bind(&done);
+ Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
+ Expression::Context context,
+ OverwriteMode mode,
+ bool left_is_constant_smi,
+ Smi* value) {
+ Label call_stub, done;
+ if (left_is_constant_smi) {
+ __ mov(ecx, eax);
+ __ mov(eax, Immediate(value));
+ __ sub(Operand(eax), ecx);
+ } else {
+ __ sub(Operand(eax), Immediate(value));
+ }
+ __ j(overflow, &call_stub);
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &done);
+
+ __ bind(&call_stub);
+ if (left_is_constant_smi) {
+ __ push(Immediate(value));
+ __ push(ecx);
+ } else {
+ // Undo the optimistic sub operation.
+ __ add(Operand(eax), Immediate(value));
+
+ __ push(eax);
+ __ push(Immediate(value));
+ }
+
+ Token::Value op = Token::SUB;
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ __ CallStub(&stub);
+ __ bind(&done);
+ Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
+ Token::Value op,
+ Expression::Context context,
+ OverwriteMode mode,
+ Smi* value) {
+ Label call_stub, smi_case, done;
+ int shift_value = value->value() & 0x1f;
+
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &smi_case);
+
+ __ bind(&call_stub);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ __ push(eax);
+ __ push(Immediate(value));
+ __ CallStub(&stub);
+ __ jmp(&done);
+
+ __ bind(&smi_case);
+ switch (op) {
+ case Token::SHL:
+ if (shift_value != 0) {
+ __ mov(edx, eax);
+ if (shift_value > 1) {
+ __ shl(edx, shift_value - 1);
+ }
+ // Convert int result to smi, checking that it is in int range.
+ ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
+ __ add(edx, Operand(edx));
+ __ j(overflow, &call_stub);
+ __ mov(eax, edx); // Put result back into eax.
+ }
+ break;
+ case Token::SAR:
+ if (shift_value != 0) {
+ __ sar(eax, shift_value);
+ __ and_(eax, ~kSmiTagMask);
+ }
+ break;
+ case Token::SHR:
+ if (shift_value < 2) {
+ __ mov(edx, eax);
+ __ SmiUntag(edx);
+ __ shr(edx, shift_value);
+ __ test(edx, Immediate(0xc0000000));
+ __ j(not_zero, &call_stub);
+ __ SmiTag(edx);
+ __ mov(eax, edx); // Put result back into eax.
+ } else {
+ __ SmiUntag(eax);
+ __ shr(eax, shift_value);
+ __ SmiTag(eax);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
+ Token::Value op,
+ Expression::Context context,
+ OverwriteMode mode,
+ Smi* value) {
+ Label smi_case, done;
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &smi_case);
+
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ // The order of the arguments does not matter for bit-ops with a
+ // constant operand.
+ __ push(Immediate(value));
+ __ push(eax);
+ __ CallStub(&stub);
+ __ jmp(&done);
+
+ __ bind(&smi_case);
+ switch (op) {
+ case Token::BIT_OR:
+ __ or_(Operand(eax), Immediate(value));
+ break;
+ case Token::BIT_XOR:
+ __ xor_(Operand(eax), Immediate(value));
+ break;
+ case Token::BIT_AND:
+ __ and_(Operand(eax), Immediate(value));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ Apply(context, eax);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
+ Token::Value op,
+ Expression::Context context,
+ OverwriteMode mode,
+ bool left_is_constant_smi,
+ Smi* value) {
+ switch (op) {
+ case Token::BIT_OR:
+ case Token::BIT_XOR:
+ case Token::BIT_AND:
+ EmitConstantSmiBitOp(expr, op, context, mode, value);
+ break;
+ case Token::SHL:
+ case Token::SAR:
+ case Token::SHR:
+ ASSERT(!left_is_constant_smi);
+ EmitConstantSmiShiftOp(expr, op, context, mode, value);
+ break;
+ case Token::ADD:
+ EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value);
+ break;
+ case Token::SUB:
+ EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+ Token::Value op,
+ Expression::Context context,
+ OverwriteMode mode,
+ Expression* left,
+ Expression* right,
+ ConstantOperand constant) {
+ if (constant == kRightConstant) {
+ Smi* value = Smi::cast(*right->AsLiteral()->handle());
+ EmitConstantSmiBinaryOp(expr, op, context, mode, false, value);
+ return;
+ } else if (constant == kLeftConstant) {
+ Smi* value = Smi::cast(*left->AsLiteral()->handle());
+ EmitConstantSmiBinaryOp(expr, op, context, mode, true, value);
+ return;
+ }
+
+ // Do combined smi check of the operands. Left operand is on the
+ // stack. Right operand is in eax.
+ Label done, stub_call, smi_case;
+ __ pop(edx);
+ __ mov(ecx, eax);
+ __ or_(eax, Operand(edx));
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &smi_case);
+
+ __ bind(&stub_call);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ if (stub.ArgsInRegistersSupported()) {
+ stub.GenerateCall(masm_, edx, ecx);
+ } else {
+ __ push(edx);
+ __ push(ecx);
+ __ CallStub(&stub);
+ }
+ __ jmp(&done);
+
+ __ bind(&smi_case);
+ __ mov(eax, edx); // Copy left operand in case of a stub call.
+
+ switch (op) {
+ case Token::SAR:
+ __ SmiUntag(eax);
+ __ SmiUntag(ecx);
+ __ sar_cl(eax); // No checks of result necessary
+ __ SmiTag(eax);
+ break;
+ case Token::SHL: {
+ Label result_ok;
+ __ SmiUntag(eax);
+ __ SmiUntag(ecx);
+ __ shl_cl(eax);
+ // Check that the *signed* result fits in a smi.
+ __ cmp(eax, 0xc0000000);
+ __ j(positive, &result_ok);
+ __ SmiTag(ecx);
+ __ jmp(&stub_call);
+ __ bind(&result_ok);
+ __ SmiTag(eax);
+ break;
+ }
+ case Token::SHR: {
+ Label result_ok;
+ __ SmiUntag(eax);
+ __ SmiUntag(ecx);
+ __ shr_cl(eax);
+ __ test(eax, Immediate(0xc0000000));
+ __ j(zero, &result_ok);
+ __ SmiTag(ecx);
+ __ jmp(&stub_call);
+ __ bind(&result_ok);
+ __ SmiTag(eax);
+ break;
+ }
+ case Token::ADD:
+ __ add(eax, Operand(ecx));
+ __ j(overflow, &stub_call);
+ break;
+ case Token::SUB:
+ __ sub(eax, Operand(ecx));
+ __ j(overflow, &stub_call);
+ break;
+ case Token::MUL: {
+ __ SmiUntag(eax);
+ __ imul(eax, Operand(ecx));
+ __ j(overflow, &stub_call);
+ __ test(eax, Operand(eax));
+ __ j(not_zero, &done, taken);
+ __ mov(ebx, edx);
+ __ or_(ebx, Operand(ecx));
+ __ j(negative, &stub_call);
+ break;
+ }
+ case Token::BIT_OR:
+ __ or_(eax, Operand(ecx));
+ break;
+ case Token::BIT_AND:
+ __ and_(eax, Operand(ecx));
+ break;
+ case Token::BIT_XOR:
+ __ xor_(eax, Operand(ecx));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ Apply(context, eax);
+}
+
+
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context,
OverwriteMode mode) {
« no previous file with comments | « src/full-codegen.cc ('k') | src/token.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698