Revision: 6236
Author: [email protected]
Date: Mon Jan 10 00:04:30 2011
Log: Landing for Martyn Capewell.

ARM: Fix comparison of NaN values.

Enables the cumulative exception flag when comparing values, and uses it to
detect NaN results.

BUG=1023
TEST=none

Code review URL: http://codereview.chromium.org/6142004
http://code.google.com/p/v8/source/detail?r=6236

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/arm/simulator-arm.cc

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Dec 7 03:31:57 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Mon Jan 10 00:04:30 2011
@@ -2340,12 +2340,14 @@
                      const SBit s,
                      const Condition cond) {
   // vcmp(Dd, Dm) double precision floating point comparison.
+  // We set bit E, as we want any NaN to set the cumulative exception flag
+  // in the FPSCR.
   // Instruction details available in ARM DDI 0406A, A8-570.
   // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
- // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | Vm(3-0) + // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=1 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP3));
   emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
-       src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
+       src1.code()*B12 | 0x5*B9 | B8 | B7 | B6 | src2.code());
 }


@@ -2355,12 +2357,14 @@
                      const Condition cond) {
   // vcmp(Dd, Dm) double precision floating point comparison.
   // Instruction details available in ARM DDI 0406A, A8-570.
+  // We set bit E, as we want any NaN to set the cumulative exception flag
+  // in the FPSCR.
   // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
- // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | 0000(3-0) + // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=1 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP3));
   ASSERT(src2 == 0.0);
   emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
-       src1.code()*B12 | 0x5*B9 | B8 | B6);
+       src1.code()*B12 | 0x5*B9 | B8 | B7 | B6);
 }


=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Tue Jan  4 06:32:54 2011
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Mon Jan 10 00:04:30 2011
@@ -302,6 +302,8 @@
 static const uint32_t kVFPRoundingModeMask = 3 << 22;
 static const uint32_t kVFPFlushToZeroMask = 1 << 24;
 static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
+static const uint32_t kVFPZConditionFlagBit = 1 << 30;
+static const uint32_t kVFPInvalidExceptionBit = 1;

 // Coprocessor register
 struct CRegister {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Sun Jan 9 23:59:13 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Jan 10 00:04:30 2011
@@ -1076,8 +1076,16 @@
     EmitBranch(true_block, false_block, nz);
   } else if (r.IsDouble()) {
     DoubleRegister reg = ToDoubleRegister(instr->input());
+    Register scratch = scratch0();
+
+    // Test for the double value. Zero and NaN are false.
+    // Clear the Invalid cumulative exception flags.
+    __ ClearFPSCRBits(kVFPInvalidExceptionBit, scratch);
     __ vcmp(reg, 0.0);
-    __ vmrs(pc);  // Move vector status bits to normal status bits.
+      // Retrieve the exception and status flags and
+      // check for zero or an invalid exception.
+    __ vmrs(scratch);
+ __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPInvalidExceptionBit));
     EmitBranch(true_block, false_block, ne);
   } else {
     ASSERT(r.IsTagged());
@@ -1104,7 +1112,7 @@
       __ tst(reg, Operand(kSmiTagMask));
       __ b(eq, true_label);

-      // Test for double values. Zero is false.
+      // Test for double values. Zero and NaN are false.
       Label call_stub;
       DoubleRegister dbl_scratch = d0;
       Register scratch = scratch0();
@@ -1114,9 +1122,14 @@
       __ b(ne, &call_stub);
       __ sub(ip, reg, Operand(kHeapObjectTag));
       __ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
+      // Clear the Invalid cumulative exception flags.
+      __ ClearFPSCRBits(kVFPInvalidExceptionBit, scratch);
       __ vcmp(dbl_scratch, 0.0);
-      __ vmrs(pc);  // Move vector status bits to normal status bits.
-      __ b(eq, false_label);
+      // Retrieve the exception and status flags and
+      // check for zero or an invalid exception.
+      __ vmrs(scratch);
+ __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPInvalidExceptionBit));
+      __ b(ne, false_label);
       __ b(true_label);

       // The conversion stub doesn't cause garbage collections so it's
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Jan 7 02:37:26 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jan 10 00:04:30 2011
@@ -517,6 +517,13 @@
     str(src2, dst2, cond);
   }
 }
+
+
+void MacroAssembler::ClearFPSCRBits(uint32_t bits_to_clear, Register scratch) {
+  vmrs(scratch);
+  bic(scratch, scratch, Operand(bits_to_clear));
+  vmsr(scratch);
+}


 void MacroAssembler::EnterFrame(StackFrame::Type type) {
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Jan 6 00:56:29 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jan 10 00:04:30 2011
@@ -243,6 +243,9 @@
             const MemOperand& dst,
             Condition cond = al);

+  // Clear FPSCR bits.
+  void ClearFPSCRBits(uint32_t bits_to_clear, Register scratch);
+
// ---------------------------------------------------------------------------
   // Activation frames

=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Dec 7 03:31:57 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Jan 10 00:04:30 2011
@@ -2599,11 +2599,6 @@
   if (instr->SzField() == 1) {
     precision = kDoublePrecision;
   }
-
-  if (instr->Bit(7) != 0) {
-    // Raising exceptions for quiet NaNs are not supported.
-    UNIMPLEMENTED();  // Not used by V8.
-  }

   int d = instr->VFPDRegCode(precision);
   int m = 0;
@@ -2617,6 +2612,13 @@
     if (instr->Opc2Field() == 0x4) {
       dm_value = get_double_from_d_register(m);
     }
+
+    // Raise exceptions for quiet NaNs if necessary.
+    if (instr->Bit(7) == 1) {
+      if (isnan(dd_value)) {
+        inv_op_vfp_flag_ = true;
+      }
+    }

     Compute_FPSCR_Flags(dd_value, dm_value);
   } else {

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to