| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 2658)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -5192,8 +5192,159 @@
|
| }
|
| break;
|
| }
|
| - // TODO(X64): Move other implementations from ia32 to here.
|
|
|
| + case Token::SAR:
|
| + if (reversed) {
|
| + Result constant_operand(value);
|
| + LikelySmiBinaryOperation(op, &constant_operand, operand,
|
| + overwrite_mode);
|
| + } else {
|
| + // Only the least significant 5 bits of the shift value are used.
|
| + // In the slow case, this masking is done inside the runtime call.
|
| + int shift_value = int_value & 0x1f;
|
| + operand->ToRegister();
|
| + frame_->Spill(operand->reg());
|
| + DeferredInlineSmiOperation* deferred =
|
| + new DeferredInlineSmiOperation(op,
|
| + operand->reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + __ testl(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + if (shift_value > 0) {
|
| + __ sarl(operand->reg(), Immediate(shift_value));
|
| + __ and_(operand->reg(), Immediate(~kSmiTagMask));
|
| + }
|
| + deferred->BindExit();
|
| + frame_->Push(operand);
|
| + }
|
| + break;
|
| +
|
| + case Token::SHR:
|
| + if (reversed) {
|
| + Result constant_operand(value);
|
| + LikelySmiBinaryOperation(op, &constant_operand, operand,
|
| + overwrite_mode);
|
| + } else {
|
| + // Only the least significant 5 bits of the shift value are used.
|
| + // 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());
|
| + DeferredInlineSmiOperation* deferred =
|
| + new DeferredInlineSmiOperation(op,
|
| + answer.reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + __ testl(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + __ movl(answer.reg(), operand->reg());
|
| + __ sarl(answer.reg(), Immediate(kSmiTagSize));
|
| + __ shrl(answer.reg(), Immediate(shift_value));
|
| + // A negative Smi shifted right two is in the positive Smi range.
|
| + if (shift_value < 2) {
|
| + __ testl(answer.reg(), Immediate(0xc0000000));
|
| + deferred->Branch(not_zero);
|
| + }
|
| + operand->Unuse();
|
| + ASSERT(kSmiTagSize == times_2); // Adjust the code if not true.
|
| + __ lea(answer.reg(),
|
| + Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
|
| + deferred->BindExit();
|
| + frame_->Push(&answer);
|
| + }
|
| + break;
|
| +
|
| + case Token::SHL:
|
| + if (reversed) {
|
| + Result constant_operand(value);
|
| + LikelySmiBinaryOperation(op, &constant_operand, operand,
|
| + overwrite_mode);
|
| + } else {
|
| + // Only the least significant 5 bits of the shift value are used.
|
| + // In the slow case, this masking is done inside the runtime call.
|
| + int shift_value = int_value & 0x1f;
|
| + operand->ToRegister();
|
| + if (shift_value == 0) {
|
| + // Spill operand so it can be overwritten in the slow case.
|
| + frame_->Spill(operand->reg());
|
| + DeferredInlineSmiOperation* deferred =
|
| + new DeferredInlineSmiOperation(op,
|
| + operand->reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + __ testl(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + deferred->BindExit();
|
| + frame_->Push(operand);
|
| + } else {
|
| + // Use a fresh temporary for nonzero shift values.
|
| + Result answer = allocator()->Allocate();
|
| + ASSERT(answer.is_valid());
|
| + DeferredInlineSmiOperation* deferred =
|
| + new DeferredInlineSmiOperation(op,
|
| + answer.reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + __ testl(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + __ movl(answer.reg(), operand->reg());
|
| + ASSERT(kSmiTag == 0); // adjust code if not the case
|
| + // We do no shifts, only the Smi conversion, if shift_value is 1.
|
| + if (shift_value > 1) {
|
| + __ shll(answer.reg(), Immediate(shift_value - 1));
|
| + }
|
| + // Convert int result to Smi, checking that it is in int range.
|
| + ASSERT(kSmiTagSize == 1); // adjust code if not the case
|
| + __ addl(answer.reg(), answer.reg());
|
| + deferred->Branch(overflow);
|
| + deferred->BindExit();
|
| + operand->Unuse();
|
| + frame_->Push(&answer);
|
| + }
|
| + }
|
| + break;
|
| +
|
| + case Token::BIT_OR:
|
| + case Token::BIT_XOR:
|
| + case Token::BIT_AND: {
|
| + operand->ToRegister();
|
| + frame_->Spill(operand->reg());
|
| + if (reversed) {
|
| + // Bit operations with a constant smi are commutative.
|
| + // We can swap left and right operands with no problem.
|
| + // Swap left and right overwrite modes. 0->0, 1->2, 2->1.
|
| + overwrite_mode = static_cast<OverwriteMode>((2 * overwrite_mode) % 3);
|
| + }
|
| + DeferredCode* deferred = new DeferredInlineSmiOperation(op,
|
| + operand->reg(),
|
| + operand->reg(),
|
| + smi_value,
|
| + overwrite_mode);
|
| + __ testl(operand->reg(), Immediate(kSmiTagMask));
|
| + deferred->Branch(not_zero);
|
| + if (op == Token::BIT_AND) {
|
| + __ and_(operand->reg(), Immediate(smi_value));
|
| + } else if (op == Token::BIT_XOR) {
|
| + if (int_value != 0) {
|
| + __ xor_(operand->reg(), Immediate(smi_value));
|
| + }
|
| + } else {
|
| + ASSERT(op == Token::BIT_OR);
|
| + if (int_value != 0) {
|
| + __ or_(operand->reg(), Immediate(smi_value));
|
| + }
|
| + }
|
| + deferred->BindExit();
|
| + frame_->Push(operand);
|
| + break;
|
| + }
|
| +
|
| // Generate inline code for mod of powers of 2 and negative powers of 2.
|
| case Token::MOD:
|
| if (!reversed &&
|
|
|