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

Unified 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, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
« 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