Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/codegen-ia32.cc (revision 2093) |
| +++ src/ia32/codegen-ia32.cc (working copy) |
| @@ -779,8 +779,7 @@ |
| // Call the specialized stub for a binary operation. |
| class DeferredInlineBinaryOperation: public DeferredCode { |
| public: |
| - DeferredInlineBinaryOperation(Token::Value op, |
| - OverwriteMode mode) |
| + DeferredInlineBinaryOperation(Token::Value op, OverwriteMode mode) |
| : op_(op), mode_(mode) { |
| set_comment("[ DeferredInlineBinaryOperation"); |
| } |
| @@ -1001,8 +1000,8 @@ |
| Result* left, |
| Result* right, |
| OverwriteMode overwrite_mode) { |
| - // Implements a binary operation using a deferred code object and |
| - // some inline code to operate on smis quickly. |
| + // Implements a binary operation using a deferred code object and some |
| + // inline code to operate on smis quickly. |
| DeferredInlineBinaryOperation* deferred = |
| new DeferredInlineBinaryOperation(op, overwrite_mode); |
| @@ -1148,12 +1147,98 @@ |
| return; |
| } |
| + // Special handling of shift operations because they use fixed |
| + // registers. |
| + if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { |
| + // Move left out of ecx if necessary. |
| + if (left->is_register() && left->reg().is(ecx)) { |
| + *left = allocator_->Allocate(); |
| + ASSERT(left->is_valid()); |
| + __ mov(left->reg(), ecx); |
| + } |
| + right->ToRegister(ecx); |
| + left->ToRegister(); |
| + ASSERT(left->is_register() && !left->reg().is(ecx)); |
| + ASSERT(right->is_register() && right->reg().is(ecx)); |
| + |
| + // We will modify right, it must be spilled. |
| + frame_->Spill(ecx); |
| + |
| + // Use a fresh answer register to avoid spilling the left operand. |
| + Result answer = allocator_->Allocate(); |
| + ASSERT(answer.is_valid()); |
| + // Check that both operands are smis using the answer register as a |
| + // temporary. |
| + __ mov(answer.reg(), left->reg()); |
| + __ or_(answer.reg(), Operand(ecx)); |
| + __ test(answer.reg(), Immediate(kSmiTagMask)); |
| + deferred->enter()->Branch(not_zero, left, right); |
| + |
| + // Untag both operands. |
| + __ mov(answer.reg(), left->reg()); |
| + __ sar(answer.reg(), kSmiTagSize); |
| + __ sar(ecx, kSmiTagSize); |
| + // Perform the operation. |
| + switch (op) { |
| + case Token::SAR: |
| + __ sar(answer.reg()); |
| + // No checks of result necessary |
| + break; |
| + case Token::SHR: { |
| + JumpTarget result_ok; |
| + __ shr(answer.reg()); |
| + // 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 |
|
William Hesse
2009/06/03 12:12:04
// Smi tagging. These two cases can..
|
| + // by 0 or 1 when handed a valid smi. |
| + // If the answer cannot be represented by a smi, restore |
| + // the left and right arguments, and jump to slow case. |
| + // The low bit of the left argument may be lost, but only |
| + // in a case where it is dropped anyway. |
| + __ test(answer.reg(), Immediate(0xc0000000)); |
| + result_ok.Branch(zero, &answer); |
| + ASSERT(kSmiTag == 0); |
| + __ shl(ecx, kSmiTagSize); |
| + answer.Unuse(); |
| + deferred->enter()->Jump(left, right); |
| + result_ok.Bind(&answer); |
| + break; |
| + } |
| + case Token::SHL: { |
| + JumpTarget result_ok; |
| + __ shl(answer.reg()); |
| + // Check that the *signed* result fits in a smi. |
| + __ cmp(answer.reg(), 0xc0000000); |
| + result_ok.Branch(positive, &answer); |
| + ASSERT(kSmiTag == 0); |
| + __ shl(ecx, kSmiTagSize); |
| + answer.Unuse(); |
| + deferred->enter()->Jump(left, right); |
| + result_ok.Bind(&answer); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| + left->Unuse(); |
| + right->Unuse(); |
| + // Smi-tag the result in answer. |
| + ASSERT(kSmiTagSize == 1); // Adjust code if not the case. |
| + __ lea(answer.reg(), |
| + Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); |
| + deferred->BindExit(&answer); |
| + frame_->Push(&answer); |
| + return; |
| + } |
| + |
| // Handle the other binary operations. |
| left->ToRegister(); |
| right->ToRegister(); |
| // A newly allocated register answer is used to hold the answer. The |
| - // registers containing left and right are not modified in most cases, |
| - // so they usually don't need to be spilled in the fast case. |
| + // registers containing left and right are not modified so they don't |
| + // need to be spilled in the fast case. |
| Result answer = allocator_->Allocate(); |
| ASSERT(answer.is_valid()); |
| @@ -1229,109 +1314,6 @@ |
| __ xor_(answer.reg(), Operand(right->reg())); |
| break; |
| - case Token::SHL: |
| - case Token::SHR: |
| - case Token::SAR: |
| - deferred->enter()->Branch(not_zero, left, right, not_taken); |
| - __ mov(answer.reg(), left->reg()); |
| - // Move right into ecx. |
| - // Left is in two registers already, so even if left or answer is ecx, |
| - // we can move right to it, and use the other one. |
| - // Right operand must be in register cl because x86 likes it that way. |
| - if (right->reg().is(ecx)) { |
| - // Right is already in the right place. Left may be in the |
| - // same register, which causes problems. Always use answer |
| - // instead of left, even if left is not ecx, since this avoids |
| - // spilling left. |
| - *left = answer; |
| - } else if (left->reg().is(ecx)) { |
| - frame_->Spill(left->reg()); |
| - __ mov(left->reg(), right->reg()); |
| - *right = *left; |
| - *left = answer; // Use copy of left in answer as left. |
| - } else if (answer.reg().is(ecx)) { |
| - __ mov(answer.reg(), right->reg()); |
| - *right = answer; |
| - } else { |
| - Result reg_ecx = allocator_->Allocate(ecx); |
| - ASSERT(reg_ecx.is_valid()); |
| - __ mov(ecx, right->reg()); |
| - *right = reg_ecx; |
| - // Answer and left both contain the left operand. Use answer, so |
| - // left is not spilled. |
| - *left = answer; |
| - } |
| - ASSERT(left->reg().is_valid()); |
| - ASSERT(!left->reg().is(ecx)); |
| - ASSERT(right->reg().is(ecx)); |
| - answer.Unuse(); // Answer may now be being used for left or right. |
| - // We will modify left and right, which we do not do in any other |
| - // binary operation. The exits to slow code need to restore the |
| - // original values of left and right, or at least values that give |
| - // the same answer. |
| - |
| - // We are modifying left and right. They must be spilled! |
| - frame_->Spill(left->reg()); |
| - frame_->Spill(right->reg()); |
| - |
| - // Remove tags from operands (but keep sign). |
| - __ sar(left->reg(), kSmiTagSize); |
| - __ sar(ecx, kSmiTagSize); |
| - // Perform the operation. |
| - switch (op) { |
| - case Token::SAR: |
| - __ sar(left->reg()); |
| - // No checks of result necessary |
| - break; |
| - case Token::SHR: { |
| - __ shr(left->reg()); |
| - // 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. |
| - // If the answer cannot be represented by a SMI, restore |
| - // the left and right arguments, and jump to slow case. |
| - // The low bit of the left argument may be lost, but only |
| - // in a case where it is dropped anyway. |
| - JumpTarget result_ok; |
| - __ test(left->reg(), Immediate(0xc0000000)); |
| - result_ok.Branch(zero, left, taken); |
| - __ shl(left->reg()); |
| - ASSERT(kSmiTag == 0); |
| - __ shl(left->reg(), kSmiTagSize); |
| - __ shl(right->reg(), kSmiTagSize); |
| - deferred->enter()->Jump(left, right); |
| - result_ok.Bind(left); |
| - break; |
| - } |
| - case Token::SHL: { |
| - __ shl(left->reg()); |
| - // Check that the *signed* result fits in a smi. |
| - JumpTarget result_ok; |
| - __ cmp(left->reg(), 0xc0000000); |
| - result_ok.Branch(positive, left, taken); |
| - |
| - __ shr(left->reg()); |
| - ASSERT(kSmiTag == 0); |
| - __ shl(left->reg(), kSmiTagSize); |
| - __ shl(right->reg(), kSmiTagSize); |
| - deferred->enter()->Jump(left, right); |
| - result_ok.Bind(left); |
| - break; |
| - } |
| - default: |
| - UNREACHABLE(); |
| - } |
| - // Smi-tag the result, in left, and make answer an alias for left-> |
| - answer = *left; |
| - answer.ToRegister(); |
| - ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| - __ lea(answer.reg(), |
| - Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); |
| - break; |
| - |
| default: |
| UNREACHABLE(); |
| break; |