Test behavior of qNaN and sNaN
authordslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Apr 2013 09:31:24 +0000 (09:31 +0000)
committerdslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Apr 2013 09:31:24 +0000 (09:31 +0000)
BUG=v8:2607

Review URL: https://codereview.chromium.org/13470002

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

src/ia32/code-stubs-ia32.cc
test/mjsunit/nans.js [new file with mode: 0644]

index 09012b6..9b77c50 100644 (file)
@@ -4525,6 +4525,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
 
   // Identical objects can be compared fast, but there are some tricky cases
   // for NaN and undefined.
+  Label generic_heap_number_comparison;
   {
     Label not_identical;
     __ cmp(eax, edx);
@@ -4541,12 +4542,11 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
       __ bind(&check_for_nan);
     }
 
-    // Test for NaN. Sadly, we can't just compare to factory->nan_value(),
-    // so we do the second best thing - test it ourselves.
-    Label heap_number;
+    // Test for NaN. Compare heap numbers in a general way,
+    // to hanlde NaNs correctly.
     __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
            Immediate(masm->isolate()->factory()->heap_number_map()));
-    __ j(equal, &heap_number, Label::kNear);
+    __ j(equal, &generic_heap_number_comparison, Label::kNear);
     if (cc != equal) {
       // Call runtime on identical JSObjects.  Otherwise return equal.
       __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
@@ -4555,37 +4555,6 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
     __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
     __ ret(0);
 
-    __ bind(&heap_number);
-    // It is a heap number, so return non-equal if it's NaN and equal if
-    // it's not NaN.
-    // The representation of NaN values has all exponent bits (52..62) set,
-    // and not all mantissa bits (0..51) clear.
-    // We only accept QNaNs, which have bit 51 set.
-    // Read top bits of double representation (second word of value).
-
-    // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
-    // all bits in the mask are set. We only need to check the word
-    // that contains the exponent and high bit of the mantissa.
-    STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
-    __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
-    __ Set(eax, Immediate(0));
-    // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
-    // bits.
-    __ add(edx, edx);
-    __ cmp(edx, kQuietNaNHighBitsMask << 1);
-    if (cc == equal) {
-      STATIC_ASSERT(EQUAL != 1);
-      __ setcc(above_equal, eax);
-      __ ret(0);
-    } else {
-      Label nan;
-      __ j(above_equal, &nan, Label::kNear);
-      __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
-      __ ret(0);
-      __ bind(&nan);
-      __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
-      __ ret(0);
-    }
 
     __ bind(&not_identical);
   }
@@ -4665,6 +4634,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
   // Generate the number comparison code.
   Label non_number_comparison;
   Label unordered;
+  __ bind(&generic_heap_number_comparison);
   if (CpuFeatures::IsSupported(SSE2)) {
     CpuFeatureScope use_sse2(masm, SSE2);
     CpuFeatureScope use_cmov(masm, CMOV);
diff --git a/test/mjsunit/nans.js b/test/mjsunit/nans.js
new file mode 100644 (file)
index 0000000..d212afd
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+
+// Test that both kinds of NaNs (signaling or quiet) do not signal
+
+function TestAllModes(f) {
+  f(); // Runtime
+  f(); // IC
+  f(); // IC second time
+  %OptimizeFunctionOnNextCall(f);
+  f(); // hydrogen
+}
+
+function TestDoubleSignalingNan() {
+  // NaN with signal bit set
+  function f() {
+    var bytes = new Uint32Array([1, 0x7FF00000]);
+    var doubles = new Float64Array(bytes.buffer);
+    assertTrue(isNaN(doubles[0]));
+    assertTrue(isNaN(doubles[0]*2.0));
+    assertTrue(isNaN(doubles[0] + 0.5));
+  }
+
+  TestAllModes(f);
+}
+
+TestDoubleSignalingNan();
+
+function TestDoubleQuietNan() {
+  // NaN with signal bit cleared
+  function f() {
+    var bytes = new Uint32Array([0, 0x7FF80000]);
+    var doubles = new Float64Array(bytes.buffer);
+    assertTrue(isNaN(doubles[0]));
+    assertTrue(isNaN(doubles[0]*2.0));
+    assertTrue(isNaN(doubles[0] + 0.5));
+  }
+
+  TestAllModes(f);
+}
+
+TestDoubleQuietNan();
+
+function TestFloatSignalingNan() {
+  // NaN with signal bit set
+  function f() {
+    var bytes = new Uint32Array([0x7F800001]);
+    var floats = new Float32Array(bytes.buffer);
+    assertTrue(isNaN(floats[0]));
+    assertTrue(isNaN(floats[0]*2.0));
+    assertTrue(isNaN(floats[0] + 0.5));
+  }
+
+  TestAllModes(f);
+}
+
+TestFloatSignalingNan();
+
+function TestFloatQuietNan() {
+  // NaN with signal bit cleared
+  function f() {
+    var bytes = new Uint32Array([0x7FC00000]);
+    var floats = new Float32Array(bytes.buffer);
+    assertTrue(isNaN(floats[0]));
+    assertTrue(isNaN(floats[0]*2.0));
+    assertTrue(isNaN(floats[0] + 0.5));
+  }
+
+  TestAllModes(f);
+}
+
+TestFloatQuietNan();
+
+
+
+