From 339c9c12e79b8c1b379df33f04f31ad4bf24bb29 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Wed, 11 Jan 2012 15:43:33 +0000 Subject: [PATCH] Inlining Math.min and Math.max in crankshaft. 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 --- src/arm/lithium-codegen-arm.cc | 10 +++++++ src/arm/lithium-codegen-arm.h | 1 + src/hydrogen-instructions.h | 3 ++ src/hydrogen.cc | 51 ++++++++++++++++++++++++++++++++ src/ia32/lithium-codegen-ia32.cc | 22 +++++++++++++- src/ia32/lithium-codegen-ia32.h | 2 ++ src/ia32/lithium-ia32.cc | 6 +++- src/ia32/lithium-ia32.h | 5 ++-- src/objects.h | 4 ++- src/x64/lithium-codegen-x64.cc | 11 +++++++ src/x64/lithium-codegen-x64.h | 1 + test/mjsunit/math-min-max.js | 64 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 175 insertions(+), 5 deletions(-) diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index ffc465a..8b96f9b 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -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()); } diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index f04173f..e3cc730 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -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. diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 5110868..f9a618b 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -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(); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 34fd6da..f2d7fe1 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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; diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 537c558..98ef28d 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -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()); } diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index 38d0b3b..4b226e1 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h @@ -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. diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 8f7a28f..8435a3c 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -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()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 51809f5..67bf937 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -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") diff --git a/src/objects.h b/src/objects.h index 7de7aa7..d53f943 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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 { diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 1170e89..c9db687 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -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()); } diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index 5cffb5a..bbdc21e 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h @@ -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. diff --git a/test/mjsunit/math-min-max.js b/test/mjsunit/math-min-max.js index 0833c5c..7717b3b 100644 --- a/test/mjsunit/math-min-max.js +++ b/test/mjsunit/math-min-max.js @@ -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); -- 2.7.4