sim: Allow toggling of quiet NaN-bit semantics
authorFaraz Shahbazker <fshahbazker@wavecomp.com>
Wed, 2 Feb 2022 10:17:22 +0000 (11:17 +0100)
committerMike Frysinger <vapier@gentoo.org>
Sat, 5 Feb 2022 00:37:25 +0000 (19:37 -0500)
IEEE754-1985 specifies the top bit of the mantissa as an indicator
of signalling vs. quiet NaN, but does not define the precise semantics.
Most architectures treat this bit as indicating quiet NaN, but legacy
(pre-R6) MIPS goes the other way and treats it as signalling NaN.

This used to be controlled by a macro that was only defined for MIPS.
This patch replaces the macro with a variable to track the current
semantics of the NaN bit and allows differentiation between older
(pre-R6) and and newer MIPS cores.

2022-02-01  Faraz Shahbazker  <fshahbazker@wavecomp.com>

sim/common/ChangeLog:
* sim-fpu.c (_sim_fpu): New.
(pack_fpu, unpack_fpu): Allow reversal of quiet NaN semantics.
* sim-fpu.h (sim_fpu_state): New struct.
(_sim_fpu): New extern.
(sim_fpu_quiet_nan_inverted): New define.

sim/mips/ChangeLog:
* cp1.h (fcsr_NAN2008_mask, fcsr_NAN2008_shift): New.
* mips.igen (check_fpu): Select default quiet NaN mode
for legacy MIPS.
* sim-main.h (SIM_QUIET_NAN_NEGATED): Remove.

sim/common/sim-fpu.c
sim/common/sim-fpu.h
sim/mips/cp1.h
sim/mips/mips.igen
sim/mips/sim-main.h

index a05c57897ffa37ea12d29e727f2efafac643f7e3..276ad234174dc7319a405c3b305ef986dd1e1f50 100644 (file)
@@ -198,11 +198,10 @@ pack_fpu (const sim_fpu *src,
       /* Force fraction to correct class.  */
       fraction = src->fraction;
       fraction >>= NR_GUARDS;
-#ifdef SIM_QUIET_NAN_NEGATED
-      fraction |= QUIET_NAN - 1;
-#else
-      fraction |= QUIET_NAN;
-#endif
+      if (sim_fpu_quiet_nan_inverted)
+       fraction |= QUIET_NAN - 1;
+      else
+       fraction |= QUIET_NAN;
       break;
     case sim_fpu_class_snan:
       sign = src->sign;
@@ -210,11 +209,10 @@ pack_fpu (const sim_fpu *src,
       /* Force fraction to correct class.  */
       fraction = src->fraction;
       fraction >>= NR_GUARDS;
-#ifdef SIM_QUIET_NAN_NEGATED
-      fraction |= QUIET_NAN;
-#else
-      fraction &= ~QUIET_NAN;
-#endif
+      if (sim_fpu_quiet_nan_inverted)
+        fraction |= QUIET_NAN;
+      else
+       fraction &= ~QUIET_NAN;
       break;
     case sim_fpu_class_infinity:
       sign = src->sign;
@@ -372,11 +370,10 @@ unpack_fpu (sim_fpu *dst, uint64_t packed, int is_double)
          /* Non zero fraction, means NaN.  */
          dst->sign = sign;
          dst->fraction = (fraction << NR_GUARDS);
-#ifdef SIM_QUIET_NAN_NEGATED
-         qnan = (fraction & QUIET_NAN) == 0;
-#else
-         qnan = fraction >= QUIET_NAN;
-#endif
+         if (sim_fpu_quiet_nan_inverted)
+           qnan = (fraction & QUIET_NAN) == 0;
+         else
+           qnan = fraction >= QUIET_NAN;
          if (qnan)
            dst->class = sim_fpu_class_qnan;
          else
@@ -2512,6 +2509,10 @@ sim_fpu_gt (int *is,
 /* A number of useful constants */
 
 #if EXTERN_SIM_FPU_P
+sim_fpu_state _sim_fpu = {
+  .quiet_nan_inverted = false,
+};
+
 const sim_fpu sim_fpu_zero = {
   sim_fpu_class_zero, 0, 0, 0
 };
index 447621b5d7314e1b3b0d6bd9de89916358cbc921..b0b318cb2838939c71c1466ecf257deba0174212 100644 (file)
@@ -25,6 +25,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #define SIM_FPU_H
 
 
+#include <stdbool.h>
+
 
 /* The FPU intermediate type - this object, passed by reference,
    should be treated as opaque.
@@ -157,6 +159,17 @@ typedef enum
 
 
 
+/* State used by the FPU.
+
+   FIXME: This state is global, but should be moved to SIM_CPU.  */
+
+typedef struct _sim_fpu_state {
+  bool quiet_nan_inverted; /* Toggle quiet NaN semantics.  */
+} sim_fpu_state;
+
+
+
+
 /* Directly map between a 32/64 bit register and the sim_fpu internal
    type.
 
@@ -375,7 +388,19 @@ enum {
 INLINE_SIM_FPU (int) sim_fpu_is (const sim_fpu *l);
 INLINE_SIM_FPU (int) sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r);
 
+/* Global FPU state.  */
+
+extern sim_fpu_state _sim_fpu;
+
+
+/* IEEE 754-1985 specifies the top bit of the mantissa as an indicator
+   of signalling vs. quiet NaN, but does not specify the semantics.
+   Most architectures treat this bit as quiet NaN, but legacy (pre-R6)
+   MIPS goes the other way and treats it as signalling.  This variable
+   tracks the current semantics of the NaN bit and allows differentiation
+   between pre-R6 and R6 MIPS cores.  */
 
+#define sim_fpu_quiet_nan_inverted _sim_fpu.quiet_nan_inverted
 
 /* A number of useful constants.  */
 
index 96c51a7b736dd165575f35ca3e2df5212855ad5e..d6d8a8874fd23e010ef20354547f5a15fea6bac3 100644 (file)
@@ -40,6 +40,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #define fcsr_RM_mask       (0x00000003)
 #define fcsr_RM_shift      (0)
 
+/* FCSR bits for IEEE754-2008 compliance.  */
+#define fcsr_NAN2008_mask       (0x00040000)
+#define fcsr_NAN2008_shift      (18)
+
 #define fenr_FS            (0x00000004)
 
 /* Macros to update and retrieve the FCSR condition-code bits.  This
index c5db5c2304fabf63fe1393fd857351f5cbe14bf5..b0c5e5995af2da50b7187cd420073d8e0a0d5fe8 100644 (file)
 {
   if (! COP_Usable (1))
     SignalExceptionCoProcessorUnusable (1);
+
+  FCSR &= ~fcsr_NAN2008_mask;
+  sim_fpu_quiet_nan_inverted = true;
 }
 
 
index d724688a4348c93d0d767286bf4395d95b1961bb..8e3e85f258559fb9a62c0f0c8d32c400c34f01b3 100644 (file)
@@ -20,9 +20,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifndef SIM_MAIN_H
 #define SIM_MAIN_H
 
-/* MIPS uses an unusual format for floating point quiet NaNs.  */
-#define SIM_QUIET_NAN_NEGATED
-
 #define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \
 mips_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), (TRANSFER), (ERROR))