Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 4633) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -1146,44 +1146,66 @@ |
int shift_value = int_value & 0x1f; // least significant 5 bits |
DeferredCode* deferred = |
new DeferredInlineSmiOperation(op, shift_value, false, mode, tos); |
- __ tst(tos, Operand(kSmiTagMask)); |
- deferred->Branch(ne); |
- __ mov(scratch, Operand(tos, ASR, kSmiTagSize)); // remove tags |
+ uint32_t problematic_mask = kSmiTagMask; |
+ // For unsigned shift by zero all negative smis are problematic. |
+ if (shift_value == 0 && op == Token::SHR) problematic_mask |= 0x80000000; |
+ __ tst(tos, Operand(problematic_mask)); |
+ deferred->Branch(ne); // Go slow for problematic input. |
switch (op) { |
case Token::SHL: { |
if (shift_value != 0) { |
- __ mov(scratch, Operand(scratch, LSL, shift_value)); |
+ int adjusted_shift = shift_value - kSmiTagSize; |
+ ASSERT(adjusted_shift >= 0); |
+ if (adjusted_shift != 0) { |
+ __ mov(scratch, Operand(tos, LSL, adjusted_shift)); |
+ // Check that the *signed* result fits in a smi. |
+ __ add(scratch2, scratch, Operand(0x40000000), SetCC); |
+ deferred->Branch(mi); |
+ __ mov(tos, Operand(scratch, LSL, kSmiTagSize)); |
+ } else { |
+ // Check that the *signed* result fits in a smi. |
+ __ add(scratch2, tos, Operand(0x40000000), SetCC); |
+ deferred->Branch(mi); |
+ __ mov(tos, Operand(tos, LSL, kSmiTagSize)); |
+ } |
} |
- // check that the *signed* result fits in a smi |
- __ add(scratch2, scratch, Operand(0x40000000), SetCC); |
- deferred->Branch(mi); |
break; |
} |
case Token::SHR: { |
- // LSR by immediate 0 means shifting 32 bits. |
if (shift_value != 0) { |
+ __ mov(scratch, Operand(tos, ASR, kSmiTagSize)); // Remove tag. |
+ // LSR by immediate 0 means shifting 32 bits. |
__ mov(scratch, Operand(scratch, LSR, shift_value)); |
+ if (shift_value < 2) { |
Søren Thygesen Gjesse
2010/05/11 07:57:11
With the test above this is shift_value == 1.
|
+ // check that the *unsigned* result fits in a smi |
+ // neither of the two high-order bits can be set: |
+ // - 0x80000000: high bit would be lost when smi tagging |
+ // - 0x40000000: this number would convert to negative when |
+ // smi tagging these two cases can only happen with shifts |
+ // by 0 or 1 when handed a valid smi |
+ __ tst(scratch, Operand(0xc0000000)); |
+ deferred->Branch(ne); |
+ } |
+ __ mov(tos, Operand(scratch, LSL, kSmiTagSize)); |
} |
- // check that the *unsigned* result fits in a smi |
- // neither of the two high-order bits can be set: |
- // - 0x80000000: high bit would be lost when smi tagging |
- // - 0x40000000: this number would convert to negative when |
- // smi tagging these two cases can only happen with shifts |
- // by 0 or 1 when handed a valid smi |
- __ tst(scratch, Operand(0xc0000000)); |
- deferred->Branch(ne); |
break; |
} |
case Token::SAR: { |
+ // In the ARM instructions set, ASR by immediate 0 means shifting 32 |
+ // bits. |
if (shift_value != 0) { |
- // ASR by immediate 0 means shifting 32 bits. |
- __ mov(scratch, Operand(scratch, ASR, shift_value)); |
+ // Do the shift and the tag removal in one operation. If the shift |
+ // is 31 bits (the highest possible value) then we emit the |
+ // instruction as a shift by 0 which means shift arithmetically by |
+ // 32. |
+ __ mov(tos, Operand(tos, ASR, (kSmiTagSize + shift_value) & 0x1f)); |
+ // Put tag back. |
+ __ mov(tos, Operand(tos, LSL, kSmiTagSize)); |
} |
break; |
} |
default: UNREACHABLE(); |
} |
- __ mov(tos, Operand(scratch, LSL, kSmiTagSize)); |
deferred->BindExit(); |
frame_->EmitPush(tos); |
break; |