aboutsummaryrefslogtreecommitdiff
path: root/fpu
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-08-20 17:28:33 -0700
committerRichard Henderson <richard.henderson@linaro.org>2023-09-16 14:57:16 +0000
commit722460652b3aee89dc19df61f1f33df53a9b97c9 (patch)
tree84cca92504817a5b1ccb466fa918e8cebb262090 /fpu
parent00f9ef8f3dd6940001311a6230985243c3ebb996 (diff)
fpu: Handle m68k extended precision denormals properly
Motorola treats denormals with explicit integer bit set as having unbiased exponent 0, unlike Intel which treats it as having unbiased exponent 1 (more like all other IEEE formats that have no explicit integer bit). Add a flag on FloatFmt to differentiate the behaviour. Reported-by: Keith Packard <keithp@keithp.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'fpu')
-rw-r--r--fpu/softfloat-parts.c.inc7
-rw-r--r--fpu/softfloat.c9
2 files changed, 12 insertions, 4 deletions
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 527e15e6ab..a44649f4f4 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -118,7 +118,8 @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
} else {
int shift = frac_normalize(p);
p->cls = float_class_normal;
- p->exp = fmt->frac_shift - fmt->exp_bias - shift + 1;
+ p->exp = fmt->frac_shift - fmt->exp_bias
+ - shift + !fmt->m68k_denormal;
}
} else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
p->cls = float_class_normal;
@@ -256,7 +257,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
is_tiny = !frac_addi(&discard, p, inc);
}
- frac_shrjam(p, 1 - exp);
+ frac_shrjam(p, !fmt->m68k_denormal - exp);
if (p->frac_lo & round_mask) {
/* Need to recompute round-to-even/round-to-odd. */
@@ -287,7 +288,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
p->frac_lo &= ~round_mask;
}
- exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0;
+ exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !fmt->m68k_denormal;
frac_shr(p, frac_shift);
if (is_tiny && (flags & float_flag_inexact)) {
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 2a33967094..027a8e576d 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -517,6 +517,7 @@ typedef struct {
* round_mask: bits below lsb which must be rounded
* The following optional modifiers are available:
* arm_althp: handle ARM Alternative Half Precision
+ * m68k_denormal: explicit integer bit for extended precision may be 1
*/
typedef struct {
int exp_size;
@@ -526,6 +527,7 @@ typedef struct {
int frac_size;
int frac_shift;
bool arm_althp;
+ bool m68k_denormal;
uint64_t round_mask;
} FloatFmt;
@@ -576,7 +578,12 @@ static const FloatFmt float128_params = {
static const FloatFmt floatx80_params[3] = {
[floatx80_precision_s] = { FLOATX80_PARAMS(23) },
[floatx80_precision_d] = { FLOATX80_PARAMS(52) },
- [floatx80_precision_x] = { FLOATX80_PARAMS(64) },
+ [floatx80_precision_x] = {
+ FLOATX80_PARAMS(64),
+#ifdef TARGET_M68K
+ .m68k_denormal = true,
+#endif
+ },
};
/* Unpack a float to parts, but do not canonicalize. */