Inlining Math.min and Math.max in crankshaft.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 Jan 2012 15:43:33 +0000 (15:43 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 Jan 2012 15:43:33 +0000 (15:43 +0000)
BUG=v8:1325
TEST=

Review URL: http://codereview.chromium.org/9147034

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

12 files changed:
src/arm/lithium-codegen-arm.cc
src/arm/lithium-codegen-arm.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/objects.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-codegen-x64.h
test/mjsunit/math-min-max.js

index ffc465a..8b96f9b 100644 (file)
@@ -3903,6 +3903,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
 void LCodeGen::EmitNumberUntagD(Register input_reg,
                                 DoubleRegister result_reg,
                                 bool deoptimize_on_undefined,
+                                bool deoptimize_on_minus_zero,
                                 LEnvironment* env) {
   Register scratch = scratch0();
   SwVfpRegister flt_scratch = double_scratch0().low();
@@ -3938,6 +3939,14 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
   // Heap number to double register conversion.
   __ sub(ip, input_reg, Operand(kHeapObjectTag));
   __ vldr(result_reg, ip, HeapNumber::kValueOffset);
+  if (deoptimize_on_minus_zero) {
+    __ vmov(ip, result_reg.low());
+    __ cmp(ip, Operand(0));
+    __ b(ne, &done);
+    __ vmov(ip, result_reg.high());
+    __ cmp(ip, Operand(HeapNumber::kSignMask));
+    DeoptimizeIf(eq, env);
+  }
   __ jmp(&done);
 
   // Smi to double register conversion
@@ -4071,6 +4080,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
 
   EmitNumberUntagD(input_reg, result_reg,
                    instr->hydrogen()->deoptimize_on_undefined(),
+                   instr->hydrogen()->deoptimize_on_minus_zero(),
                    instr->environment());
 }
 
index f04173f..e3cc730 100644 (file)
@@ -273,6 +273,7 @@ class LCodeGen BASE_EMBEDDED {
   void EmitNumberUntagD(Register input,
                         DoubleRegister result,
                         bool deoptimize_on_undefined,
+                        bool deoptimize_on_minus_zero,
                         LEnvironment* env);
 
   // Emits optimized code for typeof x == "y".  Modifies input register.
index 5110868..f9a618b 100644 (file)
@@ -1137,6 +1137,9 @@ class HChange: public HUnaryOperation {
   bool deoptimize_on_undefined() const {
     return CheckFlag(kDeoptimizeOnUndefined);
   }
+  bool deoptimize_on_minus_zero() const {
+    return CheckFlag(kBailoutOnMinusZero);
+  }
   virtual Representation RequiredInputRepresentation(int index) {
     return from();
   }
index 34fd6da..f2d7fe1 100644 (file)
@@ -5140,6 +5140,57 @@ bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
         return true;
       }
       break;
+    case kMathMax:
+    case kMathMin:
+      if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
+        AddCheckConstantFunction(expr, receiver, receiver_map, true);
+        HValue* right = Pop();
+        HValue* left = Pop();
+        // Do not inline if the return representation is not certain.
+        if (!left->representation().Equals(right->representation())) {
+          Push(left);
+          Push(right);
+          return false;
+        }
+
+        Pop();  // Pop receiver.
+        Token::Value op = (id == kMathMin) ? Token::LT : Token::GT;
+        HCompareIDAndBranch* compare = NULL;
+
+        if (left->representation().IsTagged()) {
+          HChange* left_cvt =
+              new(zone()) HChange(left, Representation::Double(), false, true);
+          left_cvt->SetFlag(HValue::kBailoutOnMinusZero);
+          AddInstruction(left_cvt);
+          HChange* right_cvt =
+              new(zone()) HChange(right, Representation::Double(), false, true);
+          right_cvt->SetFlag(HValue::kBailoutOnMinusZero);
+          AddInstruction(right_cvt);
+          compare = new(zone()) HCompareIDAndBranch(left_cvt, right_cvt, op);
+          compare->SetInputRepresentation(Representation::Double());
+        } else {
+          compare = new(zone()) HCompareIDAndBranch(left, right, op);
+          compare->SetInputRepresentation(left->representation());
+        }
+
+        HBasicBlock* return_left = graph()->CreateBasicBlock();
+        HBasicBlock* return_right = graph()->CreateBasicBlock();
+
+        compare->SetSuccessorAt(0, return_left);
+        compare->SetSuccessorAt(1, return_right);
+        current_block()->Finish(compare);
+
+        set_current_block(return_left);
+        Push(left);
+        set_current_block(return_right);
+        Push(right);
+
+        HBasicBlock* join = CreateJoin(return_left, return_right, expr->id());
+        set_current_block(join);
+        ast_context()->ReturnValue(Pop());
+        return true;
+      }
+      break;
     default:
       // Not yet supported for inlining.
       break;
index 537c558..98ef28d 100644 (file)
@@ -3699,8 +3699,10 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
 
 
 void LCodeGen::EmitNumberUntagD(Register input_reg,
+                                Register temp_reg,
                                 XMMRegister result_reg,
                                 bool deoptimize_on_undefined,
+                                bool deoptimize_on_minus_zero,
                                 LEnvironment* env) {
   Label load_smi, done;
 
@@ -3729,6 +3731,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
   }
   // Heap number to XMM conversion.
   __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
+  if (deoptimize_on_minus_zero) {
+    XMMRegister xmm_scratch = xmm0;
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(result_reg, xmm_scratch);
+    __ j(not_zero, &done, Label::kNear);
+    __ movmskpd(temp_reg, result_reg);
+    __ test_b(temp_reg, 1);
+    DeoptimizeIf(not_zero, env);
+  }
   __ jmp(&done, Label::kNear);
 
   // Smi to XMM conversion
@@ -3851,14 +3862,23 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister());
+  LOperand* temp = instr->TempAt(0);
+  ASSERT(temp == NULL || temp->IsRegister());
   LOperand* result = instr->result();
   ASSERT(result->IsDoubleRegister());
 
   Register input_reg = ToRegister(input);
   XMMRegister result_reg = ToDoubleRegister(result);
 
