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

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

Issue 6529022: ARM: Add inlined smi binary operations in full code generator (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 10 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 | « no previous file | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm/full-codegen-arm.cc
===================================================================
--- src/arm/full-codegen-arm.cc (revision 6796)
+++ src/arm/full-codegen-arm.cc (working copy)
@@ -341,7 +341,17 @@
FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
Token::Value op, Expression* left, Expression* right) {
ASSERT(ShouldInlineSmiCase(op));
- return kNoConstants;
+ 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)) {
+ // Don't inline shifts with constant left hand side.
+ return kLeftConstant;
+ } else {
+ return kNoConstants;
+ }
}
@@ -1598,14 +1608,308 @@
}
+void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
+ OverwriteMode mode,
+ bool left_is_constant_smi,
+ Smi* value) {
+ Label call_stub, done;
+ // Optimistically add smi value with unknown object. If result overflows or is
+ // not a smi then we had either a smi overflow or added a smi with a tagged
+ // pointer.
+ __ mov(r1, Operand(value));
+ __ add(r2, r0, r1, SetCC);
+ __ b(vs, &call_stub);
+ JumpPatchSite patch_site(masm_);
+ patch_site.EmitJumpIfNotSmi(r2, &call_stub);
+ __ mov(r0, r2);
+ __ b(&done);
+
+ // Call the shared stub.
+ __ bind(&call_stub);
+ if (!left_is_constant_smi) {
+ __ Swap(r0, r1, r2);
+ }
+ TypeRecordingBinaryOpStub stub(Token::ADD, mode);
+ EmitCallIC(stub.GetCode(), &patch_site);
+
+ __ bind(&done);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
+ OverwriteMode mode,
+ bool left_is_constant_smi,
+ Smi* value) {
+ Label call_stub, done;
+ // Optimistically subtract smi value and unknown object. If result overflows
+ // or is not a smi then we had either a smi overflow or subtraction between a
+ // smi and a tagged pointer.
+ __ mov(r1, Operand(value));
+ if (left_is_constant_smi) {
+ __ sub(r2, r1, r0, SetCC);
+ } else {
+ __ sub(r2, r0, r1, SetCC);
+ }
+ __ b(vs, &call_stub);
+ JumpPatchSite patch_site(masm_);
+ patch_site.EmitJumpIfNotSmi(r2, &call_stub);
+ __ mov(r0, r2);
+ __ b(&done);
+
+ // Call the shared stub.
+ __ bind(&call_stub);
+ if (!left_is_constant_smi) {
+ __ Swap(r0, r1, r2);
+ }
+ TypeRecordingBinaryOpStub stub(Token::SUB, mode);
+ EmitCallIC(stub.GetCode(), &patch_site);
+
+ __ bind(&done);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
+ Token::Value op,
+ OverwriteMode mode,
+ Smi* value) {
+ Label call_stub, smi_case, done;
+ int shift_value = value->value() & 0x1f;
+
+ JumpPatchSite patch_site(masm_);
+ patch_site.EmitJumpIfSmi(r0, &smi_case);
+
+ // Call stub.
+ __ bind(&call_stub);
+ __ mov(r1, r0);
+ __ mov(r0, Operand(value));
+ TypeRecordingBinaryOpStub stub(op, mode);
+ EmitCallIC(stub.GetCode(), &patch_site);
+ __ b(&done);
+
+ // Smi case.
+ __ bind(&smi_case);
+ switch (op) {
+ case Token::SHL:
+ if (shift_value != 0) {
+ __ mov(r1, r0);
+ if (shift_value > 1) {
+ __ mov(r1, Operand(r1, LSL, shift_value - 1));
+ }
+ // Convert int result to smi, checking that it is in int range.
+ __ SmiTag(r1, SetCC);
+ __ b(vs, &call_stub);
+ __ mov(r0, r1); // Put result back into r0.
+ }
+ break;
+ case Token::SAR:
+ if (shift_value != 0) {
+ __ mov(r0, Operand(r0, ASR, shift_value));
+ __ bic(r0, r0, Operand(kSmiTagMask));
+ }
+ break;
+ case Token::SHR:
+ // SHR must return a positive value. When shifting by 0 or 1 we need to
+ // check that smi tagging the result will not create a negative value.
+ if (shift_value < 2) {
+ __ mov(r2, Operand(shift_value));
+ __ SmiUntag(r1, r0);
+ if (shift_value != 0) {
+ __ mov(r1, Operand(r1, LSR, shift_value));
+ }
+ __ tst(r1, Operand(0xc0000000));
+ __ b(ne, &call_stub);
+ __ SmiTag(r0, r1); // result in r0.
+ } else {
+ __ SmiUntag(r0);
+ __ mov(r0, Operand(r0, LSR, shift_value));
+ __ SmiTag(r0);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
+ Token::Value op,
+ OverwriteMode mode,
+ Smi* value) {
+ Label smi_case, done;
+
+ JumpPatchSite patch_site(masm_);
+ patch_site.EmitJumpIfSmi(r0, &smi_case);
+
+ // The order of the arguments does not matter for bit-ops with a
+ // constant operand.
+ __ mov(r1, Operand(value));
+ TypeRecordingBinaryOpStub stub(op, mode);
+ EmitCallIC(stub.GetCode(), &patch_site);
+ __ jmp(&done);
+
+ // Smi case.
+ __ bind(&smi_case);
+ __ mov(r1, Operand(value));
+ switch (op) {
+ case Token::BIT_OR:
+ __ orr(r0, r0, Operand(r1));
+ break;
+ case Token::BIT_XOR:
+ __ eor(r0, r0, Operand(r1));
+ break;
+ case Token::BIT_AND:
+ __ and_(r0, r0, Operand(r1));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ context()->Plug(r0);
+}
+
+
+void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
+ Token::Value op,
+ 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, mode, value);
+ break;
+ case Token::SHL:
+ case Token::SAR:
+ case Token::SHR:
+ ASSERT(!left_is_constant_smi);
+ EmitConstantSmiShiftOp(expr, op, mode, value);
+ break;
+ case Token::ADD:
+ EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
+ break;
+ case Token::SUB:
+ EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
OverwriteMode mode,
- Expression* left,
- Expression* right,
+ Expression* left_expr,
+ Expression* right_expr,
ConstantOperand constant) {
- ASSERT(constant == kNoConstants); // Only handled case.
- EmitBinaryOp(op, mode);
+ if (constant == kRightConstant) {
+ Smi* value = Smi::cast(*right_expr->AsLiteral()->handle());
+ EmitConstantSmiBinaryOp(expr, op, mode, false, value);
+ return;
+ } else if (constant == kLeftConstant) {
+ Smi* value = Smi::cast(*left_expr->AsLiteral()->handle());
+ EmitConstantSmiBinaryOp(expr, op, mode, true, value);
+ return;
+ }
+
+ Label done, smi_case, stub_call;
+
+ Register scratch1 = r2;
+ Register scratch2 = r3;
+
+ // Get the arguments.
+ Register left = r1;
+ Register right = r0;
+ __ pop(left);
+
+ // Perform combined smi check on both operands.
+ __ orr(scratch1, left, Operand(right));
+ STATIC_ASSERT(kSmiTag == 0);
+ JumpPatchSite patch_site(masm_);
+ patch_site.EmitJumpIfSmi(scratch1, &smi_case);
+
+ __ bind(&stub_call);
+ TypeRecordingBinaryOpStub stub(op, mode);
+ EmitCallIC(stub.GetCode(), &patch_site);
+ __ jmp(&done);
+
+ __ bind(&smi_case);
+ // Smi case. This code works the same way as the smi-smi case in the type
+ // recording binary operation stub, see
+ // TypeRecordingBinaryOpStub::GenerateSmiSmiOperation for comments.
+ switch (op) {
+ case Token::SAR:
+ __ b(&stub_call);
+ __ GetLeastBitsFromSmi(scratch1, right, 5);
+ __ mov(right, Operand(left, ASR, scratch1));
+ __ bic(right, right, Operand(kSmiTagMask));
+ break;
+ case Token::SHL: {
+ __ b(&stub_call);
+ __ SmiUntag(scratch1, left);
+ __ GetLeastBitsFromSmi(scratch2, right, 5);
+ __ mov(scratch1, Operand(scratch1, LSL, scratch2));
+ __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
+ __ b(mi, &stub_call);
+ __ SmiTag(right, scratch1);
+ break;
+ }
+ case Token::SHR: {
+ __ b(&stub_call);
+ __ SmiUntag(scratch1, left);
+ __ GetLeastBitsFromSmi(scratch2, right, 5);
+ __ mov(scratch1, Operand(scratch1, LSR, scratch2));
+ __ tst(scratch1, Operand(0xc0000000));
+ __ b(ne, &stub_call);
+ __ SmiTag(right, scratch1);
+ break;
+ }
+ case Token::ADD:
+ __ add(scratch1, left, Operand(right), SetCC);
+ __ b(vs, &stub_call);
+ __ mov(right, scratch1);
+ break;
+ case Token::SUB:
+ __ sub(scratch1, left, Operand(right), SetCC);
+ __ b(vs, &stub_call);
+ __ mov(right, scratch1);
+ break;
+ case Token::MUL: {
+ __ SmiUntag(ip, right);
+ __ smull(scratch1, scratch2, left, ip);
+ __ mov(ip, Operand(scratch1, ASR, 31));
+ __ cmp(ip, Operand(scratch2));
+ __ b(ne, &stub_call);
+ __ tst(scratch1, Operand(scratch1));
+ __ mov(right, Operand(scratch1), LeaveCC, ne);
+ __ b(ne, &done);
+ __ add(scratch2, right, Operand(left), SetCC);
+ __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
+ __ b(mi, &stub_call);
+ break;
+ }
+ case Token::BIT_OR:
+ __ orr(right, left, Operand(right));
+ break;
+ case Token::BIT_AND:
+ __ and_(right, left, Operand(right));
+ break;
+ case Token::BIT_XOR:
+ __ eor(right, left, Operand(right));
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ __ bind(&done);
+ context()->Plug(r0);
}
@@ -3287,13 +3591,16 @@
// Inline smi case if we are in a loop.
Label stub_call, done;
+ JumpPatchSite patch_site(masm_);
+
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
__ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
__ b(vs, &stub_call);
// We could eliminate this smi check if we split the code at
// the first smi check before calling ToNumber.
- __ JumpIfSmi(r0, &done);
+ patch_site.EmitJumpIfSmi(r0, &done);
+
__ bind(&stub_call);
// Call stub. Undo operation first.
__ sub(r0, r0, Operand(Smi::FromInt(count_value)));
@@ -3303,8 +3610,8 @@
// Record position before stub call.
SetSourcePosition(expr->position());
- GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0);
- __ CallStub(&stub);
+ TypeRecordingBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
+ EmitCallIC(stub.GetCode(), &patch_site);
__ bind(&done);
// Store the value returned in r0.
« no previous file with comments | « no previous file | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698