From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Subject: [PULL 02/68] fpu: Add float_class_denormal
Date: Tue, 11 Feb 2025 16:24:48 +0000 [thread overview]
Message-ID: <20250211162554.4135349-3-peter.maydell@linaro.org> (raw)
In-Reply-To: <20250211162554.4135349-1-peter.maydell@linaro.org>
Currently in softfloat we canonicalize input denormals and so the
code that implements floating point operations does not need to care
whether the input value was originally normal or denormal. However,
both x86 and Arm FEAT_AFP require that an exception flag is set if:
* an input is denormal
* that input is not squashed to zero
* that input is actually used in the calculation (e.g. we
did not find the other input was a NaN)
So we need to track that the input was a non-squashed denormal. To
do this we add a new value to the FloatClass enum. In this commit we
add the value and adjust the code everywhere that looks at FloatClass
values so that the new float_class_denormal behaves identically to
float_class_normal. We will add the code that does the "raise a new
float exception flag if an input was an unsquashed denormal and we
used it" in a subsequent commit.
There should be no behavioural change in this commit.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
fpu/softfloat.c | 32 ++++++++++++++++++++++++++++---
fpu/softfloat-parts.c.inc | 40 ++++++++++++++++++++++++---------------
2 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 26f3a8dc87e..03a604c38ec 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -404,12 +404,16 @@ float64_gen2(float64 xa, float64 xb, float_status *s,
/*
* Classify a floating point number. Everything above float_class_qnan
* is a NaN so cls >= float_class_qnan is any NaN.
+ *
+ * Note that we canonicalize denormals, so most code should treat
+ * class_normal and class_denormal identically.
*/
typedef enum __attribute__ ((__packed__)) {
float_class_unclassified,
float_class_zero,
float_class_normal,
+ float_class_denormal, /* input was a non-squashed denormal */
float_class_inf,
float_class_qnan, /* all NaNs from here */
float_class_snan,
@@ -420,12 +424,14 @@ typedef enum __attribute__ ((__packed__)) {
enum {
float_cmask_zero = float_cmask(float_class_zero),
float_cmask_normal = float_cmask(float_class_normal),
+ float_cmask_denormal = float_cmask(float_class_denormal),
float_cmask_inf = float_cmask(float_class_inf),
float_cmask_qnan = float_cmask(float_class_qnan),
float_cmask_snan = float_cmask(float_class_snan),
float_cmask_infzero = float_cmask_zero | float_cmask_inf,
float_cmask_anynan = float_cmask_qnan | float_cmask_snan,
+ float_cmask_anynorm = float_cmask_normal | float_cmask_denormal,
};
/* Flags for parts_minmax. */
@@ -459,6 +465,20 @@ static inline __attribute__((unused)) bool is_qnan(FloatClass c)
return c == float_class_qnan;
}
+/*
+ * Return true if the float_cmask has only normals in it
+ * (including input denormals that were canonicalized)
+ */
+static inline bool cmask_is_only_normals(int cmask)
+{
+ return !(cmask & ~float_cmask_anynorm);
+}
+
+static inline bool is_anynorm(FloatClass c)
+{
+ return float_cmask(c) & float_cmask_anynorm;
+}
+
/*
* Structure holding all of the decomposed parts of a float.
* The exponent is unbiased and the fraction is normalized.
@@ -1729,6 +1749,7 @@ static float64 float64r32_round_pack_canonical(FloatParts64 *p,
*/
switch (p->cls) {
case float_class_normal:
+ case float_class_denormal:
if (unlikely(p->exp == 0)) {
/*
* The result is denormal for float32, but can be represented
@@ -1817,6 +1838,7 @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p,
switch (p->cls) {
case float_class_normal:
+ case float_class_denormal:
if (s->floatx80_rounding_precision == floatx80_precision_x) {
parts_uncanon_normal(p, s, fmt);
frac = p->frac_hi;
@@ -2697,6 +2719,7 @@ static void parts_float_to_ahp(FloatParts64 *a, float_status *s)
break;
case float_class_normal:
+ case float_class_denormal:
case float_class_zero:
break;
@@ -2729,7 +2752,7 @@ static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b,
a->sign = b->sign;
a->exp = b->exp;
- if (a->cls == float_class_normal) {
+ if (is_anynorm(a->cls)) {
frac_truncjam(a, b);
} else if (is_nan(a->cls)) {
/* Discard the low bits of the NaN. */
@@ -3218,6 +3241,7 @@ static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode,
return int128_zero();
case float_class_normal:
+ case float_class_denormal:
if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) {
flags = float_flag_inexact;
}
@@ -3645,6 +3669,7 @@ static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode,
return int128_zero();
case float_class_normal:
+ case float_class_denormal:
if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) {
flags = float_flag_inexact;
if (p.cls == float_class_zero) {
@@ -5231,6 +5256,8 @@ float32 float32_exp2(float32 a, float_status *status)
float32_unpack_canonical(&xp, a, status);
if (unlikely(xp.cls != float_class_normal)) {
switch (xp.cls) {
+ case float_class_denormal:
+ break;
case float_class_snan:
case float_class_qnan:
parts_return_nan(&xp, status);
@@ -5240,9 +5267,8 @@ float32 float32_exp2(float32 a, float_status *status)
case float_class_zero:
return float32_one;
default:
- break;
+ g_assert_not_reached();
}
- g_assert_not_reached();
}
float_raise(float_flag_inexact, status);
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 73621f4a970..8621cb87185 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -204,7 +204,7 @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
frac_clear(p);
} else {
int shift = frac_normalize(p);
- p->cls = float_class_normal;
+ p->cls = float_class_denormal;
p->exp = fmt->frac_shift - fmt->exp_bias
- shift + !fmt->m68k_denormal;
}
@@ -395,7 +395,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
static void partsN(uncanon)(FloatPartsN *p, float_status *s,
const FloatFmt *fmt)
{
- if (likely(p->cls == float_class_normal)) {
+ if (likely(is_anynorm(p->cls))) {
parts_uncanon_normal(p, s, fmt);
} else {
switch (p->cls) {
@@ -435,7 +435,7 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b,
if (a->sign != b_sign) {
/* Subtraction */
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
if (parts_sub_normal(a, b)) {
return a;
}
@@ -468,7 +468,7 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b,
}
} else {
/* Addition */
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
parts_add_normal(a, b);
return a;
}
@@ -488,12 +488,12 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b,
}
if (b->cls == float_class_zero) {
- g_assert(a->cls == float_class_normal);
+ g_assert(is_anynorm(a->cls));
return a;
}
g_assert(a->cls == float_class_zero);
- g_assert(b->cls == float_class_normal);
+ g_assert(is_anynorm(b->cls));
return_b:
b->sign = b_sign;
return b;
@@ -513,7 +513,7 @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b,
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
bool sign = a->sign ^ b->sign;
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
FloatPartsW tmp;
frac_mulw(&tmp, a, b);
@@ -596,7 +596,7 @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b,
a->sign ^= 1;
}
- if (unlikely(ab_mask != float_cmask_normal)) {
+ if (unlikely(!cmask_is_only_normals(ab_mask))) {
if (unlikely(ab_mask == float_cmask_infzero)) {
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
goto d_nan;
@@ -611,7 +611,7 @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b,
}
g_assert(ab_mask & float_cmask_zero);
- if (c->cls == float_class_normal) {
+ if (is_anynorm(c->cls)) {
*a = *c;
goto return_normal;
}
@@ -692,7 +692,7 @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b,
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
bool sign = a->sign ^ b->sign;
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
a->sign = sign;
a->exp -= b->exp + frac_div(a, b);
return a;
@@ -750,7 +750,7 @@ static FloatPartsN *partsN(modrem)(FloatPartsN *a, FloatPartsN *b,
{
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
frac_modrem(a, b, mod_quot);
return a;
}
@@ -800,6 +800,8 @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status,
if (unlikely(a->cls != float_class_normal)) {
switch (a->cls) {
+ case float_class_denormal:
+ break;
case float_class_snan:
case float_class_qnan:
parts_return_nan(a, status);
@@ -1130,6 +1132,7 @@ static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode,
case float_class_inf:
break;
case float_class_normal:
+ case float_class_denormal:
if (parts_round_to_int_normal(a, rmode, scale, fmt->frac_size)) {
float_raise(float_flag_inexact, s);
}
@@ -1174,6 +1177,7 @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode,
return 0;
case float_class_normal:
+ case float_class_denormal:
/* TODO: N - 2 is frac_size for rounding; could use input fmt. */
if (parts_round_to_int_normal(p, rmode, scale, N - 2)) {
flags = float_flag_inexact;
@@ -1241,6 +1245,7 @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode,
return 0;
case float_class_normal:
+ case float_class_denormal:
/* TODO: N - 2 is frac_size for rounding; could use input fmt. */
if (parts_round_to_int_normal(p, rmode, scale, N - 2)) {
flags = float_flag_inexact;
@@ -1304,6 +1309,7 @@ static int64_t partsN(float_to_sint_modulo)(FloatPartsN *p,
return 0;
case float_class_normal:
+ case float_class_denormal:
/* TODO: N - 2 is frac_size for rounding; could use input fmt. */
if (parts_round_to_int_normal(p, rmode, 0, N - 2)) {
flags = float_flag_inexact;
@@ -1452,9 +1458,10 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
a_exp = a->exp;
b_exp = b->exp;
- if (unlikely(ab_mask != float_cmask_normal)) {
+ if (unlikely(!cmask_is_only_normals(ab_mask))) {
switch (a->cls) {
case float_class_normal:
+ case float_class_denormal:
break;
case float_class_inf:
a_exp = INT16_MAX;
@@ -1467,6 +1474,7 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
}
switch (b->cls) {
case float_class_normal:
+ case float_class_denormal:
break;
case float_class_inf:
b_exp = INT16_MAX;
@@ -1513,7 +1521,7 @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b,
{
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
- if (likely(ab_mask == float_cmask_normal)) {
+ if (likely(cmask_is_only_normals(ab_mask))) {
FloatRelation cmp;
if (a->sign != b->sign) {
@@ -1581,6 +1589,7 @@ static void partsN(scalbn)(FloatPartsN *a, int n, float_status *s)
case float_class_inf:
break;
case float_class_normal:
+ case float_class_denormal:
a->exp += MIN(MAX(n, -0x10000), 0x10000);
break;
default:
@@ -1599,6 +1608,8 @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt)
if (unlikely(a->cls != float_class_normal)) {
switch (a->cls) {
+ case float_class_denormal:
+ break;
case float_class_snan:
case float_class_qnan:
parts_return_nan(a, s);
@@ -1615,9 +1626,8 @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt)
}
return;
default:
- break;
+ g_assert_not_reached();
}
- g_assert_not_reached();
}
if (unlikely(a->sign)) {
goto d_nan;
--
2.34.1
next prev parent reply other threads:[~2025-02-11 16:26 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-11 16:24 [PULL 00/68] target-arm queue Peter Maydell
2025-02-11 16:24 ` [PULL 01/68] target/alpha: Don't corrupt error_code with unknown softfloat flags Peter Maydell
2025-02-11 16:24 ` Peter Maydell [this message]
2025-02-11 16:24 ` [PULL 03/68] fpu: Implement float_flag_input_denormal_used Peter Maydell
2025-02-11 16:24 ` [PULL 04/68] fpu: allow flushing of output denormals to be after rounding Peter Maydell
2025-02-11 16:24 ` [PULL 05/68] target/arm: Define FPCR AH, FIZ, NEP bits Peter Maydell
2025-02-11 16:24 ` [PULL 06/68] target/arm: Implement FPCR.FIZ handling Peter Maydell
2025-02-11 16:24 ` [PULL 07/68] target/arm: Adjust FP behaviour for FPCR.AH = 1 Peter Maydell
2025-02-11 16:24 ` [PULL 08/68] target/arm: Adjust exception flag handling for AH " Peter Maydell
2025-02-11 16:24 ` [PULL 09/68] target/arm: Add FPCR.AH to tbflags Peter Maydell
2025-02-11 16:24 ` [PULL 10/68] target/arm: Set up float_status to use for FPCR.AH=1 behaviour Peter Maydell
2025-02-11 16:24 ` [PULL 11/68] target/arm: Use FPST_FPCR_AH for FRECPE, FRECPS, FRECPX, FRSQRTE, FRSQRTS Peter Maydell
2025-02-11 16:24 ` [PULL 12/68] target/arm: Use FPST_FPCR_AH for BFCVT* insns Peter Maydell
2025-02-11 16:24 ` [PULL 13/68] target/arm: Use FPST_FPCR_AH for BFMLAL*, BFMLSL* insns Peter Maydell
2025-02-11 16:25 ` [PULL 14/68] target/arm: Add FPCR.NEP to TBFLAGS Peter Maydell
2025-02-11 16:25 ` [PULL 15/68] target/arm: Define and use new write_fp_*reg_merging() functions Peter Maydell
2025-02-11 16:25 ` [PULL 16/68] target/arm: Handle FPCR.NEP for 3-input scalar operations Peter Maydell
2025-02-11 16:25 ` [PULL 17/68] target/arm: Handle FPCR.NEP for BFCVT scalar Peter Maydell
2025-02-11 16:25 ` [PULL 18/68] target/arm: Handle FPCR.NEP for 1-input scalar operations Peter Maydell
2025-02-11 16:25 ` [PULL 19/68] target/arm: Handle FPCR.NEP in do_cvtf_scalar() Peter Maydell
2025-02-11 16:25 ` [PULL 20/68] target/arm: Handle FPCR.NEP for scalar FABS and FNEG Peter Maydell
2025-02-11 16:25 ` [PULL 21/68] target/arm: Handle FPCR.NEP for FCVTXN (scalar) Peter Maydell
2025-02-11 16:25 ` [PULL 22/68] target/arm: Handle FPCR.NEP for NEP for FMUL, FMULX scalar by element Peter Maydell
2025-02-11 16:25 ` [PULL 23/68] target/arm: Implement FPCR.AH semantics for scalar FMIN/FMAX Peter Maydell
2025-02-11 16:25 ` [PULL 24/68] target/arm: Implement FPCR.AH semantics for vector FMIN/FMAX Peter Maydell
2025-02-11 16:25 ` [PULL 25/68] target/arm: Implement FPCR.AH semantics for FMAXV and FMINV Peter Maydell
2025-02-11 16:25 ` [PULL 26/68] target/arm: Implement FPCR.AH semantics for FMINP and FMAXP Peter Maydell
2025-02-11 16:25 ` [PULL 27/68] target/arm: Implement FPCR.AH semantics for SVE FMAXV and FMINV Peter Maydell
2025-02-11 16:25 ` [PULL 28/68] target/arm: Implement FPCR.AH semantics for SVE FMIN/FMAX immediate Peter Maydell
2025-02-11 16:25 ` [PULL 29/68] target/arm: Implement FPCR.AH semantics for SVE FMIN/FMAX vector Peter Maydell
2025-02-11 16:25 ` [PULL 30/68] target/arm: Implement FPCR.AH handling of negation of NaN Peter Maydell
2025-02-11 16:25 ` [PULL 31/68] target/arm: Implement FPCR.AH handling for scalar FABS and FABD Peter Maydell
2025-02-11 16:25 ` [PULL 32/68] target/arm: Handle FPCR.AH in vector FABD Peter Maydell
2025-02-11 16:25 ` [PULL 33/68] target/arm: Handle FPCR.AH in SVE FNEG Peter Maydell
2025-02-11 16:25 ` [PULL 34/68] target/arm: Handle FPCR.AH in SVE FABS Peter Maydell
2025-02-11 16:25 ` [PULL 35/68] target/arm: Handle FPCR.AH in SVE FABD Peter Maydell
2025-02-11 16:25 ` [PULL 36/68] target/arm: Handle FPCR.AH in negation steps in SVE FCADD Peter Maydell
2025-02-11 16:25 ` [PULL 37/68] target/arm: Handle FPCR.AH in negation steps in FCADD Peter Maydell
2025-02-11 16:25 ` [PULL 38/68] target/arm: Handle FPCR.AH in FRECPS and FRSQRTS scalar insns Peter Maydell
2025-02-11 16:25 ` [PULL 39/68] target/arm: Handle FPCR.AH in FRECPS and FRSQRTS vector insns Peter Maydell
2025-02-11 16:25 ` [PULL 40/68] target/arm: Handle FPCR.AH in negation step in FMLS (indexed) Peter Maydell
2025-02-11 16:25 ` [PULL 41/68] target/arm: Handle FPCR.AH in negation in FMLS (vector) Peter Maydell
2025-02-11 16:25 ` [PULL 42/68] target/arm: Handle FPCR.AH in negation step in SVE " Peter Maydell
2025-02-11 16:25 ` [PULL 43/68] target/arm: Handle FPCR.AH in SVE FTSSEL Peter Maydell
2025-02-11 16:25 ` [PULL 44/68] target/arm: Handle FPCR.AH in SVE FTMAD Peter Maydell
2025-02-11 16:25 ` [PULL 45/68] target/arm: Handle FPCR.AH in vector FCMLA Peter Maydell
2025-02-11 16:25 ` [PULL 46/68] target/arm: Handle FPCR.AH in FCMLA by index Peter Maydell
2025-02-11 16:25 ` [PULL 47/68] target/arm: Handle FPCR.AH in SVE FCMLA Peter Maydell
2025-02-11 16:25 ` [PULL 48/68] target/arm: Handle FPCR.AH in FMLSL (by element and vector) Peter Maydell
2025-02-11 16:25 ` [PULL 49/68] target/arm: Handle FPCR.AH in SVE FMLSL (indexed) Peter Maydell
2025-02-11 16:25 ` [PULL 50/68] target/arm: Handle FPCR.AH in SVE FMLSLB, FMLSLT (vectors) Peter Maydell
2025-02-11 16:25 ` [PULL 51/68] target/arm: Enable FEAT_AFP for '-cpu max' Peter Maydell
2025-02-11 16:25 ` [PULL 52/68] target/arm: Plumb FEAT_RPRES frecpe and frsqrte through to new helper Peter Maydell
2025-02-11 16:25 ` [PULL 53/68] target/arm: Implement increased precision FRECPE Peter Maydell
2025-02-11 16:25 ` [PULL 54/68] target/arm: Implement increased precision FRSQRTE Peter Maydell
2025-02-11 16:25 ` [PULL 55/68] target/arm: Enable FEAT_RPRES for -cpu max Peter Maydell
2025-02-11 16:25 ` [PULL 56/68] target/arm: Introduce CPUARMState.vfp.fp_status[] Peter Maydell
2025-02-11 16:25 ` [PULL 57/68] target/arm: Remove standard_fp_status_f16 Peter Maydell
2025-02-11 16:25 ` [PULL 58/68] target/arm: Remove standard_fp_status Peter Maydell
2025-02-11 16:25 ` [PULL 59/68] target/arm: Remove ah_fp_status_f16 Peter Maydell
2025-02-11 16:25 ` [PULL 60/68] target/arm: Remove ah_fp_status Peter Maydell
2025-02-11 16:25 ` [PULL 61/68] target/arm: Remove fp_status_f16_a64 Peter Maydell
2025-02-11 16:25 ` [PULL 62/68] target/arm: Remove fp_status_f16_a32 Peter Maydell
2025-02-11 16:25 ` [PULL 63/68] target/arm: Remove fp_status_a64 Peter Maydell
2025-02-11 16:25 ` [PULL 64/68] target/arm: Remove fp_status_a32 Peter Maydell
2025-02-11 16:25 ` [PULL 65/68] target/arm: Simplify fp_status indexing in mve_helper.c Peter Maydell
2025-02-11 16:25 ` [PULL 66/68] target/arm: Simplify DO_VFP_cmp in vfp_helper.c Peter Maydell
2025-02-11 16:25 ` [PULL 67/68] target/arm: Read fz16 from env->vfp.fpcr Peter Maydell
2025-02-11 16:25 ` [PULL 68/68] target/arm: Sink fp_status and fpcr access into do_fmlal* Peter Maydell
2025-02-12 17:38 ` [PULL 00/68] target-arm queue Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250211162554.4135349-3-peter.maydell@linaro.org \
--to=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).