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

Unified Diff: src/ia32/codegen-ia32.cc

Issue 119037: As a simplification, manually inline the function... (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 2087)
+++ src/ia32/codegen-ia32.cc (working copy)
@@ -776,27 +776,20 @@
}
-// A deferred code class implementing binary operations on likely smis.
-// This class generates both inline code and deferred code.
-// The fastest path is implemented inline. Deferred code calls
-// the GenericBinaryOpStub stub for slow cases.
+// Call the specialized stub for a binary operation.
class DeferredInlineBinaryOperation: public DeferredCode {
public:
DeferredInlineBinaryOperation(Token::Value op,
- OverwriteMode mode,
- GenericBinaryFlags flags)
- : stub_(op, mode, flags), op_(op) {
+ OverwriteMode mode)
+ : op_(op), mode_(mode) {
set_comment("[ DeferredInlineBinaryOperation");
}
- // Consumes its arguments, left and right, leaving them invalid.
- Result GenerateInlineCode(Result* left, Result* right);
-
virtual void Generate();
private:
- GenericBinaryOpStub stub_;
Token::Value op_;
+ OverwriteMode mode_;
};
@@ -806,7 +799,8 @@
enter()->Bind(&left, &right);
cgen()->frame()->Push(&left);
cgen()->frame()->Push(&right);
- Result answer = cgen()->frame()->CallStub(&stub_, 2);
+ GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED);
+ Result answer = cgen()->frame()->CallStub(&stub, 2);
exit_.Jump(&answer);
}
@@ -1007,13 +1001,343 @@
Result* left,
Result* right,
OverwriteMode overwrite_mode) {
- // Implements a binary operation using a deferred code object
- // and some inline code to operate on smis quickly.
+ // Implements a binary operation using a deferred code object and
+ // some inline code to operate on smis quickly.
DeferredInlineBinaryOperation* deferred =
- new DeferredInlineBinaryOperation(op, overwrite_mode, SMI_CODE_INLINED);
- // Generate the inline code that handles some smi operations,
- // and jumps to the deferred code for everything else.
- Result answer = deferred->GenerateInlineCode(left, right);
+ new DeferredInlineBinaryOperation(op, overwrite_mode);
+
+ // 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 = allocator_->Allocate();
+ ASSERT(fresh.is_valid());
+ if (fresh.reg().is(edx)) {
+ remainder = fresh;
+ fresh = 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 = 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_valid()) {
+ if ((left->is_register() && left->reg().is(edx)) ||
+ (right->is_register() && right->reg().is(edx))) {
+ Result fresh = 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 = 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();
+ frame_->Spill(quotient.reg());
+ 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));
+ }
+ deferred->SetEntryFrame(left, right);
+ deferred->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()));
+ deferred->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()));
+ deferred->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);
+ deferred->enter()->Branch(equal, left, right);
+ // Check that the remainder is zero.
+ __ test(remainder.reg(), Operand(remainder.reg()));
+ remainder.Unuse();
+ deferred->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));
+ deferred->BindExit(&quotient);
+ frame_->Push(&quotient);
+ } else {
+ ASSERT(op == Token::MOD);
+ quotient.Unuse();
+ // 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()));
+ deferred->enter()->Branch(negative, left, right);
+ left->Unuse();
+ right->Unuse();
+ __ bind(&non_zero_result);
+ deferred->BindExit(&remainder);
+ frame_->Push(&remainder);
+ }
+ return;
+ }
+
+ // 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.
+ Result answer = allocator_->Allocate();
+
+ ASSERT(answer.is_valid());
+ // 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 test if not the case.
+ __ test(answer.reg(), Immediate(kSmiTagMask));
+ }
+ switch (op) {
+ case Token::ADD:
+ deferred->SetEntryFrame(left, right);
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ __ add(answer.reg(), Operand(right->reg())); // Add optimistically.
+ deferred->enter()->Branch(overflow, left, right, not_taken);
+ break;
+
+ case Token::SUB:
+ deferred->SetEntryFrame(left, right);
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically.
+ deferred->enter()->Branch(overflow, left, right, not_taken);
+ break;
+
+ case Token::MUL: {
+ deferred->SetEntryFrame(left, right);
+ deferred->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 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.
+ deferred->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.
+ Label non_zero_result;
+ __ test(answer.reg(), Operand(answer.reg()));
+ __ j(not_zero, &non_zero_result, taken);
+ __ mov(answer.reg(), left->reg());
+ __ or_(answer.reg(), Operand(right->reg()));
+ deferred->enter()->Branch(negative, left, right, not_taken);
+ __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
+ __ bind(&non_zero_result);
+ break;
+ }
+
+ case Token::BIT_OR:
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ __ or_(answer.reg(), Operand(right->reg()));
+ break;
+
+ case Token::BIT_AND:
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ __ and_(answer.reg(), Operand(right->reg()));
+ break;
+
+ case Token::BIT_XOR:
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ __ xor_(answer.reg(), Operand(right->reg()));
+ break;
+
+ case Token::SHL:
+ case Token::SHR:
+ case Token::SAR:
+ deferred->enter()->Branch(not_zero, left, right, not_taken);
+ __ mov(answer.reg(), left->reg());
+ // Move right into ecx.
+ // Left is in two registers already, so even if left or answer is ecx,
+ // we can move right to it, and use the other one.
+ // Right operand must be in register cl because x86 likes it that way.
+ if (right->reg().is(ecx)) {
+ // Right is already in the right place. Left may be in the
+ // same register, which causes problems. Always use answer
+ // instead of left, even if left is not ecx, since this avoids
+ // spilling left.
+ *left = answer;
+ } else if (left->reg().is(ecx)) {
+ frame_->Spill(left->reg());
+ __ mov(left->reg(), right->reg());
+ *right = *left;
+ *left = answer; // Use copy of left in answer as left.
+ } else if (answer.reg().is(ecx)) {
+ __ mov(answer.reg(), right->reg());
+ *right = answer;
+ } else {
+ Result reg_ecx = allocator_->Allocate(ecx);
+ ASSERT(reg_ecx.is_valid());
+ __ mov(ecx, right->reg());
+ *right = reg_ecx;
+ // Answer and left both contain the left operand. Use answer, so
+ // left is not spilled.
+ *left = answer;
+ }
+ ASSERT(left->reg().is_valid());
+ ASSERT(!left->reg().is(ecx));
+ ASSERT(right->reg().is(ecx));
+ answer.Unuse(); // Answer may now be being used for left or right.
+ // We will modify left and right, which we do not do in any other
+ // binary operation. The exits to slow code need to restore the
+ // original values of left and right, or at least values that give
+ // the same answer.
+
+ // We are modifying left and right. They must be spilled!
+ frame_->Spill(left->reg());
+ frame_->Spill(right->reg());
+
+ // Remove tags from operands (but keep sign).
+ __ sar(left->reg(), kSmiTagSize);
+ __ sar(ecx, kSmiTagSize);
+ // Perform the operation.
+ switch (op) {
+ case Token::SAR:
+ __ sar(left->reg());
+ // No checks of result necessary
+ break;
+ case Token::SHR: {
+ __ shr(left->reg());
+ // Check that the *unsigned* result fits in a smi.
+ // Neither of the two high-order bits can be set:
+ // - 0x80000000: high bit would be lost when smi tagging.
+ // - 0x40000000: this number would convert to negative when
+ // Smi tagging these two cases can only happen with shifts
+ // by 0 or 1 when handed a valid smi.
+ // If the answer cannot be represented by a SMI, restore
+ // the left and right arguments, and jump to slow case.
+ // The low bit of the left argument may be lost, but only
+ // in a case where it is dropped anyway.
+ JumpTarget result_ok;
+ __ test(left->reg(), Immediate(0xc0000000));
+ result_ok.Branch(zero, left, taken);
+ __ shl(left->reg());
+ ASSERT(kSmiTag == 0);
+ __ shl(left->reg(), kSmiTagSize);
+ __ shl(right->reg(), kSmiTagSize);
+ deferred->enter()->Jump(left, right);
+ result_ok.Bind(left);
+ break;
+ }
+ case Token::SHL: {
+ __ shl(left->reg());
+ // Check that the *signed* result fits in a smi.
+ JumpTarget result_ok;
+ __ cmp(left->reg(), 0xc0000000);
+ result_ok.Branch(positive, left, taken);
+
+ __ shr(left->reg());
+ ASSERT(kSmiTag == 0);
+ __ shl(left->reg(), kSmiTagSize);
+ __ shl(right->reg(), kSmiTagSize);
+ deferred->enter()->Jump(left, right);
+ result_ok.Bind(left);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ // Smi-tag the result, in left, and make answer an alias for left->
+ answer = *left;
+ answer.ToRegister();
+ ASSERT(kSmiTagSize == times_2); // adjust code if not the case
+ __ lea(answer.reg(),
+ Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ left->Unuse();
+ right->Unuse();
deferred->BindExit(&answer);
frame_->Push(&answer);
}
@@ -5732,341 +6056,6 @@
}
-Result DeferredInlineBinaryOperation::GenerateInlineCode(Result* left,
- Result* right) {
- MacroAssembler* masm = cgen()->masm();
-
- // 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_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.
- Result answer = cgen()->allocator()->Allocate();
-
- ASSERT(answer.is_valid());
- // 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 test if not the case.
- __ test(answer.reg(), Immediate(kSmiTagMask));
- }
- switch (op_) {
- case Token::ADD:
- SetEntryFrame(left, right);
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- __ add(answer.reg(), Operand(right->reg())); // Add optimistically.
- enter()->Branch(overflow, left, right, not_taken);
- break;
-
- case Token::SUB:
- SetEntryFrame(left, right);
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically.
- enter()->Branch(overflow, left, right, not_taken);
- break;
-
- case Token::MUL: {
- SetEntryFrame(left, right);
- 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 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.
- Label non_zero_result;
- __ test(answer.reg(), Operand(answer.reg()));
- __ j(not_zero, &non_zero_result, taken);
- __ mov(answer.reg(), left->reg());
- __ or_(answer.reg(), Operand(right->reg()));
- enter()->Branch(negative, left, right, not_taken);
- __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
- __ bind(&non_zero_result);
- break;
- }
-
- case Token::BIT_OR:
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- __ or_(answer.reg(), Operand(right->reg()));
- break;
-
- case Token::BIT_AND:
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- __ and_(answer.reg(), Operand(right->reg()));
- break;
-
- case Token::BIT_XOR:
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- __ xor_(answer.reg(), Operand(right->reg()));
- break;
-
- case Token::SHL:
- case Token::SHR:
- case Token::SAR:
- enter()->Branch(not_zero, left, right, not_taken);
- __ mov(answer.reg(), left->reg());
- // Move right into ecx.
- // Left is in two registers already, so even if left or answer is ecx,
- // we can move right to it, and use the other one.
- // Right operand must be in register cl because x86 likes it that way.
- if (right->reg().is(ecx)) {
- // Right is already in the right place. Left may be in the
- // same register, which causes problems. Always use answer
- // instead of left, even if left is not ecx, since this avoids
- // spilling left.
- *left = answer;
- } else if (left->reg().is(ecx)) {
- cgen()->frame()->Spill(left->reg());
- __ mov(left->reg(), right->reg());
- *right = *left;
- *left = answer; // Use copy of left in answer as left.
- } else if (answer.reg().is(ecx)) {
- __ mov(answer.reg(), right->reg());
- *right = answer;
- } else {
- Result reg_ecx = cgen()->allocator()->Allocate(ecx);
- ASSERT(reg_ecx.is_valid());
- __ mov(ecx, right->reg());
- *right = reg_ecx;
- // Answer and left both contain the left operand. Use answer, so
- // left is not spilled.
- *left = answer;
- }
- ASSERT(left->reg().is_valid());
- ASSERT(!left->reg().is(ecx));
- ASSERT(right->reg().is(ecx));
- answer.Unuse(); // Answer may now be being used for left or right.
- // We will modify left and right, which we do not do in any other
- // binary operation. The exits to slow code need to restore the
- // original values of left and right, or at least values that give
- // the same answer.
-
- // We are modifying left and right. They must be spilled!
- cgen()->frame()->Spill(left->reg());
- cgen()->frame()->Spill(right->reg());
-
- // Remove tags from operands (but keep sign).
- __ sar(left->reg(), kSmiTagSize);
- __ sar(ecx, kSmiTagSize);
- // Perform the operation.
- switch (op_) {
- case Token::SAR:
- __ sar(left->reg());
- // No checks of result necessary
- break;
- case Token::SHR: {
- __ shr(left->reg());
- // Check that the *unsigned* result fits in a smi.
- // Neither of the two high-order bits can be set:
- // - 0x80000000: high bit would be lost when smi tagging.
- // - 0x40000000: this number would convert to negative when
- // Smi tagging these two cases can only happen with shifts
- // by 0 or 1 when handed a valid smi.
- // If the answer cannot be represented by a SMI, restore
- // the left and right arguments, and jump to slow case.
- // The low bit of the left argument may be lost, but only
- // in a case where it is dropped anyway.
- JumpTarget result_ok;
- __ test(left->reg(), Immediate(0xc0000000));
- result_ok.Branch(zero, left, taken);
- __ shl(left->reg());
- ASSERT(kSmiTag == 0);
- __ shl(left->reg(), kSmiTagSize);
- __ shl(right->reg(), kSmiTagSize);
- enter()->Jump(left, right);
- result_ok.Bind(left);
- break;
- }
- case Token::SHL: {
- __ shl(left->reg());
- // Check that the *signed* result fits in a smi.
- JumpTarget result_ok;
- __ cmp(left->reg(), 0xc0000000);
- result_ok.Branch(positive, left, taken);
-
- __ shr(left->reg());
- ASSERT(kSmiTag == 0);
- __ shl(left->reg(), kSmiTagSize);
- __ shl(right->reg(), kSmiTagSize);
- enter()->Jump(left, right);
- result_ok.Bind(left);
- break;
- }
- default:
- UNREACHABLE();
- }
- // Smi-tag the result, in left, and make answer an alias for left->
- answer = *left;
- answer.ToRegister();
- ASSERT(kSmiTagSize == times_2); // adjust code if not the case
- __ lea(answer.reg(),
- Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
- break;
-
- default:
- UNREACHABLE();
- break;
- }
- left->Unuse();
- right->Unuse();
- return answer;
-}
-
-
void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
// Perform fast-case smi code for the operation (eax <op> ebx) and
// leave result in register eax.
« 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