Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/x64/codegen-x64.cc

Issue 159584: X64: Fix error in division & modulus, adjust mjsunit test status, fix lint er... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/macro-assembler-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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(&quotient); 5003 frame_->Push(&quotient);
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/macro-assembler-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698