Fix Math.pow(-0, 0.5) and Math.pow(-0, -0.5). These are not equal to sqrt(-0) and...
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 12:54:58 +0000 (12:54 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 12:54:58 +0000 (12:54 +0000)
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
src/assembler.cc
src/ia32/code-stubs-ia32.cc
src/ia32/codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/x64/codegen-x64.cc
test/mjsunit/math-pow.js

index 0d429d6..9a60183 100644 (file)
@@ -4698,12 +4698,15 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* 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<Expression*>* 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);
index fb9a4af..ca72d63 100644 (file)
@@ -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();
index 006ee46..a9c3085 100644 (file)
@@ -3499,10 +3499,12 @@ void MathPowStub::Generate(MacroAssembler* masm) {
   __ j(not_equal, &not_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);
index 2b48b0b..73c952a 100644 (file)
@@ -7951,10 +7951,12 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
     __ j(not_equal, &not_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<Expression*>* 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;
index d35bfc9..1922697 100644 (file)
@@ -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);
 }
 
index bebe468..91686f9 100644 (file)
@@ -6969,10 +6969,12 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
   __ j(not_equal, &not_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<Expression*>* 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;
index e732955..30d0cbd 100644 (file)
@@ -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);