Add static analysis to AST expressions that records whether a negative zero will...
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 14:03:36 +0000 (14:03 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 14:03:36 +0000 (14:03 +0000)
Review URL: http://codereview.chromium.org/965001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4130 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ast.h
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/rewriter.cc

index 0d654b19c86d986b901d9eed9b33c190945df1ce..9377f5e0880186bdba321413f2bc7f458e93939f 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -251,6 +251,14 @@ class Expression: public AstNode {
     bitfields_ |= SideEffectFreeField::encode(is_side_effect_free);
   }
 
+  // Will the use of this expression treat -0 the same as 0 in all cases?
+  // If so, we can return 0 instead of -0 if we want to, to optimize code.
+  bool no_negative_zero() { return NoNegativeZeroField::decode(bitfields_); }
+  void set_no_negative_zero(bool no_negative_zero) {
+    bitfields_ &= ~NoNegativeZeroField::mask();
+    bitfields_ |= NoNegativeZeroField::encode(no_negative_zero);
+  }
+
   // Will ToInt32 (ECMA 262-3 9.5) or ToUint32 (ECMA 262-3 9.6)
   // be applied to the value of this expression?
   // If so, we may be able to optimize the calculation of the value.
@@ -270,7 +278,8 @@ class Expression: public AstNode {
 
   // Using template BitField<type, start, size>.
   class SideEffectFreeField : public BitField<bool, 0, 1> {};
-  class ToInt32Field : public BitField<bool, 1, 1> {};
+  class NoNegativeZeroField : public BitField<bool, 1, 1> {};
+  class ToInt32Field : public BitField<bool, 2, 1> {};
 };
 
 
index 703fffe07ed4a96f4812469cf59c28b1ebe975af..832e773bed7b4ff3845182a595d3d40562ff7592 100644 (file)
@@ -1102,7 +1102,8 @@ static NumberInfo CalculateNumberInfo(NumberInfo operands_type,
 
 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 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
     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 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
         (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 @@ static void CheckTwoForSminess(MacroAssembler* masm,
 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 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
       // 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 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
       // 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 @@ Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
       // 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 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
                                                  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 CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
     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 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
       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 @@ Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
       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 CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
         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 CodeGenerator::ConstantSmiBinaryOperation(Token::Value op,
       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 @@ void CodeGenerator::EmitSlotAssignment(Assignment* node) {
          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 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
          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 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
          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 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
       Load(node->left());
       Load(node->right());
     }
-    GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
+    GenericBinaryOperation(node->op(), node->type(),
+                           overwrite_mode, node->no_negative_zero());
   }
 }
 
index f7ec0b580ef5ef9d1f5d2e47ec827f97c8f7bbd3..5f474d27b7a712021fc1af0d23f7d1c238ebc8e6 100644 (file)
@@ -469,7 +469,8 @@ class CodeGenerator: public AstVisitor {
   void GenericBinaryOperation(
       Token::Value op,
       StaticType* type,
-      OverwriteMode overwrite_mode);
+      OverwriteMode overwrite_mode,
+      bool no_negative_zero);
 
   // If possible, combine two constant smi values using op to produce
   // a smi result, and push it on the virtual frame, all at compile time.
@@ -483,7 +484,8 @@ class CodeGenerator: public AstVisitor {
                                     Handle<Object> constant_operand,
                                     StaticType* type,
                                     bool reversed,
-                                    OverwriteMode overwrite_mode);
+                                    OverwriteMode overwrite_mode,
+                                    bool no_negative_zero);
 
   // Emit code to perform a binary operation on two likely smis.
   // The code to handle smi arguments is produced inline.
@@ -491,7 +493,8 @@ class CodeGenerator: public AstVisitor {
   Result LikelySmiBinaryOperation(Token::Value op,
                                   Result* left,
                                   Result* right,
-                                  OverwriteMode overwrite_mode);
+                                  OverwriteMode overwrite_mode,
+                                  bool no_negative_zero);
 
   void Comparison(AstNode* node,
                   Condition cc,
index 8a3221280cf673a5489dec1bfcd2adc352e5941c..0f40623e6be497c34083fe778c3fe8cdde880ba3 100644 (file)
@@ -220,6 +220,7 @@ void AstOptimizer::VisitFunctionBoilerplateLiteral(
 
 
 void AstOptimizer::VisitConditional(Conditional* node) {
+  node->condition()->set_no_negative_zero(true);
   Visit(node->condition());
   Visit(node->then_expression());
   Visit(node->else_expression());
@@ -319,6 +320,7 @@ void AstOptimizer::VisitAssignment(Assignment* node) {
       node->type()->SetAsLikelySmiIfUnknown();
       node->target()->type()->SetAsLikelySmiIfUnknown();
       node->value()->type()->SetAsLikelySmiIfUnknown();
+      node->value()->set_no_negative_zero(true);
       break;
     case Token::ASSIGN_ADD:
     case Token::ASSIGN_SUB:
@@ -393,6 +395,7 @@ void AstOptimizer::VisitThrow(Throw* node) {
 
 
 void AstOptimizer::VisitProperty(Property* node) {
+  node->key()->set_no_negative_zero(true);
   Visit(node->obj());
   Visit(node->key());
 }
@@ -422,6 +425,11 @@ void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
 
 
 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
+  if (node->op() == Token::ADD || node->op() == Token::SUB) {
+    node->expression()->set_no_negative_zero(node->no_negative_zero());
+  } else {
+    node->expression()->set_no_negative_zero(true);
+  }
   Visit(node->expression());
   if (FLAG_safe_int32_compiler) {
     switch (node->op()) {
@@ -449,6 +457,9 @@ void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
 
 void AstOptimizer::VisitCountOperation(CountOperation* node) {
   // Count operations assume that they work on Smis.
+  node->expression()->set_no_negative_zero(node->is_prefix() ?
+                                           true :
+                                           node->no_negative_zero());
   node->type()->SetAsLikelySmiIfUnknown();
   node->expression()->type()->SetAsLikelySmiIfUnknown();
   Visit(node->expression());
@@ -461,7 +472,12 @@ void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
   switch (node->op()) {
     case Token::COMMA:
     case Token::OR:
+      node->left()->set_no_negative_zero(true);
+      node->right()->set_no_negative_zero(node->no_negative_zero());
+      break;
     case Token::AND:
+      node->left()->set_no_negative_zero(node->no_negative_zero());
+      node->right()->set_no_negative_zero(node->no_negative_zero());
       break;
     case Token::BIT_OR:
     case Token::BIT_XOR:
@@ -474,6 +490,8 @@ void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
       node->right()->type()->SetAsLikelySmiIfUnknown();
       node->left()->set_to_int32(true);
       node->right()->set_to_int32(true);
+      node->left()->set_no_negative_zero(true);
+      node->right()->set_no_negative_zero(true);
       break;
     case Token::ADD:
     case Token::SUB:
@@ -484,6 +502,13 @@ void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
         node->left()->type()->SetAsLikelySmiIfUnknown();
         node->right()->type()->SetAsLikelySmiIfUnknown();
       }
+      node->left()->set_no_negative_zero(node->no_negative_zero());
+      node->right()->set_no_negative_zero(node->no_negative_zero());
+      if (node->op() == Token::DIV) {
+        node->right()->set_no_negative_zero(false);
+      } else if (node->op() == Token::MOD) {
+        node->right()->set_no_negative_zero(true);
+      }
       break;
     default:
       UNREACHABLE();
@@ -551,6 +576,10 @@ void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
     node->right()->type()->SetAsLikelySmiIfUnknown();
   }
 
+  node->left()->set_no_negative_zero(true);
+  // Only [[HasInstance]] has the right argument passed unchanged to it.
+  node->right()->set_no_negative_zero(true);
+
   Visit(node->left());
   Visit(node->right());