| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 4966)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -869,7 +869,6 @@
|
| } else {
|
| // Fall through!
|
| }
|
| - case Token::MUL:
|
| case Token::DIV:
|
| case Token::MOD:
|
| case Token::SHL:
|
| @@ -884,6 +883,39 @@
|
| break;
|
| }
|
|
|
| + case Token::MUL: {
|
| + Register rhs = frame_->PopToRegister();
|
| + Register lhs = frame_->PopToRegister(rhs);
|
| + GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs);
|
| + if (inline_smi) {
|
| + JumpTarget slow, done;
|
| + Register smi_test_reg = VirtualFrame::scratch0();
|
| + Register low = VirtualFrame::scratch1();
|
| + Register high = smi_test_reg;
|
| + // We need to know whether we are dealing with two positive Smis. Set
|
| + // up smi_test_reg to tell us that.
|
| + __ orr(smi_test_reg, lhs, Operand(rhs));
|
| + __ tst(smi_test_reg, Operand(0x80000000 | kSmiTagMask));
|
| + smi_test_reg = no_reg;
|
| + slow.Branch(ne);
|
| + // Do multiplication
|
| + __ smull(low, high, lhs, rhs);
|
| + __ cmp(high, Operand(0));
|
| + // Remove double tag from answer.
|
| + __ mov(r0, Operand(low, LSR, kSmiTagSize), LeaveCC, eq);
|
| + done.Branch(eq);
|
| + slow.Bind();
|
| + frame_->SpillAll();
|
| + frame_->CallStub(&stub, 0);
|
| + done.Bind();
|
| + } else {
|
| + frame_->SpillAll();
|
| + frame_->CallStub(&stub, 0);
|
| + }
|
| + frame_->EmitPush(r0);
|
| + break;
|
| + }
|
| +
|
| case Token::COMMA: {
|
| Register scratch = frame_->PopToRegister();
|
| // Simply discard left value.
|
| @@ -1036,58 +1068,60 @@
|
|
|
| bool both_sides_are_smi = frame_->KnownSmiAt(0);
|
|
|
| - bool something_to_inline;
|
| + bool inline_op_with_constant_smi;
|
| + GenerateInlineSmi inline_generic_smi_code = GENERATE_INLINE_SMI;
|
| switch (op) {
|
| case Token::ADD:
|
| case Token::SUB:
|
| case Token::BIT_AND:
|
| case Token::BIT_OR:
|
| case Token::BIT_XOR: {
|
| - something_to_inline = true;
|
| + inline_op_with_constant_smi = true;
|
| break;
|
| }
|
| case Token::SHL: {
|
| - something_to_inline = (both_sides_are_smi || !reversed);
|
| + inline_op_with_constant_smi = (both_sides_are_smi || !reversed);
|
| break;
|
| }
|
| case Token::SHR:
|
| case Token::SAR: {
|
| if (reversed) {
|
| - something_to_inline = false;
|
| + inline_op_with_constant_smi = false;
|
| } else {
|
| - something_to_inline = true;
|
| + inline_op_with_constant_smi = true;
|
| }
|
| break;
|
| }
|
| + case Token::MUL: {
|
| + // Multiplying by negative small constants is too annoying because of the
|
| + // -0 issues.
|
| + inline_op_with_constant_smi = (int_value >= 2);
|
| + inline_generic_smi_code = inline_op_with_constant_smi ?
|
| + GENERATE_INLINE_SMI :
|
| + DONT_GENERATE_INLINE_SMI;
|
| + break;
|
| + }
|
| case Token::MOD: {
|
| if (reversed || int_value < 2 || !IsPowerOf2(int_value)) {
|
| - something_to_inline = false;
|
| + inline_op_with_constant_smi = false;
|
| } else {
|
| - something_to_inline = true;
|
| + inline_op_with_constant_smi = true;
|
| }
|
| break;
|
| }
|
| - case Token::MUL: {
|
| - if (!IsEasyToMultiplyBy(int_value)) {
|
| - something_to_inline = false;
|
| - } else {
|
| - something_to_inline = true;
|
| - }
|
| - break;
|
| - }
|
| default: {
|
| - something_to_inline = false;
|
| + inline_op_with_constant_smi = false;
|
| break;
|
| }
|
| }
|
|
|
| - if (!something_to_inline) {
|
| + if (!inline_op_with_constant_smi) {
|
| if (!reversed) {
|
| // Push the rhs onto the virtual frame by putting it in a TOS register.
|
| Register rhs = frame_->GetTOSRegister();
|
| __ mov(rhs, Operand(value));
|
| frame_->EmitPush(rhs, TypeInfo::Smi());
|
| - GenericBinaryOperation(op, mode, GENERATE_INLINE_SMI, int_value);
|
| + GenericBinaryOperation(op, mode, inline_generic_smi_code, int_value);
|
| } else {
|
| // Pop the rhs, then push lhs and rhs in the right order. Only performs
|
| // at most one pop, the rest takes place in TOS registers.
|
| @@ -1097,7 +1131,7 @@
|
| frame_->EmitPush(lhs, TypeInfo::Smi());
|
| TypeInfo t = both_sides_are_smi ? TypeInfo::Smi() : TypeInfo::Unknown();
|
| frame_->EmitPush(rhs, t);
|
| - GenericBinaryOperation(op, mode, GENERATE_INLINE_SMI, kUnknownIntValue);
|
| + GenericBinaryOperation(op, mode, inline_generic_smi_code, kUnknownIntValue);
|
| }
|
| return;
|
| }
|
| @@ -1303,7 +1337,8 @@
|
| }
|
|
|
| case Token::MUL: {
|
| - ASSERT(IsEasyToMultiplyBy(int_value));
|
| + ASSERT(int_value > 0);
|
| +
|
| DeferredCode* deferred =
|
| new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos);
|
| unsigned max_smi_that_wont_overflow = Smi::kMaxValue / int_value;
|
| @@ -1312,14 +1347,25 @@
|
| while ((mask & max_smi_that_wont_overflow) == 0) {
|
| mask |= mask >> 1;
|
| }
|
| - mask |= kSmiTagMask;
|
| + if (!both_sides_are_smi) mask |= kSmiTagMask;
|
| // This does a single mask that checks for a too high value in a
|
| // conservative way and for a non-Smi. It also filters out negative
|
| // numbers, unfortunately, but since this code is inline we prefer
|
| // brevity to comprehensiveness.
|
| __ tst(tos, Operand(mask));
|
| deferred->Branch(ne);
|
| - MultiplyByKnownInt(masm_, tos, tos, int_value);
|
| +
|
| + if (IsEasyToMultiplyBy(int_value)) {
|
| + MultiplyByKnownInt(masm_, tos, tos, int_value);
|
| + } else {
|
| + Register high = VirtualFrame::scratch0();
|
| + Register low = VirtualFrame::scratch1();
|
| + __ mov(ip, Operand(int_value));
|
| + // Multiplying a tagged with an untagged value gives a tagged
|
| + // result.
|
| + __ smull(tos, high, tos, ip);
|
| + // Remove double tag from answer and make its sign bit 0.
|
| + }
|
| deferred->BindExit();
|
| frame_->EmitPush(tos);
|
| break;
|
|
|