@samitouri / QOSamiQemu / commits / acb6d59857

fpu: Introduce FloatSNaNRule

Merge snan_bit_is_one and no_signaling_nans into one control. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed May 1, 2026 at 14:19 UTC acb6d598578fbb47b687ec02a664919950e15fbd
8 files changed +51 -50
fpu/softfloat-specialize.c.inc
+18 -30
@@ -79,26 +79,6 @@ this code that are retained.
79 * version 2 or later. See the COPYING file in the top-level directory.
80 */
81
82 -/*
83 - * Define whether architecture deviates from IEEE in not supporting
84 - * signaling NaNs (so all NaNs are treated as quiet).
85 - */
86 -static inline bool no_signaling_nans(float_status *status)
87 -{
88 - return status->no_signaling_nans;
89 -}
90 -
91 -/* Define how the architecture discriminates signaling NaNs.
92 - * This done with the most significant bit of the fraction.
93 - * In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
94 - * the msb must be zero. MIPS is (so far) unique in supporting both the
95 - * 2008 revision and backward compatibility with their original choice.
96 - */
97 -static inline bool snan_bit_is_one(float_status *status)
98 -{
99 - return status->snan_bit_is_one;
100 -}
101 -
82 /*----------------------------------------------------------------------------
83 | For the deconstructed floating-point with fraction FRAC, return true
84 | if the fraction represents a signalling NaN; otherwise false.
@@ -106,11 +86,15 @@ static inline bool snan_bit_is_one(float_status *status)
86
87 static bool frac_msb_is_snan(bool msb, float_status *status)
88 {
109 - if (no_signaling_nans(status)) {
89 + switch (get_snan_rule(status)) {
90 + case float_snan_never:
91 return false;
111 - } else {
112 - return msb == snan_bit_is_one(status);
92 + case float_snan_bit_is_one:
93 + return msb;
94 + case float_snan_bit_is_zero:
95 + return !msb;
96 }
97 + g_assert_not_reached();
98 }
99
100 static bool parts_is_snan_frac(uint64_t frac, float_status *status)
@@ -172,14 +156,18 @@ FloatParts128 parts128_default_nan(float_status *status)
156
157 static uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status)
158 {
175 - g_assert(!no_signaling_nans(status));
176 -
177 - /* The only snan_bit_is_one target without default_nan_mode is HPPA. */
178 - if (snan_bit_is_one(status)) {
159 + switch (get_snan_rule(status)) {
160 + case float_snan_bit_is_zero:
161 + frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1);
162 + break;
163 + case float_snan_bit_is_one:
164 + /* The only snan_bit_is_one target without default_nan_mode is HPPA. */
165 frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1));
166 frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2);
181 - } else {
182 - frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1);
167 + break;
168 + case float_snan_never:
169 + default:
170 + g_assert_not_reached();
171 }
172 return frac;
173 }
@@ -390,7 +378,7 @@ bool floatx80_is_signaling_nan(floatx80 a, float_status *status)
378 floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
379 {
380 /* None of the targets that have snan_bit_is_one use floatx80. */
393 - assert(!snan_bit_is_one(status));
381 + assert(get_snan_rule(status) == float_snan_bit_is_zero);
382 a.low |= UINT64_C(0xC000000000000000);
383 return a;
384 }
include/fpu/softfloat-helpers.h
+7 -7
@@ -127,14 +127,9 @@ static inline void set_default_nan_mode(bool val, float_status *status)
127 status->default_nan_mode = val;
128 }
129
130 -static inline void set_snan_bit_is_one(bool val, float_status *status)
130 +static inline void set_snan_rule(FloatSNaNRule val, float_status *status)
131 {
132 - status->snan_bit_is_one = val;
133 -}
134 -
135 -static inline void set_no_signaling_nans(bool val, float_status *status)
136 -{
137 - status->no_signaling_nans = val;
132 + status->float_snan_rule = val;
133 }
134
135 static inline bool get_float_detect_tininess(const float_status *status)
@@ -203,6 +198,11 @@ static inline bool get_default_nan_mode(const float_status *status)
198 return status->default_nan_mode;
199 }
200
201 +static inline FloatSNaNRule get_snan_rule(float_status *status)
202 +{
203 + return status->float_snan_rule;
204 +}
205 +
206 static inline FloatFTZDetection get_float_ftz_detection(const float_status *status)
207 {
208 return status->ftz_detection;
include/fpu/softfloat-types.h
+18 -7
@@ -192,6 +192,23 @@ typedef enum __attribute__((__packed__)) {
192 floatx80_precision_s,
193 } FloatX80RoundPrec;
194
195 +/*
196 + * Define how the architecture discriminates signaling NaNs.
197 + * This done with the most significant bit of the fraction.
198 + *
199 + * In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
200 + * the msb must be 0. But setting the msb to 1 got baked into HPPA, SH4,
201 + * and pre-2008 MIPS.
202 + *
203 + * Further, some architectures (or modes of architectures) do not detect
204 + * signaling NaNs at all.
205 + */
206 +typedef enum __attribute__((__packed__)) {
207 + float_snan_bit_is_zero,
208 + float_snan_bit_is_one,
209 + float_snan_never,
210 +} FloatSNaNRule;
211 +
212 /*
213 * 2-input NaN propagation rule. Individual architectures have
214 * different rules for which input NaN is propagated to the output
@@ -394,6 +411,7 @@ typedef struct float_status {
411 Float2NaNPropRule float_2nan_prop_rule;
412 Float3NaNPropRule float_3nan_prop_rule;
413 FloatInfZeroNaNRule float_infzeronan_rule;
414 + FloatSNaNRule float_snan_rule;
415 bool tininess_before_rounding;
416 /* should denormalised results go to zero and set output_denormal_flushed? */
417 bool flush_to_zero;
@@ -412,13 +430,6 @@ typedef struct float_status {
430 * create a default NaN.
431 */
432 uint8_t default_nan_pattern;
415 - /*
416 - * The flags below are not used on all specializations and may
417 - * constant fold away (see snan_bit_is_one()/no_signalling_nans() in
418 - * softfloat-specialize.inc.c)
419 - */
420 - bool snan_bit_is_one;
421 - bool no_signaling_nans;
433 /* should overflowed results subtract re_bias to its exponent? */
434 bool rebias_overflow;
435 /* should underflowed results add re_bias to its exponent? */
target/hppa/fpu_helper.c
+1 -1
@@ -66,7 +66,7 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
66 set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
67 /* Default NaN: sign bit clear, msb-1 frac bit set */
68 set_float_default_nan_pattern(0b00100000, &env->fp_status);
69 - set_snan_bit_is_one(true, &env->fp_status);
69 + set_snan_rule(float_snan_bit_is_one, &env->fp_status);
70 /*
71 * "PA-RISC 2.0 Architecture" says it is IMPDEF whether the flushing
72 * enabled by FPSR.D happens before or after rounding. We pick "before"
target/mips/fpu_helper.h
+2 -1
@@ -35,7 +35,8 @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
35 * With nan2008, SNaNs are silenced in the usual way.
36 * Before that, SNaNs are not silenced; default nans are produced.
37 */
38 - set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
38 + set_snan_rule(nan2008 ? float_snan_bit_is_zero : float_snan_bit_is_one,
39 + &env->active_fpu.fp_status);
40 set_default_nan_mode(!nan2008, &env->active_fpu.fp_status);
41 /*
42 * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
target/mips/msa.c
+2 -2
@@ -84,8 +84,8 @@ void msa_reset(CPUMIPSState *env)
84 /* clear float_status nan mode */
85 set_default_nan_mode(0, &env->active_tc.msa_fp_status);
86
87 - /* set proper signanling bit meaning ("1" means "quiet") */
88 - set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
87 + /* set proper signanling bit meaning */
88 + set_snan_rule(float_snan_bit_is_zero, &env->active_tc.msa_fp_status);
89
90 /* Inf * 0 + NaN returns the input NaN */
91 set_float_infzeronan_rule(float_infzeronan_dnan_never,
target/sh4/cpu.c
+1 -1
@@ -151,7 +151,7 @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
151 set_flush_to_zero(1, &env->fp_status);
152 #endif
153 set_default_nan_mode(1, &env->fp_status);
154 - set_snan_bit_is_one(true, &env->fp_status);
154 + set_snan_rule(float_snan_bit_is_one, &env->fp_status);
155 /* sign bit clear, set all frac bits other than msb */
156 set_float_default_nan_pattern(0b00111111, &env->fp_status);
157 /*
target/xtensa/cpu.c
+2 -1
@@ -209,7 +209,8 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
209 #endif
210 /* For inf * 0 + NaN, return the input NaN */
211 set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
212 - set_no_signaling_nans(!dfpu, &env->fp_status);
212 + set_snan_rule(dfpu ? float_snan_bit_is_zero : float_snan_never,
213 + &env->fp_status);
214 /* Default NaN value: sign bit clear, set frac msb */
215 set_float_default_nan_pattern(0b01000000, &env->fp_status);
216 xtensa_use_first_nan(env, !dfpu);