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

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

Issue 118110: Factor out the code for emitting the IA32 binary operations div and... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 6 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 | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-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 5717 matching lines...) Expand 10 before | Expand all | Expand 10 after
5728 __ ret(1 * kPointerSize); 5728 __ ret(1 * kPointerSize);
5729 __ bind(&false_result); 5729 __ bind(&false_result);
5730 __ mov(eax, 0); 5730 __ mov(eax, 0);
5731 __ ret(1 * kPointerSize); 5731 __ ret(1 * kPointerSize);
5732 } 5732 }
5733 5733
5734 5734
5735 Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, 5735 Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
5736 Result* right) { 5736 Result* right) {
5737 MacroAssembler* masm = cgen()->masm(); 5737 MacroAssembler* masm = cgen()->masm();
5738 // Perform fast-case smi code for the operation (left <op> right) and
5739 // returns the result in a Result.
5740 // If any fast-case tests fail, it jumps to the slow-case deferred code,
5741 // which calls the binary operation stub, with the arguments (in registers)
5742 // on top of the frame.
5743 // Consumes its arguments (sets left and right to invalid and frees their
5744 // registers).
5745 5738
5739 // Special handling of div and mod because they use fixed registers.
5740 if (op_ == Token::DIV || op_ == Token::MOD) {
5741 // We need eax as the quotient register, edx as the remainder
5742 // register, neither left nor right in eax or edx, and left copied
5743 // to eax.
5744 Result quotient;
5745 Result remainder;
5746 bool left_is_in_eax = false;
5747 // Step 1: get eax for quotient.
5748 if ((left->is_register() && left->reg().is(eax)) ||
5749 (right->is_register() && right->reg().is(eax))) {
5750 // One or both is in eax. Use a fresh non-edx register for
5751 // them.
5752 Result fresh = cgen()->allocator()->Allocate();
5753 ASSERT(fresh.is_valid());
5754 if (fresh.reg().is(edx)) {
5755 remainder = fresh;
5756 fresh = cgen()->allocator()->Allocate();
5757 ASSERT(fresh.is_valid());
5758 }
5759 if (left->is_register() && left->reg().is(eax)) {
5760 quotient = *left;
5761 *left = fresh;
5762 left_is_in_eax = true;
5763 }
5764 if (right->is_register() && right->reg().is(eax)) {
5765 quotient = *right;
5766 *right = fresh;
5767 }
5768 __ mov(fresh.reg(), eax);
5769 } else {
5770 // Neither left nor right is in eax.
5771 quotient = cgen()->allocator()->Allocate(eax);
5772 }
5773 ASSERT(quotient.is_register() && quotient.reg().is(eax));
5774 ASSERT(!(left->is_register() && left->reg().is(eax)));
5775 ASSERT(!(right->is_register() && right->reg().is(eax)));
5776
5777 // Step 2: get edx for remainder if necessary.
5778 if (!(remainder.is_register() && remainder.reg().is(edx))) {
William Hesse 2009/06/02 09:11:54 remainder is either invalid or edx at this point,
Kevin Millikin (Chromium) 2009/06/02 10:37:00 Thanks. I've changed it to !remainder.is_valid()
5779 if ((left->is_register() && left->reg().is(edx)) ||
5780 (right->is_register() && right->reg().is(edx))) {
5781 Result fresh = cgen()->allocator()->Allocate();
5782 ASSERT(fresh.is_valid());
5783 if (left->is_register() && left->reg().is(edx)) {
5784 remainder = *left;
5785 *left = fresh;
5786 }
5787 if (right->is_register() && right->reg().is(edx)) {
5788 remainder = *right;
5789 *right = fresh;
5790 }
5791 __ mov(fresh.reg(), edx);
5792 } else {
5793 // Neither left nor right is in edx.
5794 remainder = cgen()->allocator()->Allocate(edx);
5795 }
5796 }
5797 ASSERT(remainder.is_register() && remainder.reg().is(edx));
5798 ASSERT(!(left->is_register() && left->reg().is(edx)));
5799 ASSERT(!(right->is_register() && right->reg().is(edx)));
5800
5801 left->ToRegister();
5802 right->ToRegister();
5803 cgen()->frame()->Spill(quotient.reg());
5804 cgen()->frame()->Spill(remainder.reg());
5805
5806 // Check that left and right are smi tagged.
5807 if (left->reg().is(right->reg())) {
5808 __ test(left->reg(), Immediate(kSmiTagMask));
5809 } else {
5810 // Use the quotient register as a scratch for the tag check.
5811 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
5812 left_is_in_eax = false;
5813 __ or_(quotient.reg(), Operand(right->reg()));
5814 ASSERT(kSmiTag == 0); // Adjust test if not the case.
5815 __ test(quotient.reg(), Immediate(kSmiTagMask));
5816 }
5817 SetEntryFrame(left, right);
5818 enter()->Branch(not_zero, left, right);
5819
5820 if (!left_is_in_eax) __ mov(quotient.reg(), left->reg());
5821
5822 // Sign extend eax into edx:eax.
5823 __ cdq();
5824 // Check for 0 divisor.
5825 __ test(right->reg(), Operand(right->reg()));
5826 enter()->Branch(zero, left, right);
5827 // Divide edx:eax by the right operand.
5828 __ idiv(right->reg());
5829
5830 // Complete the operation.
5831 if (op_ == Token::DIV) {
5832 // Check for negative zero result. If result is zero, and divisor
5833 // is negative, return a floating point negative zero. The
5834 // virtual frame is unchanged in this block, so local control flow
5835 // can use a Label rather than a JumpTarget.
5836 Label non_zero_result;
5837 __ test(left->reg(), Operand(left->reg()));
5838 __ j(not_zero, &non_zero_result);
5839 __ test(right->reg(), Operand(right->reg()));
5840 enter()->Branch(negative, left, right);
5841 __ bind(&non_zero_result);
5842 // Check for the corner case of dividing the most negative smi by
5843 // -1. We cannot use the overflow flag, since it is not set by
5844 // idiv instruction.
5845 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
5846 __ cmp(quotient.reg(), 0x40000000);
5847 enter()->Branch(equal, left, right);
5848 // Check that the remainder is zero.
5849 __ test(remainder.reg(), Operand(remainder.reg()));
5850 enter()->Branch(not_zero, left, right);
5851 left->Unuse();
5852 right->Unuse();
5853 // Tag the result and store it in the quotient register.
5854 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5855 __ lea(quotient.reg(),
5856 Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag));
5857 return quotient;
5858 } else {
5859 ASSERT(op_ == Token::MOD);
5860 // Check for a negative zero result. If the result is zero, and
5861 // the dividend is negative, return a floating point negative
5862 // zero. The frame is unchanged in this block, so local control
5863 // flow can use a Label rather than a JumpTarget.
5864 Label non_zero_result;
5865 __ test(remainder.reg(), Operand(remainder.reg()));
5866 __ j(not_zero, &non_zero_result, taken);
5867 __ test(left->reg(), Operand(left->reg()));
5868 enter()->Branch(negative, left, right);
5869 left->Unuse();
5870 right->Unuse();
5871 __ bind(&non_zero_result);
5872 return remainder;
5873 }
5874 }
5875
5876 // Handle the other binary operations.
5746 left->ToRegister(); 5877 left->ToRegister();
5747 right->ToRegister(); 5878 right->ToRegister();
5748 // A newly allocated register answer is used to hold the answer. 5879 // A newly allocated register answer is used to hold the answer. The
5749 // The registers containing left and right are not modified in 5880 // registers containing left and right are not modified in most cases,
5750 // most cases, so they usually don't need to be spilled in the fast case. 5881 // so they usually don't need to be spilled in the fast case.
5751 Result answer = cgen()->allocator()->Allocate(); 5882 Result answer = cgen()->allocator()->Allocate();
5752 5883
5753 ASSERT(answer.is_valid()); 5884 ASSERT(answer.is_valid());
5754 // Perform the smi check. 5885 // Perform the smi tag check.
5755 if (left->reg().is(right->reg())) { 5886 if (left->reg().is(right->reg())) {
5756 __ test(left->reg(), Immediate(kSmiTagMask)); 5887 __ test(left->reg(), Immediate(kSmiTagMask));
5757 } else { 5888 } else {
5758 __ mov(answer.reg(), left->reg()); 5889 __ mov(answer.reg(), left->reg());
5759 __ or_(answer.reg(), Operand(right->reg())); 5890 __ or_(answer.reg(), Operand(right->reg()));
5760 ASSERT(kSmiTag == 0); // adjust zero check if not the case 5891 ASSERT(kSmiTag == 0); // Adjust test if not the case.
5761 __ test(answer.reg(), Immediate(kSmiTagMask)); 5892 __ test(answer.reg(), Immediate(kSmiTagMask));
5762 } 5893 }
5763 switch (op_) { 5894 switch (op_) {
5764 case Token::ADD: 5895 case Token::ADD:
5765 SetEntryFrame(left, right); 5896 SetEntryFrame(left, right);
5766 enter()->Branch(not_zero, left, right, not_taken); 5897 enter()->Branch(not_zero, left, right, not_taken);
5767 __ mov(answer.reg(), left->reg()); 5898 __ mov(answer.reg(), left->reg());
5768 __ add(answer.reg(), Operand(right->reg())); // add optimistically 5899 __ add(answer.reg(), Operand(right->reg())); // Add optimistically.
5769 enter()->Branch(overflow, left, right, not_taken); 5900 enter()->Branch(overflow, left, right, not_taken);
5770 break; 5901 break;
5771 5902
5772 case Token::SUB: 5903 case Token::SUB:
5773 SetEntryFrame(left, right); 5904 SetEntryFrame(left, right);
5774 enter()->Branch(not_zero, left, right, not_taken); 5905 enter()->Branch(not_zero, left, right, not_taken);
5775 __ mov(answer.reg(), left->reg()); 5906 __ mov(answer.reg(), left->reg());
5776 __ sub(answer.reg(), Operand(right->reg())); // subtract optimistically 5907 __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically.
5777 enter()->Branch(overflow, left, right, not_taken); 5908 enter()->Branch(overflow, left, right, not_taken);
5778 break; 5909 break;
5779 5910
5780 case Token::MUL: { 5911 case Token::MUL: {
5781 SetEntryFrame(left, right); 5912 SetEntryFrame(left, right);
5782 enter()->Branch(not_zero, left, right, not_taken); 5913 enter()->Branch(not_zero, left, right, not_taken);
5783 __ mov(answer.reg(), left->reg()); 5914 __ mov(answer.reg(), left->reg());
5784 // If the smi tag is 0 we can just leave the tag on one operand. 5915 // If the smi tag is 0 we can just leave the tag on one operand.
5785 ASSERT(kSmiTag == 0); // adjust code below if not the case 5916 ASSERT(kSmiTag == 0); // Adjust code below if not the case.
5786 // Remove tag from the left operand (but keep sign). 5917 // Remove smi tag from the left operand (but keep sign).
5787 // Left hand operand has been copied into answer. 5918 // Left-hand operand has been copied into answer.
5788 __ sar(answer.reg(), kSmiTagSize); 5919 __ sar(answer.reg(), kSmiTagSize);
5789 // Do multiplication of smis, leaving result in answer. 5920 // Do multiplication of smis, leaving result in answer.
5790 __ imul(answer.reg(), Operand(right->reg())); 5921 __ imul(answer.reg(), Operand(right->reg()));
5791 // Go slow on overflows. 5922 // Go slow on overflows.
5792 enter()->Branch(overflow, left, right, not_taken); 5923 enter()->Branch(overflow, left, right, not_taken);
5793 // Check for negative zero result. If product is zero, 5924 // Check for negative zero result. If product is zero, and one
5794 // and one argument is negative, go to slow case. 5925 // argument is negative, go to slow case. The frame is unchanged
5795 // The frame is unchanged in this block, so local control flow can 5926 // in this block, so local control flow can use a Label rather
5796 // use a Label rather than a JumpTarget. 5927 // than a JumpTarget.
5797 Label non_zero_result; 5928 Label non_zero_result;
5798 __ test(answer.reg(), Operand(answer.reg())); 5929 __ test(answer.reg(), Operand(answer.reg()));
5799 __ j(not_zero, &non_zero_result, taken); 5930 __ j(not_zero, &non_zero_result, taken);
5800 __ mov(answer.reg(), left->reg()); 5931 __ mov(answer.reg(), left->reg());
5801 __ or_(answer.reg(), Operand(right->reg())); 5932 __ or_(answer.reg(), Operand(right->reg()));
5802 enter()->Branch(negative, left, right, not_taken); 5933 enter()->Branch(negative, left, right, not_taken);
5803 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. 5934 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
5804 __ bind(&non_zero_result); 5935 __ bind(&non_zero_result);
5805 break; 5936 break;
5806 } 5937 }
5807 5938
5808 case Token::DIV: // Fall through.
5809 case Token::MOD: {
5810 enter()->Branch(not_zero, left, right, not_taken);
5811 __ mov(answer.reg(), left->reg());
5812 // Div and mod use the registers eax and edx. Left and right must
5813 // be preserved, because the original operands are needed if we switch
5814 // to the slow case. Move them if either is in eax or edx.
5815 // The Result answer should be changed into an alias for eax.
5816 // Precondition:
5817 // The Results left and right are valid. They may be the same register,
5818 // and may be unspilled. The Result answer is valid and is distinct
5819 // from left and right, and is spilled.
5820 // The value in left is copied to answer.
5821
5822 Result reg_eax = cgen()->allocator()->Allocate(eax);
5823 Result reg_edx = cgen()->allocator()->Allocate(edx);
5824 // These allocations may have failed, if one of left, right, or answer
5825 // is in register eax or edx.
5826 bool left_copied_to_eax = false; // We will make sure this becomes true.
5827
5828 // Part 1: Get eax
5829 if (answer.reg().is(eax)) {
5830 reg_eax = answer;
5831 left_copied_to_eax = true;
5832 } else if (right->reg().is(eax) || left->reg().is(eax)) {
5833 // We need a non-edx register to move one or both of left and right to.
5834 // We use answer if it is not edx, otherwise we allocate one.
5835 if (answer.reg().is(edx)) {
5836 reg_edx = answer;
5837 answer = cgen()->allocator()->Allocate();
5838 ASSERT(answer.is_valid());
5839 }
5840
5841 if (left->reg().is(eax)) {
5842 reg_eax = *left;
5843 left_copied_to_eax = true;
5844 *left = answer;
5845 }
5846 if (right->reg().is(eax)) {
5847 reg_eax = *right;
5848 *right = answer;
5849 }
5850 __ mov(answer.reg(), eax);
5851 }
5852 // End of Part 1.
5853 // reg_eax is valid, and neither left nor right is in eax.
5854 ASSERT(reg_eax.is_valid());
5855 ASSERT(!left->reg().is(eax));
5856 ASSERT(!right->reg().is(eax));
5857
5858 // Part 2: Get edx
5859 // reg_edx is invalid if and only if either left, right,
5860 // or answer is in edx. If edx is valid, then either edx
5861 // was free, or it was answer, but answer was reallocated.
5862 if (answer.reg().is(edx)) {
5863 reg_edx = answer;
5864 } else if (right->reg().is(edx) || left->reg().is(edx)) {
5865 // Is answer used?
5866 if (answer.reg().is(eax) || answer.reg().is(left->reg()) ||
5867 answer.reg().is(right->reg())) {
5868 answer = cgen()->allocator()->Allocate();
5869 ASSERT(answer.is_valid()); // We cannot hit both Allocate() calls.
5870 }
5871 if (left->reg().is(edx)) {
5872 reg_edx = *left;
5873 *left = answer;
5874 }
5875 if (right->reg().is(edx)) {
5876 reg_edx = *right;
5877 *right = answer;
5878 }
5879 __ mov(answer.reg(), edx);
5880 }
5881 // End of Part 2
5882 ASSERT(reg_edx.is_valid());
5883 ASSERT(!left->reg().is(eax));
5884 ASSERT(!right->reg().is(eax));
5885
5886 answer = reg_eax; // May free answer, if it was never used.
5887 cgen()->frame()->Spill(eax);
5888 if (!left_copied_to_eax) {
5889 __ mov(eax, left->reg());
5890 left_copied_to_eax = true;
5891 }
5892 cgen()->frame()->Spill(edx);
5893
5894 // Postcondition:
5895 // reg_eax, reg_edx are valid, correct, and spilled.
5896 // reg_eax contains the value originally in left
5897 // left and right are not eax or edx. They may or may not be
5898 // spilled or distinct.
5899 // answer is an alias for reg_eax.
5900
5901 // Sign extend eax into edx:eax.
5902 __ cdq();
5903 // Check for 0 divisor.
5904 __ test(right->reg(), Operand(right->reg()));
5905 enter()->Branch(zero, left, right, not_taken);
5906 // Divide edx:eax by the right operand.
5907 __ idiv(right->reg());
5908 if (op_ == Token::DIV) {
5909 // Check for negative zero result. If result is zero, and divisor
5910 // is negative, return a floating point negative zero.
5911 // The frame is unchanged in this block, so local control flow can
5912 // use a Label rather than a JumpTarget.
5913 Label non_zero_result;
5914 __ test(left->reg(), Operand(left->reg()));
5915 __ j(not_zero, &non_zero_result, taken);
5916 __ test(right->reg(), Operand(right->reg()));
5917 enter()->Branch(negative, left, right, not_taken);
5918 __ bind(&non_zero_result);
5919 // Check for the corner case of dividing the most negative smi
5920 // by -1. We cannot use the overflow flag, since it is not set
5921 // by idiv instruction.
5922 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
5923 __ cmp(eax, 0x40000000);
5924 enter()->Branch(equal, left, right, not_taken);
5925 // Check that the remainder is zero.
5926 __ test(edx, Operand(edx));
5927 enter()->Branch(not_zero, left, right, not_taken);
5928 // Tag the result and store it in register temp.
5929 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
5930 __ lea(answer.reg(), Operand(eax, eax, times_1, kSmiTag));
5931 } else {
5932 ASSERT(op_ == Token::MOD);
5933 // Check for a negative zero result. If the result is zero, and the
5934 // dividend is negative, return a floating point negative zero.
5935 // The frame is unchanged in this block, so local control flow can
5936 // use a Label rather than a JumpTarget.
5937 Label non_zero_result;
5938 __ test(edx, Operand(edx));
5939 __ j(not_zero, &non_zero_result, taken);
5940 __ test(left->reg(), Operand(left->reg()));
5941 enter()->Branch(negative, left, right, not_taken);
5942 __ bind(&non_zero_result);
5943 // The answer is in edx.
5944 answer = reg_edx;
5945 }
5946 break;
5947 }
5948 case Token::BIT_OR: 5939 case Token::BIT_OR:
5949 enter()->Branch(not_zero, left, right, not_taken); 5940 enter()->Branch(not_zero, left, right, not_taken);
5950 __ mov(answer.reg(), left->reg()); 5941 __ mov(answer.reg(), left->reg());
5951 __ or_(answer.reg(), Operand(right->reg())); 5942 __ or_(answer.reg(), Operand(right->reg()));
5952 break; 5943 break;
5953 5944
5954 case Token::BIT_AND: 5945 case Token::BIT_AND:
5955 enter()->Branch(not_zero, left, right, not_taken); 5946 enter()->Branch(not_zero, left, right, not_taken);
5956 __ mov(answer.reg(), left->reg()); 5947 __ mov(answer.reg(), left->reg());
5957 __ and_(answer.reg(), Operand(right->reg())); 5948 __ and_(answer.reg(), Operand(right->reg()));
(...skipping 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after
7289 7280
7290 // Slow-case: Go through the JavaScript implementation. 7281 // Slow-case: Go through the JavaScript implementation.
7291 __ bind(&slow); 7282 __ bind(&slow);
7292 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 7283 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7293 } 7284 }
7294 7285
7295 7286
7296 #undef __ 7287 #undef __
7297 7288
7298 } } // namespace v8::internal 7289 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698