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

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

Issue 118157: Refactor IA32 shift operations to simplify moving the right operand... (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 2093)
+++ src/ia32/codegen-ia32.cc (working copy)
@@ -779,8 +779,7 @@
// Call the specialized stub for a binary operation.
class DeferredInlineBinaryOperation: public DeferredCode {
public:
- DeferredInlineBinaryOperation(Token::Value op,
- OverwriteMode mode)
+ DeferredInlineBinaryOperation(Token::Value op, OverwriteMode mode)
: op_(op), mode_(mode) {
set_comment("[ DeferredInlineBinaryOperation");
}
@@ -1001,8 +1000,8 @@
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);
@@ -1148,12 +1147,98 @@
return;
}
+ // Special handling of shift operations because they use fixed
+ // registers.
+ if (op == Token::SHL || op == Token::SHR || op == Token::SAR) {
+ // Move left out of ecx if necessary.
+ if (left->is_register() && left->reg().is(ecx)) {
+ *left = allocator_->Allocate();
+ ASSERT(left->is_valid());
+ __ mov(left->reg(), ecx);
+ }
+ right->ToRegister(ecx);
+ left->ToRegister();
+ ASSERT(left->is_register() && !left->reg().is(ecx));
+ ASSERT(right->is_register() && right->reg().is(ecx));
+
+ // We will modify right, it must be spilled.
+ frame_->Spill(ecx);
+
+ // Use a fresh answer register to avoid spilling the left operand.
+ Result answer = allocator_->Allocate();
+ ASSERT(answer.is_valid());
+ // Check that both operands are smis using the answer register as a
+ // temporary.
+ __ mov(answer.reg(), left->reg());
+ __ or_(answer.reg(), Operand(ecx));
+ __ test(answer.reg(), Immediate(kSmiTagMask));
+ deferred->enter()->Branch(not_zero, left, right);
+
+ // Untag both operands.
+ __ mov(answer.reg(), left->reg());
+ __ sar(answer.reg(), kSmiTagSize);
+ __ sar(ecx, kSmiTagSize);
+ // Perform the operation.
+ switch (op) {
+ case Token::SAR:
+ __ sar(answer.reg());
+ // No checks of result necessary
+ break;
+ case Token::SHR: {
+ JumpTarget result_ok;
+ __ shr(answer.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
William Hesse 2009/06/03 12:12:04 // Smi tagging. These two cases can..
+ // 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.
+ __ test(answer.reg(), Immediate(0xc0000000));
+ result_ok.Branch(zero, &answer);
+ ASSERT(kSmiTag == 0);
+ __ shl(ecx, kSmiTagSize);
+ answer.Unuse();
+ deferred->enter()->Jump(left, right);
+ result_ok.Bind(&answer);
+ break;
+ }
+ case Token::SHL: {
+ JumpTarget result_ok;
+ __ shl(answer.reg());
+ // Check that the *signed* result fits in a smi.
+ __ cmp(answer.reg(), 0xc0000000);
+ result_ok.Branch(positive, &answer);
+ ASSERT(kSmiTag == 0);
+ __ shl(ecx, kSmiTagSize);
+ answer.Unuse();
+ deferred->enter()->Jump(left, right);
+ result_ok.Bind(&answer);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ left->Unuse();
+ right->Unuse();
+ // Smi-tag the result in answer.
+ ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
+ __ lea(answer.reg(),
+ Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
+ deferred->BindExit(&answer);
+ frame_->Push(&answer);
+ 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.
+ // registers containing left and right are not modified so they don't
+ // need to be spilled in the fast case.
Result answer = allocator_->Allocate();
ASSERT(answer.is_valid());
@@ -1229,109 +1314,6 @@
__ 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;
« 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