OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4844 smi_value, | 4844 smi_value, |
4845 overwrite_mode); | 4845 overwrite_mode); |
4846 } | 4846 } |
4847 __ testl(operand->reg(), Immediate(kSmiTagMask)); | 4847 __ testl(operand->reg(), Immediate(kSmiTagMask)); |
4848 deferred->Branch(not_zero); | 4848 deferred->Branch(not_zero); |
4849 // A smi currently fits in a 32-bit Immediate. | 4849 // A smi currently fits in a 32-bit Immediate. |
4850 __ addl(operand->reg(), Immediate(smi_value)); | 4850 __ addl(operand->reg(), Immediate(smi_value)); |
4851 Label add_success; | 4851 Label add_success; |
4852 __ j(no_overflow, &add_success); | 4852 __ j(no_overflow, &add_success); |
4853 __ subl(operand->reg(), Immediate(smi_value)); | 4853 __ subl(operand->reg(), Immediate(smi_value)); |
4854 __ movsxlq(operand->reg(), operand->reg()); | |
4855 deferred->Jump(); | 4854 deferred->Jump(); |
4856 __ bind(&add_success); | 4855 __ bind(&add_success); |
4857 __ movsxlq(operand->reg(), operand->reg()); | |
4858 deferred->BindExit(); | 4856 deferred->BindExit(); |
4859 frame_->Push(operand); | 4857 frame_->Push(operand); |
4860 break; | 4858 break; |
4861 } | 4859 } |
4862 // TODO(X64): Move other implementations from ia32 to here. | 4860 // TODO(X64): Move other implementations from ia32 to here. |
4863 default: { | 4861 default: { |
4864 Result constant_operand(value); | 4862 Result constant_operand(value); |
4865 if (reversed) { | 4863 if (reversed) { |
4866 LikelySmiBinaryOperation(op, &constant_operand, operand, | 4864 LikelySmiBinaryOperation(op, &constant_operand, operand, |
4867 overwrite_mode); | 4865 overwrite_mode); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4958 } else { | 4956 } else { |
4959 // Use the quotient register as a scratch for the tag check. | 4957 // Use the quotient register as a scratch for the tag check. |
4960 if (!left_is_in_rax) __ movq(rax, left->reg()); | 4958 if (!left_is_in_rax) __ movq(rax, left->reg()); |
4961 left_is_in_rax = false; // About to destroy the value in rax. | 4959 left_is_in_rax = false; // About to destroy the value in rax. |
4962 __ or_(rax, right->reg()); | 4960 __ or_(rax, right->reg()); |
4963 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 4961 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
4964 __ testl(rax, Immediate(kSmiTagMask)); | 4962 __ testl(rax, Immediate(kSmiTagMask)); |
4965 } | 4963 } |
4966 deferred->Branch(not_zero); | 4964 deferred->Branch(not_zero); |
4967 | 4965 |
4968 if (!left_is_in_rax) __ movq(rax, left->reg()); | 4966 // All operations on the smi values are on 32-bit registers, which are |
4969 // Sign extend rax into rdx:rax. | 4967 // zero-extended into 64-bits by all 32-bit operations. |
4970 __ cqo(); | 4968 if (!left_is_in_rax) __ movl(rax, left->reg()); |
4969 // Sign extend eax into edx:eax. | |
4970 __ cdq(); | |
4971 // Check for 0 divisor. | 4971 // Check for 0 divisor. |
4972 __ testq(right->reg(), right->reg()); | 4972 __ testl(right->reg(), right->reg()); |
4973 deferred->Branch(zero); | 4973 deferred->Branch(zero); |
4974 // Divide rdx:rax by the right operand. | 4974 // Divide rdx:rax by the right operand. |
4975 __ idiv(right->reg()); | 4975 __ idivl(right->reg()); |
4976 | 4976 |
4977 // Complete the operation. | 4977 // Complete the operation. |
4978 if (op == Token::DIV) { | 4978 if (op == Token::DIV) { |
4979 // Check for negative zero result. If result is zero, and divisor | 4979 // Check for negative zero result. If result is zero, and divisor |
4980 // is negative, return a floating point negative zero. The | 4980 // is negative, return a floating point negative zero. The jump |
4981 // virtual frame is unchanged in this block, so local control flow | 4981 // to non_zero_result is safe w.r.t. the frame. |
4982 // can use a Label rather than a JumpTarget. | |
4983 Label non_zero_result; | 4982 Label non_zero_result; |
4984 __ testq(left->reg(), left->reg()); | 4983 __ testl(left->reg(), left->reg()); |
4985 __ j(not_zero, &non_zero_result); | 4984 __ j(not_zero, &non_zero_result); |
4986 __ testq(right->reg(), right->reg()); | 4985 __ testl(right->reg(), right->reg()); |
4987 deferred->Branch(negative); | 4986 deferred->Branch(negative); |
4988 __ bind(&non_zero_result); | 4987 __ bind(&non_zero_result); |
4989 // Check for the corner case of dividing the most negative smi by | 4988 // Check for the corner case of dividing the most negative smi by |
4990 // -1. We cannot use the overflow flag, since it is not set by | 4989 // -1. We cannot use the overflow flag, since it is not set by |
4991 // idiv instruction. | 4990 // idiv instruction. |
4992 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 4991 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
4993 __ cmpq(rax, Immediate(0x40000000)); | 4992 __ cmpl(rax, Immediate(0x40000000)); |
4994 deferred->Branch(equal); | 4993 deferred->Branch(equal); |
4995 // Check that the remainder is zero. | 4994 // Check that the remainder is zero. |
4996 __ testq(rdx, rdx); | 4995 __ testl(rdx, rdx); |
4997 deferred->Branch(not_zero); | 4996 deferred->Branch(not_zero); |
4998 // Tag the result and store it in the quotient register. | 4997 // Tag the result and store it in the quotient register. |
4999 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 4998 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
5000 __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); | 4999 __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
5001 deferred->BindExit(); | 5000 deferred->BindExit(); |
5002 left->Unuse(); | 5001 left->Unuse(); |
5003 right->Unuse(); | 5002 right->Unuse(); |
5004 frame_->Push("ient); | 5003 frame_->Push("ient); |
5005 } else { | 5004 } else { |
5006 ASSERT(op == Token::MOD); | 5005 ASSERT(op == Token::MOD); |
5007 // Check for a negative zero result. If the result is zero, and | 5006 // Check for a negative zero result. If the result is zero, and |
5008 // the dividend is negative, return a floating point negative | 5007 // the dividend is negative, return a floating point negative |
5009 // zero. The frame is unchanged in this block, so local control | 5008 // zero. The frame is unchanged between the jump to &non_zero_result |
5010 // flow can use a Label rather than a JumpTarget. | 5009 // and the target, so a Label can be used. |
Kevin Millikin (Chromium)
2009/07/30 07:52:05
To me this is less precise than what was before.
| |
5011 Label non_zero_result; | 5010 Label non_zero_result; |
5012 __ testq(rdx, rdx); | 5011 __ testl(rdx, rdx); |
5013 __ j(not_zero, &non_zero_result); | 5012 __ j(not_zero, &non_zero_result); |
5014 __ testq(left->reg(), left->reg()); | 5013 __ testl(left->reg(), left->reg()); |
5015 deferred->Branch(negative); | 5014 deferred->Branch(negative); |
5016 __ bind(&non_zero_result); | 5015 __ bind(&non_zero_result); |
5017 deferred->BindExit(); | 5016 deferred->BindExit(); |
5018 left->Unuse(); | 5017 left->Unuse(); |
5019 right->Unuse(); | 5018 right->Unuse(); |
5020 frame_->Push(&remainder); | 5019 frame_->Push(&remainder); |
5021 } | 5020 } |
5022 return; | 5021 return; |
5023 } | 5022 } |
5024 | 5023 |
(...skipping 24 matching lines...) Expand all Loading... | |
5049 answer.reg(), | 5048 answer.reg(), |
5050 left->reg(), | 5049 left->reg(), |
5051 rcx, | 5050 rcx, |
5052 overwrite_mode); | 5051 overwrite_mode); |
5053 __ movq(answer.reg(), left->reg()); | 5052 __ movq(answer.reg(), left->reg()); |
5054 __ or_(answer.reg(), rcx); | 5053 __ or_(answer.reg(), rcx); |
5055 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 5054 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
5056 deferred->Branch(not_zero); | 5055 deferred->Branch(not_zero); |
5057 | 5056 |
5058 // Untag both operands. | 5057 // Untag both operands. |
5059 __ movq(answer.reg(), left->reg()); | 5058 __ movl(answer.reg(), left->reg()); |
5060 __ sar(answer.reg(), Immediate(kSmiTagSize)); | 5059 __ sarl(answer.reg(), Immediate(kSmiTagSize)); |
5061 __ sar(rcx, Immediate(kSmiTagSize)); | 5060 __ sarl(rcx, Immediate(kSmiTagSize)); |
5062 // Perform the operation. | 5061 // Perform the operation. |
5063 switch (op) { | 5062 switch (op) { |
5064 case Token::SAR: | 5063 case Token::SAR: |
5065 __ sarl(answer.reg()); | 5064 __ sarl(answer.reg()); |
5066 // No checks of result necessary | 5065 // No checks of result necessary |
5067 break; | 5066 break; |
5068 case Token::SHR: { | 5067 case Token::SHR: { |
5069 Label result_ok; | 5068 Label result_ok; |
5070 __ shrl(answer.reg()); | 5069 __ shrl(answer.reg()); |
5071 // Check that the *unsigned* result fits in a smi. Neither of | 5070 // Check that the *unsigned* result fits in a smi. Neither of |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5157 __ sarl(answer.reg(), Immediate(kSmiTagSize)); | 5156 __ sarl(answer.reg(), Immediate(kSmiTagSize)); |
5158 // Do multiplication of smis, leaving result in answer. | 5157 // Do multiplication of smis, leaving result in answer. |
5159 __ imull(answer.reg(), right->reg()); | 5158 __ imull(answer.reg(), right->reg()); |
5160 // Go slow on overflows. | 5159 // Go slow on overflows. |
5161 deferred->Branch(overflow); | 5160 deferred->Branch(overflow); |
5162 // Check for negative zero result. If product is zero, and one | 5161 // Check for negative zero result. If product is zero, and one |
5163 // argument is negative, go to slow case. The frame is unchanged | 5162 // argument is negative, go to slow case. The frame is unchanged |
5164 // in this block, so local control flow can use a Label rather | 5163 // in this block, so local control flow can use a Label rather |
5165 // than a JumpTarget. | 5164 // than a JumpTarget. |
5166 Label non_zero_result; | 5165 Label non_zero_result; |
5167 __ testq(answer.reg(), answer.reg()); | 5166 __ testl(answer.reg(), answer.reg()); |
5168 __ j(not_zero, &non_zero_result); | 5167 __ j(not_zero, &non_zero_result); |
5169 __ movq(answer.reg(), left->reg()); | 5168 __ movq(answer.reg(), left->reg()); |
5170 __ or_(answer.reg(), right->reg()); | 5169 __ or_(answer.reg(), right->reg()); |
5171 deferred->Branch(negative); | 5170 deferred->Branch(negative); |
5172 __ xor_(answer.reg(), answer.reg()); // Positive 0 is correct. | 5171 __ xor_(answer.reg(), answer.reg()); // Positive 0 is correct. |
5173 __ bind(&non_zero_result); | 5172 __ bind(&non_zero_result); |
5174 break; | 5173 break; |
5175 } | 5174 } |
5176 | 5175 |
5177 case Token::BIT_OR: | 5176 case Token::BIT_OR: |
(...skipping 1379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6557 default: return "GenericBinaryOpStub"; | 6556 default: return "GenericBinaryOpStub"; |
6558 } | 6557 } |
6559 } | 6558 } |
6560 | 6559 |
6561 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 6560 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
6562 // Perform fast-case smi code for the operation (rax <op> rbx) and | 6561 // Perform fast-case smi code for the operation (rax <op> rbx) and |
6563 // leave result in register rax. | 6562 // leave result in register rax. |
6564 | 6563 |
6565 // Smi check both operands. | 6564 // Smi check both operands. |
6566 __ movq(rcx, rbx); | 6565 __ movq(rcx, rbx); |
6567 __ or_(rcx, rax); | 6566 __ or_(rcx, rax); // The value in ecx is used for negative zero test later. |
6568 __ testl(rcx, Immediate(kSmiTagMask)); | 6567 __ testl(rcx, Immediate(kSmiTagMask)); |
6569 __ j(not_zero, slow); | 6568 __ j(not_zero, slow); |
6570 | 6569 |
6571 switch (op_) { | 6570 switch (op_) { |
6572 case Token::ADD: { | 6571 case Token::ADD: { |
6573 __ addl(rax, rbx); | 6572 __ addl(rax, rbx); |
6574 __ j(overflow, slow); // The slow case rereads operands from the stack. | 6573 __ j(overflow, slow); // The slow case rereads operands from the stack. |
6575 __ movsxlq(rax, rax); // Sign extend eax into rax. | |
6576 break; | 6574 break; |
6577 } | 6575 } |
6578 | 6576 |
6579 case Token::SUB: { | 6577 case Token::SUB: { |
6580 __ subl(rax, rbx); | 6578 __ subl(rax, rbx); |
6581 __ j(overflow, slow); // The slow case rereads operands from the stack. | 6579 __ j(overflow, slow); // The slow case rereads operands from the stack. |
6582 __ movsxlq(rax, rax); // Sign extend eax into rax. | |
6583 break; | 6580 break; |
6584 } | 6581 } |
6585 | 6582 |
6586 case Token::MUL: | 6583 case Token::MUL: |
6587 // If the smi tag is 0 we can just leave the tag on one operand. | 6584 // If the smi tag is 0 we can just leave the tag on one operand. |
6588 ASSERT(kSmiTag == 0); // adjust code below if not the case | 6585 ASSERT(kSmiTag == 0); // adjust code below if not the case |
6589 // Remove tag from one of the operands (but keep sign). | 6586 // Remove tag from one of the operands (but keep sign). |
6590 __ sarl(rax, Immediate(kSmiTagSize)); | 6587 __ sarl(rax, Immediate(kSmiTagSize)); |
6591 // Do multiplication. | 6588 // Do multiplication. |
6592 __ imull(rax, rbx); // multiplication of smis; result in eax | 6589 __ imull(rax, rbx); // multiplication of smis; result in eax |
6593 // Go slow on overflows. | 6590 // Go slow on overflows. |
6594 __ j(overflow, slow); | 6591 __ j(overflow, slow); |
6595 // Check for negative zero result. | 6592 // Check for negative zero result. |
6596 __ movsxlq(rax, rax); // Sign extend eax into rax. | 6593 __ NegativeZeroTest(rax, rcx, slow); // ecx (not rcx) holds x | y. |
6597 __ NegativeZeroTest(rax, rcx, slow); // use rcx = x | y | |
6598 break; | 6594 break; |
6599 | 6595 |
6600 case Token::DIV: | 6596 case Token::DIV: |
6601 // Sign extend rax into rdx:rax | 6597 // Sign extend eax into edx:eax. |
6602 // (also sign extends eax into edx if eax is Smi). | 6598 __ cdq(); |
6603 __ cqo(); | |
6604 // Check for 0 divisor. | 6599 // Check for 0 divisor. |
6605 __ testq(rbx, rbx); | 6600 __ testl(rbx, rbx); |
6606 __ j(zero, slow); | 6601 __ j(zero, slow); |
6607 // Divide rdx:rax by rbx (where rdx:rax is equivalent to the smi in eax). | 6602 // Divide edx:eax by ebx (where edx:eax is equivalent to the smi in eax). |
6608 __ idiv(rbx); | 6603 __ idivl(rbx); |
6609 // Check that the remainder is zero. | 6604 // Check that the remainder is zero. |
6610 __ testq(rdx, rdx); | 6605 __ testl(rdx, rdx); |
6611 __ j(not_zero, slow); | 6606 __ j(not_zero, slow); |
6612 // Check for the corner case of dividing the most negative smi | 6607 // Check for the corner case of dividing the most negative smi |
6613 // by -1. We cannot use the overflow flag, since it is not set | 6608 // by -1. We cannot use the overflow flag, since it is not set |
6614 // by idiv instruction. | 6609 // by idiv instruction. |
6615 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 6610 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
6616 // TODO(X64): TODO(Smi): Smi implementation dependent constant. | 6611 // TODO(X64): TODO(Smi): Smi implementation dependent constant. |
6617 // Value is Smi::fromInt(-(1<<31)) / Smi::fromInt(-1) | 6612 // Value is Smi::fromInt(-(1<<31)) / Smi::fromInt(-1) |
6618 __ cmpq(rax, Immediate(0x40000000)); | 6613 __ cmpl(rax, Immediate(0x40000000)); |
6619 __ j(equal, slow); | 6614 __ j(equal, slow); |
6620 // Check for negative zero result. | 6615 // Check for negative zero result. |
6621 __ NegativeZeroTest(rax, rcx, slow); // use ecx = x | y | 6616 __ NegativeZeroTest(rax, rcx, slow); // ecx (not rcx) holds x | y. |
6622 // Tag the result and store it in register rax. | 6617 // Tag the result and store it in register rax. |
6623 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 6618 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
6624 __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); | 6619 __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); |
6625 break; | 6620 break; |
6626 | 6621 |
6627 case Token::MOD: | 6622 case Token::MOD: |
6628 // Sign extend rax into rdx:rax | 6623 // Sign extend eax into edx:eax |
6629 // (also sign extends eax into edx if eax is Smi). | 6624 __ cdq(); |
6630 __ cqo(); | |
6631 // Check for 0 divisor. | 6625 // Check for 0 divisor. |
6632 __ testq(rbx, rbx); | 6626 __ testl(rbx, rbx); |
6633 __ j(zero, slow); | 6627 __ j(zero, slow); |
6634 // Divide rdx:rax by rbx. | 6628 // Divide edx:eax by ebx. |
6635 __ idiv(rbx); | 6629 __ idivl(rbx); |
6636 // Check for negative zero result. | 6630 // Check for negative zero result. |
6637 __ NegativeZeroTest(rdx, rcx, slow); // use ecx = x | y | 6631 __ NegativeZeroTest(rdx, rcx, slow); // ecx (not rcx) holds x | y. |
6638 // Move remainder to register rax. | 6632 // Move remainder to register rax. |
6639 __ movq(rax, rdx); | 6633 __ movl(rax, rdx); |
6640 break; | 6634 break; |
6641 | 6635 |
6642 case Token::BIT_OR: | 6636 case Token::BIT_OR: |
6643 __ or_(rax, rbx); | 6637 __ or_(rax, rbx); |
6644 break; | 6638 break; |
6645 | 6639 |
6646 case Token::BIT_AND: | 6640 case Token::BIT_AND: |
6647 __ and_(rax, rbx); | 6641 __ and_(rax, rbx); |
6648 break; | 6642 break; |
6649 | 6643 |
6650 case Token::BIT_XOR: | 6644 case Token::BIT_XOR: |
6651 ASSERT_EQ(0, kSmiTag); | 6645 ASSERT_EQ(0, kSmiTag); |
6652 __ xor_(rax, rbx); | 6646 __ xor_(rax, rbx); |
6653 break; | 6647 break; |
6654 | 6648 |
6655 case Token::SHL: | 6649 case Token::SHL: |
6656 case Token::SHR: | 6650 case Token::SHR: |
6657 case Token::SAR: | 6651 case Token::SAR: |
6658 // Move the second operand into register ecx. | 6652 // Move the second operand into register ecx. |
6659 __ movq(rcx, rbx); | 6653 __ movl(rcx, rbx); |
6660 // Remove tags from operands (but keep sign). | 6654 // Remove tags from operands (but keep sign). |
6661 __ sarl(rax, Immediate(kSmiTagSize)); | 6655 __ sarl(rax, Immediate(kSmiTagSize)); |
6662 __ sarl(rcx, Immediate(kSmiTagSize)); | 6656 __ sarl(rcx, Immediate(kSmiTagSize)); |
6663 // Perform the operation. | 6657 // Perform the operation. |
6664 switch (op_) { | 6658 switch (op_) { |
6665 case Token::SAR: | 6659 case Token::SAR: |
6666 __ sarl(rax); | 6660 __ sarl(rax); |
6667 // No checks of result necessary | 6661 // No checks of result necessary |
6668 break; | 6662 break; |
6669 case Token::SHR: | 6663 case Token::SHR: |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6943 int CompareStub::MinorKey() { | 6937 int CompareStub::MinorKey() { |
6944 // Encode the two parameters in a unique 16 bit value. | 6938 // Encode the two parameters in a unique 16 bit value. |
6945 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 6939 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
6946 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 6940 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
6947 } | 6941 } |
6948 | 6942 |
6949 | 6943 |
6950 #undef __ | 6944 #undef __ |
6951 | 6945 |
6952 } } // namespace v8::internal | 6946 } } // namespace v8::internal |
OLD | NEW |