Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/codegen-ia32.cc (revision 2081) |
| +++ src/ia32/codegen-ia32.cc (working copy) |
| @@ -5735,29 +5735,160 @@ |
| Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left, |
| Result* right) { |
| MacroAssembler* masm = cgen()->masm(); |
| - // Perform fast-case smi code for the operation (left <op> right) and |
| - // returns the result in a Result. |
| - // If any fast-case tests fail, it jumps to the slow-case deferred code, |
| - // which calls the binary operation stub, with the arguments (in registers) |
| - // on top of the frame. |
| - // Consumes its arguments (sets left and right to invalid and frees their |
| - // registers). |
| + // Special handling of div and mod because they use fixed registers. |
| + if (op_ == Token::DIV || op_ == Token::MOD) { |
| + // We need eax as the quotient register, edx as the remainder |
| + // register, neither left nor right in eax or edx, and left copied |
| + // to eax. |
| + Result quotient; |
| + Result remainder; |
| + bool left_is_in_eax = false; |
| + // Step 1: get eax for quotient. |
| + if ((left->is_register() && left->reg().is(eax)) || |
| + (right->is_register() && right->reg().is(eax))) { |
| + // One or both is in eax. Use a fresh non-edx register for |
| + // them. |
| + Result fresh = cgen()->allocator()->Allocate(); |
| + ASSERT(fresh.is_valid()); |
| + if (fresh.reg().is(edx)) { |
| + remainder = fresh; |
| + fresh = cgen()->allocator()->Allocate(); |
| + ASSERT(fresh.is_valid()); |
| + } |
| + if (left->is_register() && left->reg().is(eax)) { |
| + quotient = *left; |
| + *left = fresh; |
| + left_is_in_eax = true; |
| + } |
| + if (right->is_register() && right->reg().is(eax)) { |
| + quotient = *right; |
| + *right = fresh; |
| + } |
| + __ mov(fresh.reg(), eax); |
| + } else { |
| + // Neither left nor right is in eax. |
| + quotient = cgen()->allocator()->Allocate(eax); |
| + } |
| + ASSERT(quotient.is_register() && quotient.reg().is(eax)); |
| + ASSERT(!(left->is_register() && left->reg().is(eax))); |
| + ASSERT(!(right->is_register() && right->reg().is(eax))); |
| + |
| + // Step 2: get edx for remainder if necessary. |
| + 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()
|
| + if ((left->is_register() && left->reg().is(edx)) || |
| + (right->is_register() && right->reg().is(edx))) { |
| + Result fresh = cgen()->allocator()->Allocate(); |
| + ASSERT(fresh.is_valid()); |
| + if (left->is_register() && left->reg().is(edx)) { |
| + remainder = *left; |
| + *left = fresh; |
| + } |
| + if (right->is_register() && right->reg().is(edx)) { |
| + remainder = *right; |
| + *right = fresh; |
| + } |
| + __ mov(fresh.reg(), edx); |
| + } else { |
| + // Neither left nor right is in edx. |
| + remainder = cgen()->allocator()->Allocate(edx); |
| + } |
| + } |
| + ASSERT(remainder.is_register() && remainder.reg().is(edx)); |
| + ASSERT(!(left->is_register() && left->reg().is(edx))); |
| + ASSERT(!(right->is_register() && right->reg().is(edx))); |
| + |
| + left->ToRegister(); |
| + right->ToRegister(); |
| + cgen()->frame()->Spill(quotient.reg()); |
| + cgen()->frame()->Spill(remainder.reg()); |
| + |
| + // Check that left and right are smi tagged. |
| + if (left->reg().is(right->reg())) { |
| + __ test(left->reg(), Immediate(kSmiTagMask)); |
| + } else { |
| + // Use the quotient register as a scratch for the tag check. |
| + if (!left_is_in_eax) __ mov(quotient.reg(), left->reg()); |
| + left_is_in_eax = false; |
| + __ or_(quotient.reg(), Operand(right->reg())); |
| + ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| + __ test(quotient.reg(), Immediate(kSmiTagMask)); |
| + } |
| + SetEntryFrame(left, right); |
| + enter()->Branch(not_zero, left, right); |
| + |
| + if (!left_is_in_eax) __ mov(quotient.reg(), left->reg()); |
| + |
| + // Sign extend eax into edx:eax. |
| + __ cdq(); |
| + // Check for 0 divisor. |
| + __ test(right->reg(), Operand(right->reg())); |
| + enter()->Branch(zero, left, right); |
| + // Divide edx:eax by the right operand. |
| + __ idiv(right->reg()); |
| + |
| + // Complete the operation. |
| + if (op_ == Token::DIV) { |
| + // Check for negative zero result. If result is zero, and divisor |
| + // is negative, return a floating point negative zero. The |
| + // virtual frame is unchanged in this block, so local control flow |
| + // can use a Label rather than a JumpTarget. |
| + Label non_zero_result; |
| + __ test(left->reg(), Operand(left->reg())); |
| + __ j(not_zero, &non_zero_result); |
| + __ test(right->reg(), Operand(right->reg())); |
| + enter()->Branch(negative, left, right); |
| + __ bind(&non_zero_result); |
| + // Check for the corner case of dividing the most negative smi by |
| + // -1. We cannot use the overflow flag, since it is not set by |
| + // idiv instruction. |
| + ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| + __ cmp(quotient.reg(), 0x40000000); |
| + enter()->Branch(equal, left, right); |
| + // Check that the remainder is zero. |
| + __ test(remainder.reg(), Operand(remainder.reg())); |
| + enter()->Branch(not_zero, left, right); |
| + left->Unuse(); |
| + right->Unuse(); |
| + // Tag the result and store it in the quotient register. |
| + ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| + __ lea(quotient.reg(), |
| + Operand(quotient.reg(), quotient.reg(), times_1, kSmiTag)); |
| + return quotient; |
| + } else { |
| + ASSERT(op_ == Token::MOD); |
| + // Check for a negative zero result. If the result is zero, and |
| + // the dividend is negative, return a floating point negative |
| + // zero. The frame is unchanged in this block, so local control |
| + // flow can use a Label rather than a JumpTarget. |
| + Label non_zero_result; |
| + __ test(remainder.reg(), Operand(remainder.reg())); |
| + __ j(not_zero, &non_zero_result, taken); |
| + __ test(left->reg(), Operand(left->reg())); |
| + enter()->Branch(negative, left, right); |
| + left->Unuse(); |
| + right->Unuse(); |
| + __ bind(&non_zero_result); |
| + return remainder; |
| + } |
| + } |
| + |
| + // 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. |
| + // 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. |
| Result answer = cgen()->allocator()->Allocate(); |
| ASSERT(answer.is_valid()); |
| - // Perform the smi check. |
| + // Perform the smi tag check. |
| if (left->reg().is(right->reg())) { |
| __ test(left->reg(), Immediate(kSmiTagMask)); |
| } else { |
| __ mov(answer.reg(), left->reg()); |
| __ or_(answer.reg(), Operand(right->reg())); |
| - ASSERT(kSmiTag == 0); // adjust zero check if not the case |
| + ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| __ test(answer.reg(), Immediate(kSmiTagMask)); |
| } |
| switch (op_) { |
| @@ -5765,7 +5896,7 @@ |
| SetEntryFrame(left, right); |
| enter()->Branch(not_zero, left, right, not_taken); |
| __ mov(answer.reg(), left->reg()); |
| - __ add(answer.reg(), Operand(right->reg())); // add optimistically |
| + __ add(answer.reg(), Operand(right->reg())); // Add optimistically. |
| enter()->Branch(overflow, left, right, not_taken); |
| break; |
| @@ -5773,7 +5904,7 @@ |
| SetEntryFrame(left, right); |
| enter()->Branch(not_zero, left, right, not_taken); |
| __ mov(answer.reg(), left->reg()); |
| - __ sub(answer.reg(), Operand(right->reg())); // subtract optimistically |
| + __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically. |
| enter()->Branch(overflow, left, right, not_taken); |
| break; |
| @@ -5782,18 +5913,18 @@ |
| enter()->Branch(not_zero, left, right, not_taken); |
| __ mov(answer.reg(), left->reg()); |
| // If the smi tag is 0 we can just leave the tag on one operand. |
| - ASSERT(kSmiTag == 0); // adjust code below if not the case |
| - // Remove tag from the left operand (but keep sign). |
| - // Left hand operand has been copied into answer. |
| + ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
| + // Remove smi tag from the left operand (but keep sign). |
| + // Left-hand operand has been copied into answer. |
| __ sar(answer.reg(), kSmiTagSize); |
| // Do multiplication of smis, leaving result in answer. |
| __ imul(answer.reg(), Operand(right->reg())); |
| // Go slow on overflows. |
| enter()->Branch(overflow, left, right, not_taken); |
| - // Check for negative zero result. If product is zero, |
| - // and one argument is negative, go to slow case. |
| - // The frame is unchanged in this block, so local control flow can |
| - // use a Label rather than a JumpTarget. |
| + // Check for negative zero result. If product is zero, and one |
| + // argument is negative, go to slow case. The frame is unchanged |
| + // in this block, so local control flow can use a Label rather |
| + // than a JumpTarget. |
| Label non_zero_result; |
| __ test(answer.reg(), Operand(answer.reg())); |
| __ j(not_zero, &non_zero_result, taken); |
| @@ -5805,146 +5936,6 @@ |
| break; |
| } |
| - case Token::DIV: // Fall through. |
| - case Token::MOD: { |
| - enter()->Branch(not_zero, left, right, not_taken); |
| - __ mov(answer.reg(), left->reg()); |
| - // Div and mod use the registers eax and edx. Left and right must |
| - // be preserved, because the original operands are needed if we switch |
| - // to the slow case. Move them if either is in eax or edx. |
| - // The Result answer should be changed into an alias for eax. |
| - // Precondition: |
| - // The Results left and right are valid. They may be the same register, |
| - // and may be unspilled. The Result answer is valid and is distinct |
| - // from left and right, and is spilled. |
| - // The value in left is copied to answer. |
| - |
| - Result reg_eax = cgen()->allocator()->Allocate(eax); |
| - Result reg_edx = cgen()->allocator()->Allocate(edx); |
| - // These allocations may have failed, if one of left, right, or answer |
| - // is in register eax or edx. |
| - bool left_copied_to_eax = false; // We will make sure this becomes true. |
| - |
| - // Part 1: Get eax |
| - if (answer.reg().is(eax)) { |
| - reg_eax = answer; |
| - left_copied_to_eax = true; |
| - } else if (right->reg().is(eax) || left->reg().is(eax)) { |
| - // We need a non-edx register to move one or both of left and right to. |
| - // We use answer if it is not edx, otherwise we allocate one. |
| - if (answer.reg().is(edx)) { |
| - reg_edx = answer; |
| - answer = cgen()->allocator()->Allocate(); |
| - ASSERT(answer.is_valid()); |
| - } |
| - |
| - if (left->reg().is(eax)) { |
| - reg_eax = *left; |
| - left_copied_to_eax = true; |
| - *left = answer; |
| - } |
| - if (right->reg().is(eax)) { |
| - reg_eax = *right; |
| - *right = answer; |
| - } |
| - __ mov(answer.reg(), eax); |
| - } |
| - // End of Part 1. |
| - // reg_eax is valid, and neither left nor right is in eax. |
| - ASSERT(reg_eax.is_valid()); |
| - ASSERT(!left->reg().is(eax)); |
| - ASSERT(!right->reg().is(eax)); |
| - |
| - // Part 2: Get edx |
| - // reg_edx is invalid if and only if either left, right, |
| - // or answer is in edx. If edx is valid, then either edx |
| - // was free, or it was answer, but answer was reallocated. |
| - if (answer.reg().is(edx)) { |
| - reg_edx = answer; |
| - } else if (right->reg().is(edx) || left->reg().is(edx)) { |
| - // Is answer used? |
| - if (answer.reg().is(eax) || answer.reg().is(left->reg()) || |
| - answer.reg().is(right->reg())) { |
| - answer = cgen()->allocator()->Allocate(); |
| - ASSERT(answer.is_valid()); // We cannot hit both Allocate() calls. |
| - } |
| - if (left->reg().is(edx)) { |
| - reg_edx = *left; |
| - *left = answer; |
| - } |
| - if (right->reg().is(edx)) { |
| - reg_edx = *right; |
| - *right = answer; |
| - } |
| - __ mov(answer.reg(), edx); |
| - } |
| - // End of Part 2 |
| - ASSERT(reg_edx.is_valid()); |
| - ASSERT(!left->reg().is(eax)); |
| - ASSERT(!right->reg().is(eax)); |
| - |
| - answer = reg_eax; // May free answer, if it was never used. |
| - cgen()->frame()->Spill(eax); |
| - if (!left_copied_to_eax) { |
| - __ mov(eax, left->reg()); |
| - left_copied_to_eax = true; |
| - } |
| - cgen()->frame()->Spill(edx); |
| - |
| - // Postcondition: |
| - // reg_eax, reg_edx are valid, correct, and spilled. |
| - // reg_eax contains the value originally in left |
| - // left and right are not eax or edx. They may or may not be |
| - // spilled or distinct. |
| - // answer is an alias for reg_eax. |
| - |
| - // Sign extend eax into edx:eax. |
| - __ cdq(); |
| - // Check for 0 divisor. |
| - __ test(right->reg(), Operand(right->reg())); |
| - enter()->Branch(zero, left, right, not_taken); |
| - // Divide edx:eax by the right operand. |
| - __ idiv(right->reg()); |
| - if (op_ == Token::DIV) { |
| - // Check for negative zero result. If result is zero, and divisor |
| - // is negative, return a floating point negative zero. |
| - // The frame is unchanged in this block, so local control flow can |
| - // use a Label rather than a JumpTarget. |
| - Label non_zero_result; |
| - __ test(left->reg(), Operand(left->reg())); |
| - __ j(not_zero, &non_zero_result, taken); |
| - __ test(right->reg(), Operand(right->reg())); |
| - enter()->Branch(negative, left, right, not_taken); |
| - __ bind(&non_zero_result); |
| - // Check for the corner case of dividing the most negative smi |
| - // by -1. We cannot use the overflow flag, since it is not set |
| - // by idiv instruction. |
| - ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| - __ cmp(eax, 0x40000000); |
| - enter()->Branch(equal, left, right, not_taken); |
| - // Check that the remainder is zero. |
| - __ test(edx, Operand(edx)); |
| - enter()->Branch(not_zero, left, right, not_taken); |
| - // Tag the result and store it in register temp. |
| - ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| - __ lea(answer.reg(), Operand(eax, eax, times_1, kSmiTag)); |
| - } else { |
| - ASSERT(op_ == Token::MOD); |
| - // Check for a negative zero result. If the result is zero, and the |
| - // dividend is negative, return a floating point negative zero. |
| - // The frame is unchanged in this block, so local control flow can |
| - // use a Label rather than a JumpTarget. |
| - Label non_zero_result; |
| - __ test(edx, Operand(edx)); |
| - __ j(not_zero, &non_zero_result, taken); |
| - __ test(left->reg(), Operand(left->reg())); |
| - enter()->Branch(negative, left, right, not_taken); |
| - __ bind(&non_zero_result); |
| - // The answer is in edx. |
| - answer = reg_edx; |
| - } |
| - break; |
| - } |
| case Token::BIT_OR: |
| enter()->Branch(not_zero, left, right, not_taken); |
| __ mov(answer.reg(), left->reg()); |