From a5f94a4862d2add26e1b33bbca8ffe12f2439014 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Wed, 2 Feb 2011 12:54:58 +0000 Subject: [PATCH] Fix Math.pow(-0, 0.5) and Math.pow(-0, -0.5). These are not equal to sqrt(-0) and 1/sqrt(-0). Add tests for these cases. Fixes V8 issue 1088. BUG=1088 TEST=test/mjsunit/math-pow.js Review URL: http://codereview.chromium.org/6368050 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6573 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 10 +++++++-- src/assembler.cc | 4 ++-- src/ia32/code-stubs-ia32.cc | 12 +++++++---- src/ia32/codegen-ia32.cc | 12 +++++++---- src/ia32/lithium-codegen-ia32.cc | 2 ++ src/x64/codegen-x64.cc | 12 +++++++---- test/mjsunit/math-pow.js | 45 ++++++++++++++++++++++++++-------------- 7 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 0d429d6..9a60183 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -4698,12 +4698,15 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { runtime.entry_label(), AVOID_NANS_AND_INFINITIES); + // Convert -0 into +0 by adding +0. + __ vmov(d2, 0.0); + __ vadd(d0, d2, d0); // Load 1.0 into d2. __ vmov(d2, 1.0); - // Calculate the reciprocal of the square root. 1/sqrt(x) = sqrt(1/x). - __ vdiv(d0, d2, d0); + // Calculate the reciprocal of the square root. __ vsqrt(d0, d0); + __ vdiv(d0, d2, d0); __ b(&allocate_return); @@ -4717,6 +4720,9 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { scratch1, scratch2, heap_number_map, s0, runtime.entry_label(), AVOID_NANS_AND_INFINITIES); + // Convert -0 into +0 by adding +0. + __ vmov(d2, 0.0); + __ vadd(d0, d2, d0); __ vsqrt(d0, d0); __ bind(&allocate_return); diff --git a/src/assembler.cc b/src/assembler.cc index fb9a4af..ca72d63 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -838,8 +838,8 @@ double power_double_double(double x, double y) { return power_double_int(x, y_int); // Returns 1.0 for exponent 0. } if (!isinf(x)) { - if (y == 0.5) return sqrt(x); - if (y == -0.5) return 1.0 / sqrt(x); + if (y == 0.5) return sqrt(x + 0.0); // -0 must be converted to +0. + if (y == -0.5) return 1.0 / sqrt(x + 0.0); } if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { return OS::nan_value(); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 006ee46..a9c3085 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -3499,10 +3499,12 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -3514,7 +3516,9 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ ucomisd(xmm2, xmm1); __ j(not_equal, &call_runtime); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); __ bind(&allocate_return); diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 2b48b0b..73c952a 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -7951,10 +7951,12 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -7966,7 +7968,9 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { __ ucomisd(xmm2, xmm1); call_runtime.Branch(not_equal); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); JumpTarget done; diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index d35bfc9..1922697 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2397,6 +2397,8 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity)); __ ucomisd(xmm_scratch, input_reg); DeoptimizeIf(equal, instr->environment()); + __ xorpd(xmm_scratch, xmm_scratch); + __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. __ sqrtsd(input_reg, input_reg); } diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index bebe468..91686f9 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -6969,10 +6969,12 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -6985,7 +6987,9 @@ void CodeGenerator::GenerateMathPow(ZoneList* args) { call_runtime.Branch(not_equal); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); JumpTarget done; diff --git a/test/mjsunit/math-pow.js b/test/mjsunit/math-pow.js index e732955..30d0cbd 100644 --- a/test/mjsunit/math-pow.js +++ b/test/mjsunit/math-pow.js @@ -58,10 +58,11 @@ assertEquals(Infinity, Math.pow(-1.1, Infinity)); assertEquals(Infinity, Math.pow(2, Infinity)); assertEquals(Infinity, Math.pow(-2, Infinity)); -assertEquals(+0, Math.pow(1.1, -Infinity)); -assertEquals(+0, Math.pow(-1.1, -Infinity)); -assertEquals(+0, Math.pow(2, -Infinity)); -assertEquals(+0, Math.pow(-2, -Infinity)); +// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity +assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(2, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(-2, -Infinity)); assertEquals(NaN, Math.pow(1, Infinity)); assertEquals(NaN, Math.pow(1, -Infinity)); @@ -81,8 +82,8 @@ assertEquals(Infinity, Math.pow(-0.999, -Infinity)); assertEquals(Infinity, Math.pow(Infinity, 0.1)); assertEquals(Infinity, Math.pow(Infinity, 2)); -assertEquals(+0, Math.pow(Infinity, -0.1)); -assertEquals(+0, Math.pow(Infinity, -2)); +assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1)); +assertEquals(+Infinity, 1/Math.pow(Infinity, -2)); assertEquals(-Infinity, Math.pow(-Infinity, 3)); assertEquals(-Infinity, Math.pow(-Infinity, 13)); @@ -90,23 +91,23 @@ assertEquals(-Infinity, Math.pow(-Infinity, 13)); assertEquals(Infinity, Math.pow(-Infinity, 3.1)); assertEquals(Infinity, Math.pow(-Infinity, 2)); -assertEquals(-0, Math.pow(-Infinity, -3)); -assertEquals(-0, Math.pow(-Infinity, -13)); +assertEquals(-Infinity, 1/Math.pow(-Infinity, -3)); +assertEquals(-Infinity, 1/Math.pow(-Infinity, -13)); -assertEquals(+0, Math.pow(-Infinity, -3.1)); -assertEquals(+0, Math.pow(-Infinity, -2)); +assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1)); +assertEquals(+Infinity, 1/Math.pow(-Infinity, -2)); -assertEquals(+0, Math.pow(+0, 1.1)); -assertEquals(+0, Math.pow(+0, 2)); +assertEquals(+Infinity, 1/Math.pow(+0, 1.1)); +assertEquals(+Infinity, 1/Math.pow(+0, 2)); assertEquals(Infinity, Math.pow(+0, -1.1)); assertEquals(Infinity, Math.pow(+0, -2)); -assertEquals(-0, Math.pow(-0, 3)); -assertEquals(-0, Math.pow(-0, 13)); +assertEquals(-Infinity, 1/Math.pow(-0, 3)); +assertEquals(-Infinity, 1/Math.pow(-0, 13)); -assertEquals(+0, Math.pow(-0, 3.1)); -assertEquals(+0, Math.pow(-0, 2)); +assertEquals(+Infinity, 1/Math.pow(-0, 3.1)); +assertEquals(+Infinity, 1/Math.pow(-0, 2)); assertEquals(-Infinity, Math.pow(-0, -3)); assertEquals(-Infinity, Math.pow(-0, -13)); @@ -123,6 +124,18 @@ assertEquals(NaN, Math.pow(-2, -1.1)); assertEquals(NaN, Math.pow(-1000, 1.1)); assertEquals(NaN, Math.pow(-1000, -1.1)); +assertEquals(+Infinity, 1/Math.pow(-0, 0.5)); +assertEquals(+Infinity, 1/Math.pow(-0, 0.6)); +assertEquals(-Infinity, 1/Math.pow(-0, 1)); +assertEquals(-Infinity, 1/Math.pow(-0, 10000000001)); + +assertEquals(+Infinity, Math.pow(-0, -0.5)); +assertEquals(+Infinity, Math.pow(-0, -0.6)); +assertEquals(-Infinity, Math.pow(-0, -1)); +assertEquals(-Infinity, Math.pow(-0, -10000000001)); + + + // Tests from Sputnik S8.5_A13_T1. assertTrue((1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308); assertTrue((1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308); -- 2.7.4