| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 3433)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -1616,30 +1616,33 @@
|
| // In the slow case, this masking is done inside the runtime call.
|
| int shift_value = int_value & 0x1f;
|
| operand->ToRegister();
|
| - Result answer = allocator()->Allocate();
|
| - ASSERT(answer.is_valid());
|
| + frame_->Spill(operand->reg());
|
| DeferredInlineSmiOperation* deferred =
|
| new DeferredInlineSmiOperation(op,
|
| - answer.reg(),
|
| operand->reg(),
|
| + operand->reg(),
|
| smi_value,
|
| overwrite_mode);
|
| - __ test(operand->reg(), Immediate(kSmiTagMask));
|
| - deferred->Branch(not_zero);
|
| - __ mov(answer.reg(), operand->reg());
|
| - __ sar(answer.reg(), kSmiTagSize);
|
| - __ shr(answer.reg(), shift_value);
|
| - // A negative Smi shifted right two is in the positive Smi range.
|
| if (shift_value < 2) {
|
| - __ test(answer.reg(), Immediate(0xc0000000));
|
| + // A negative Smi shifted by 0 or 1 is too big to fit in the positive
|
| + // Smi range. Fold the test into the Smi tag test.
|
| + __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000));
|
| deferred->Branch(not_zero);
|
| + if (shift_value == 1) {
|
| + __ shr(operand->reg(), 1);
|
| + __ and_(operand->reg(), ~kSmiTagMask);
|
| + }
|
| + } else {
|
| + __ test(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + __ sar(operand->reg(), 1);
|
| + __ shr(operand->reg(), shift_value - 1);
|
| + __ and_(operand->reg(), ~kSmiTagMask);
|
| }
|
| - operand->Unuse();
|
| - ASSERT(kSmiTagSize == times_2); // Adjust the code if not true.
|
| - __ lea(answer.reg(),
|
| - Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
|
| + ASSERT(kSmiTag == 0); // adjust code if not the case
|
| + ASSERT(kSmiTagSize == 1); // Adjust the code if not true.
|
| deferred->BindExit();
|
| - frame_->Push(&answer);
|
| + frame_->Push(operand);
|
| }
|
| break;
|
|
|
| @@ -1733,6 +1736,74 @@
|
| break;
|
| }
|
|
|
| + case Token::MUL: {
|
| + operand->ToRegister();
|
| + frame_->Spill(operand->reg());
|
| + DeferredCode* deferred = NULL;
|
| + Result* answer = NULL;
|
| + Result answer_reg;
|
| + if (int_value == 0 || int_value == 1 || int_value == -1) {
|
| + // Re-use operand register.
|
| + answer = operand;
|
| + } else {
|
| + // Need a fresh register.
|
| + answer_reg = allocator()->Allocate();
|
| + answer = &answer_reg;
|
| + ASSERT(answer->is_valid());
|
| + }
|
| + if (reversed) {
|
| + deferred = new DeferredInlineSmiOperationReversed(op,
|
| + answer->reg(),
|
| + smi_value,
|
| + operand->reg(),
|
| + overwrite_mode);
|
| + } else {
|
| + deferred = new DeferredInlineSmiOperation(op,
|
| + answer->reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + }
|
| + __ test(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
|
| +
|
| + if (int_value == 1) {
|
| + // Already have correct value in 'answer'.
|
| + ASSERT(answer == operand);
|
| + } else if (int_value == 0) {
|
| + // The result is positive zero or negative zero depending on the sign of
|
| + // the operand.
|
| + __ test(operand->reg(), Operand(operand->reg()));
|
| + deferred->Branch(negative);
|
| + __ Set(answer->reg(), Immediate(0));
|
| + } else if (int_value == -1) {
|
| + ASSERT(answer == operand);
|
| + __ neg(answer->reg());
|
| + // The only value that can overflow is MIN_SMI, for which negation
|
| + // yields the same bit pattern. Thus the operand register, although
|
| + // negated, holds the original value, ready for the deferred code.
|
| + deferred->Branch(overflow);
|
| + // If the result is zero, it should be negative zero. Again, the
|
| + // operand register, although negated, contains the original value!
|
| + deferred->Branch(zero);
|
| + } else {
|
| + __ imul(answer->reg(), operand->reg(), int_value);
|
| + deferred->Branch(overflow);
|
| +
|
| + if (int_value < 0) { // Negative zero test.
|
| + __ test(answer->reg(), Operand(answer->reg()));
|
| + deferred->Branch(zero);
|
| + }
|
| + }
|
| + deferred->BindExit();
|
| + if (operand != answer) {
|
| + operand->Unuse();
|
| + }
|
| + frame_->Push(answer);
|
| + break;
|
| + }
|
| +
|
| // Generate inline code for mod of powers of 2 and negative powers of 2.
|
| case Token::MOD:
|
| if (!reversed &&
|
| @@ -7295,29 +7366,23 @@
|
| void UnarySubStub::Generate(MacroAssembler* masm) {
|
| Label undo;
|
| Label slow;
|
| - Label done;
|
| Label try_float;
|
|
|
| // Check whether the value is a smi.
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(not_zero, &try_float, not_taken);
|
|
|
| - // Enter runtime system if the value of the expression is zero
|
| - // to make sure that we switch between 0 and -0.
|
| - __ test(eax, Operand(eax));
|
| + // Optimistically negate. There are two special case. (1) The
|
| + // smallest Smi value will overflow. (2) 0 should yield -0. Both of
|
| + // these cases enter the runtime system. No restoration of the
|
| + // operand's original value is necessary, as the two values are (the
|
| + // only) values such that x == -x in two's complement arithmetic.
|
| + __ neg(eax);
|
| + __ j(overflow, &slow, not_taken);
|
| __ j(zero, &slow, not_taken);
|
|
|
| - // The value of the expression is a smi that is not zero. Try
|
| - // optimistic subtraction '0 - value'.
|
| - __ mov(edx, Operand(eax));
|
| - __ Set(eax, Immediate(0));
|
| - __ sub(eax, Operand(edx));
|
| - __ j(overflow, &undo, not_taken);
|
| + __ StubReturn(1);
|
|
|
| - // If result is a smi we are done.
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, &done, taken);
|
| -
|
| // Restore eax and enter runtime system.
|
| __ bind(&undo);
|
| __ mov(eax, Operand(edx));
|
| @@ -7350,8 +7415,6 @@
|
| __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
|
| }
|
|
|
| - __ bind(&done);
|
| -
|
| __ StubReturn(1);
|
| }
|
|
|
|
|