Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 4129) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -1102,7 +1102,8 @@ |
void CodeGenerator::GenericBinaryOperation(Token::Value op, |
StaticType* type, |
- OverwriteMode overwrite_mode) { |
+ OverwriteMode overwrite_mode, |
+ bool no_negative_zero) { |
Comment cmnt(masm_, "[ BinaryOperation"); |
Comment cmnt_token(masm_, Token::String(op)); |
@@ -1170,10 +1171,12 @@ |
answer = stub.GenerateCall(masm_, frame_, &left, &right); |
} else if (right_is_smi_constant) { |
answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
- type, false, overwrite_mode); |
+ type, false, overwrite_mode, |
+ no_negative_zero); |
} else if (left_is_smi_constant) { |
answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
- type, true, overwrite_mode); |
+ type, true, overwrite_mode, |
+ no_negative_zero); |
} else { |
// Set the flags based on the operation, type and loop nesting level. |
// Bit operations always assume they likely operate on Smis. Still only |
@@ -1184,7 +1187,8 @@ |
(Token::IsBitOp(op) || |
operands_type.IsInteger32() || |
type->IsLikelySmi())) { |
- answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
+ answer = LikelySmiBinaryOperation(op, &left, &right, |
+ overwrite_mode, no_negative_zero); |
} else { |
GenericBinaryOpStub stub(op, |
overwrite_mode, |
@@ -1291,7 +1295,8 @@ |
Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
Result* left, |
Result* right, |
- OverwriteMode overwrite_mode) { |
+ OverwriteMode overwrite_mode, |
+ bool no_negative_zero) { |
Result answer; |
// Special handling of div and mod because they use fixed registers. |
if (op == Token::DIV || op == Token::MOD) { |
@@ -1395,13 +1400,16 @@ |
// 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->Branch(negative); |
- __ bind(&non_zero_result); |
+ // can use a Label rather than a JumpTarget. If the context of this |
+ // expression will treat -0 like 0, do not do this test. |
+ if (!no_negative_zero) { |
+ Label non_zero_result; |
+ __ test(left->reg(), Operand(left->reg())); |
+ __ j(not_zero, &non_zero_result); |
+ __ test(right->reg(), Operand(right->reg())); |
+ deferred->Branch(negative); |
+ __ 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. |
@@ -1423,12 +1431,14 @@ |
// 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())); |
- deferred->Branch(negative); |
- __ bind(&non_zero_result); |
+ if (!no_negative_zero) { |
+ Label non_zero_result; |
+ __ test(edx, Operand(edx)); |
+ __ j(not_zero, &non_zero_result, taken); |
+ __ test(left->reg(), Operand(left->reg())); |
+ deferred->Branch(negative); |
+ __ bind(&non_zero_result); |
+ } |
deferred->BindExit(); |
left->Unuse(); |
right->Unuse(); |
@@ -1571,14 +1581,16 @@ |
// 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->Branch(negative); |
- __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. |
- __ bind(&non_zero_result); |
+ if (!no_negative_zero) { |
+ 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->Branch(negative); |
+ __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. |
+ __ bind(&non_zero_result); |
+ } |
break; |
} |
@@ -1817,7 +1829,8 @@ |
Handle<Object> value, |
StaticType* type, |
bool reversed, |
- OverwriteMode overwrite_mode) { |
+ OverwriteMode overwrite_mode, |
+ bool no_negative_zero) { |
// NOTE: This is an attempt to inline (a bit) more of the code for |
// some possible smi operations (like + and -) when (at least) one |
// of the operands is a constant smi. |
@@ -1828,10 +1841,10 @@ |
Result unsafe_operand(value); |
if (reversed) { |
return LikelySmiBinaryOperation(op, &unsafe_operand, operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} else { |
return LikelySmiBinaryOperation(op, operand, &unsafe_operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} |
} |
@@ -1911,7 +1924,7 @@ |
if (reversed) { |
Result constant_operand(value); |
answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} else { |
// Only the least significant 5 bits of the shift value are used. |
// In the slow case, this masking is done inside the runtime call. |
@@ -1947,7 +1960,7 @@ |
if (reversed) { |
Result constant_operand(value); |
answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} else { |
// Only the least significant 5 bits of the shift value are used. |
// In the slow case, this masking is done inside the runtime call. |
@@ -2140,10 +2153,10 @@ |
Result constant_operand(value); |
if (reversed) { |
answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} else { |
answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} |
} |
break; |
@@ -2180,10 +2193,10 @@ |
Result constant_operand(value); |
if (reversed) { |
answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} else { |
answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
- overwrite_mode); |
+ overwrite_mode, no_negative_zero); |
} |
break; |
} |
@@ -4950,7 +4963,8 @@ |
node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
GenericBinaryOperation(node->binary_op(), |
node->type(), |
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
+ node->no_negative_zero()); |
} else { |
Load(node->value()); |
} |
@@ -5027,7 +5041,8 @@ |
node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
GenericBinaryOperation(node->binary_op(), |
node->type(), |
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
+ node->no_negative_zero()); |
} else { |
Load(node->value()); |
} |
@@ -5106,7 +5121,8 @@ |
node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
GenericBinaryOperation(node->binary_op(), |
node->type(), |
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
+ node->no_negative_zero()); |
} else { |
Load(node->value()); |
} |
@@ -6868,7 +6884,8 @@ |
Load(node->left()); |
Load(node->right()); |
} |
- GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
+ GenericBinaryOperation(node->op(), node->type(), |
+ overwrite_mode, node->no_negative_zero()); |
} |
} |