-  EmitNumberUntagD(input_reg, result_reg,
+  bool deoptimize_on_minus_zero =
+      instr->hydrogen()->deoptimize_on_minus_zero();
+  Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
+
+  EmitNumberUntagD(input_reg,
+                   temp_reg,
+                   result_reg,
                    instr->hydrogen()->deoptimize_on_undefined(),
+                   deoptimize_on_minus_zero,
                    instr->environment());
 }
 
index 38d0b3b..4b226e1 100644 (file)
@@ -268,8 +268,10 @@ class LCodeGen BASE_EMBEDDED {
   void EmitGoto(int block);
   void EmitBranch(int left_block, int right_block, Condition cc);
   void EmitNumberUntagD(Register input,
+                        Register temp,
                         XMMRegister result,
                         bool deoptimize_on_undefined,
+                        bool deoptimize_on_minus_zero,
                         LEnvironment* env);
 
   // Emits optimized code for typeof x == "y".  Modifies input register.
index 8f7a28f..8435a3c 100644 (file)
@@ -1682,7 +1682,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
   if (from.IsTagged()) {
     if (to.IsDouble()) {
       LOperand* value = UseRegister(instr->value());
-      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
+      // Temp register only necessary for minus zero check.
+      LOperand* temp = instr->deoptimize_on_minus_zero()
+                       ? TempRegister()
+                       : NULL;
+      LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
       return AssignEnvironment(DefineAsRegister(res));
     } else {
       ASSERT(to.IsInteger32());
index 51809f5..67bf937 100644 (file)
@@ -1624,10 +1624,11 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> {
 };
 
 
-class LNumberUntagD: public LTemplateInstruction<1, 1, 0> {
+class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
  public:
-  explicit LNumberUntagD(LOperand* value) {
+  explicit LNumberUntagD(LOperand* value, LOperand* temp) {
     inputs_[0] = value;
+    temps_[0] = temp;
   }
 
   DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
index 7de7aa7..d53f943 100644 (file)
@@ -4894,7 +4894,9 @@ class Script: public Struct {
   V(Math, exp, MathExp)                             \
   V(Math, sqrt, MathSqrt)                           \
   V(Math, pow, MathPow)                             \
-  V(Math, random, MathRandom)
+  V(Math, random, MathRandom)                       \
+  V(Math, max, MathMax)                             \
+  V(Math, min, MathMin)
 
 
 enum BuiltinFunctionId {
index 1170e89..c9db687 100644 (file)
@@ -3547,6 +3547,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
 void LCodeGen::EmitNumberUntagD(Register input_reg,
                                 XMMRegister result_reg,
                                 bool deoptimize_on_undefined,
+                                bool deoptimize_on_minus_zero,
                                 LEnvironment* env) {
   Label load_smi, done;
 
@@ -3574,6 +3575,15 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
   }
   // Heap number to XMM conversion.
   __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
+  if (deoptimize_on_minus_zero) {
+    XMMRegister xmm_scratch = xmm0;
+    __ xorps(xmm_scratch, xmm_scratch);
+    __ ucomisd(xmm_scratch, result_reg);
+    __ j(not_equal, &done, Label::kNear);
+    __ movmskpd(kScratchRegister, result_reg);
+    __ testq(kScratchRegister, Immediate(1));
+    DeoptimizeIf(not_zero, env);
+  }
   __ jmp(&done, Label::kNear);
 
   // Smi to XMM conversion
@@ -3665,6 +3675,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
 
   EmitNumberUntagD(input_reg, result_reg,
                    instr->hydrogen()->deoptimize_on_undefined(),
+                   instr->hydrogen()->deoptimize_on_minus_zero(),
                    instr->environment());
 }
 
index 5cffb5a..bbdc21e 100644 (file)
@@ -255,6 +255,7 @@ class LCodeGen BASE_EMBEDDED {
   void EmitNumberUntagD(Register input,
                         XMMRegister result,
                         bool deoptimize_on_undefined,
+                        bool deoptimize_on_minus_zero,
                         LEnvironment* env);
 
   // Emits optimized code for typeof x == "y".  Modifies input register.
index 0833c5c..7717b3b 100644 (file)
@@ -115,3 +115,67 @@ assertEquals(NaN, Math.max(1, 'oxen'));
 
 assertEquals(Infinity, 1/Math.max(ZERO, -0));
 assertEquals(Infinity, 1/Math.max(-0, ZERO));
+
+function run(crankshaft_test) {
+  crankshaft_test(1);
+  crankshaft_test(1);
+  %OptimizeFunctionOnNextCall(crankshaft_test);
+  crankshaft_test(-0);
+}
+
+function crankshaft_test_1(arg) {
+  var v1 = 1;
+  var v2 = 5;
+  var v3 = 1.5;
+  var v4 = 5.5;
+  var v5 = 2;
+  var v6 = 6;
+  var v7 = 0;
+  var v8 = -0;
+
+  var v9 = 9.9;
+  var v0 = 10.1;
+  // Integer32 representation.
+  assertEquals(v2, Math.max(v1++, v2++));
+  assertEquals(v1, Math.min(v1++, v2++));
+  // Tagged representation.
+  assertEquals(v4, Math.max(v3, v4));
+  assertEquals(v3, Math.min(v3, v4));
+  assertEquals(v6, Math.max(v5, v6));
+  assertEquals(v5, Math.min(v5, v6));
+  // Double representation.
+  assertEquals(v0, Math.max(v0++, v9++));
+  assertEquals(v9, Math.min(v0++, v9++));
+  // Minus zero.
+  assertEquals(Infinity, 1/Math.max(v7, v8));
+  assertEquals(-Infinity, 1/Math.min(v7, v8));
+  // NaN.
+  assertEquals(NaN, Math.max(NaN, v8));
+  assertEquals(NaN, Math.min(NaN, v9));
+  assertEquals(NaN, Math.max(v8, NaN));
+  assertEquals(NaN, Math.min(v9, NaN));
+  // Minus zero as Integer32.
+  assertEquals((arg === -0) ? -Infinity : 1, 1/Math.min(arg, v2));
+}
+
+run(crankshaft_test_1);
+
+function crankshaft_test_2() {
+  var v9 = {};
+  v9.valueOf = function() { return 6; }
+  // Deopt expected due to non-heapnumber objects.
+  assertEquals(6, Math.min(v9, 12));
+}
+
+run(crankshaft_test_2);
+
+// Test overriding Math.min and Math.max
+Math.min = function(a, b) { return a + b; }
+Math.max = function(a, b) { return a - b; }
+
+function crankshaft_test_3() {
+  assertEquals(8, Math.min(3, 5));
+  assertEquals(3, Math.max(5, 2));
+}
+
+run(crankshaft_test_3);