mirror of
https://github.com/qemu/qemu.git
synced 2024-11-28 14:24:02 +08:00
softfloat: Adjust parts_uncanon_normal for floatx80
With floatx80_precision_x, the rounding happens across the break between words. Notice this case with frac_lsb = round_mask + 1 -> 0 and check the bits in frac_hi as needed. In addition, since frac_shift == 0, we won't implicitly clear round_mask via the right-shift, so explicitly clear those bits. This fixes rounding for floatx80_precision_[sd]. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
8da5f1dbb0
commit
98b3cff753
@ -155,7 +155,13 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
|
|||||||
|
|
||||||
switch (s->float_rounding_mode) {
|
switch (s->float_rounding_mode) {
|
||||||
case float_round_nearest_even:
|
case float_round_nearest_even:
|
||||||
inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
|
if (N > 64 && frac_lsb == 0) {
|
||||||
|
inc = ((p->frac_hi & 1) || (p->frac_lo & round_mask) != frac_lsbm1
|
||||||
|
? frac_lsbm1 : 0);
|
||||||
|
} else {
|
||||||
|
inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1
|
||||||
|
? frac_lsbm1 : 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case float_round_ties_away:
|
case float_round_ties_away:
|
||||||
inc = frac_lsbm1;
|
inc = frac_lsbm1;
|
||||||
@ -176,7 +182,11 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
|
|||||||
overflow_norm = true;
|
overflow_norm = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case float_round_to_odd_inf:
|
case float_round_to_odd_inf:
|
||||||
|
if (N > 64 && frac_lsb == 0) {
|
||||||
|
inc = p->frac_hi & 1 ? 0 : round_mask;
|
||||||
|
} else {
|
||||||
inc = p->frac_lo & frac_lsb ? 0 : round_mask;
|
inc = p->frac_lo & frac_lsb ? 0 : round_mask;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
@ -191,8 +201,8 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
|
|||||||
p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
|
p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
|
||||||
exp++;
|
exp++;
|
||||||
}
|
}
|
||||||
|
p->frac_lo &= ~round_mask;
|
||||||
}
|
}
|
||||||
frac_shr(p, frac_shift);
|
|
||||||
|
|
||||||
if (fmt->arm_althp) {
|
if (fmt->arm_althp) {
|
||||||
/* ARM Alt HP eschews Inf and NaN for a wider exponent. */
|
/* ARM Alt HP eschews Inf and NaN for a wider exponent. */
|
||||||
@ -201,18 +211,21 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
|
|||||||
flags = float_flag_invalid;
|
flags = float_flag_invalid;
|
||||||
exp = exp_max;
|
exp = exp_max;
|
||||||
frac_allones(p);
|
frac_allones(p);
|
||||||
|
p->frac_lo &= ~round_mask;
|
||||||
}
|
}
|
||||||
} else if (unlikely(exp >= exp_max)) {
|
} else if (unlikely(exp >= exp_max)) {
|
||||||
flags |= float_flag_overflow | float_flag_inexact;
|
flags |= float_flag_overflow | float_flag_inexact;
|
||||||
if (overflow_norm) {
|
if (overflow_norm) {
|
||||||
exp = exp_max - 1;
|
exp = exp_max - 1;
|
||||||
frac_allones(p);
|
frac_allones(p);
|
||||||
|
p->frac_lo &= ~round_mask;
|
||||||
} else {
|
} else {
|
||||||
p->cls = float_class_inf;
|
p->cls = float_class_inf;
|
||||||
exp = exp_max;
|
exp = exp_max;
|
||||||
frac_clear(p);
|
frac_clear(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
frac_shr(p, frac_shift);
|
||||||
} else if (s->flush_to_zero) {
|
} else if (s->flush_to_zero) {
|
||||||
flags |= float_flag_output_denormal;
|
flags |= float_flag_output_denormal;
|
||||||
p->cls = float_class_zero;
|
p->cls = float_class_zero;
|
||||||
@ -232,18 +245,29 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
|
|||||||
/* Need to recompute round-to-even/round-to-odd. */
|
/* Need to recompute round-to-even/round-to-odd. */
|
||||||
switch (s->float_rounding_mode) {
|
switch (s->float_rounding_mode) {
|
||||||
case float_round_nearest_even:
|
case float_round_nearest_even:
|
||||||
|
if (N > 64 && frac_lsb == 0) {
|
||||||
|
inc = ((p->frac_hi & 1) ||
|
||||||
|
(p->frac_lo & round_mask) != frac_lsbm1
|
||||||
|
? frac_lsbm1 : 0);
|
||||||
|
} else {
|
||||||
inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1
|
inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1
|
||||||
? frac_lsbm1 : 0);
|
? frac_lsbm1 : 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case float_round_to_odd:
|
case float_round_to_odd:
|
||||||
case float_round_to_odd_inf:
|
case float_round_to_odd_inf:
|
||||||
|
if (N > 64 && frac_lsb == 0) {
|
||||||
|
inc = p->frac_hi & 1 ? 0 : round_mask;
|
||||||
|
} else {
|
||||||
inc = p->frac_lo & frac_lsb ? 0 : round_mask;
|
inc = p->frac_lo & frac_lsb ? 0 : round_mask;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
flags |= float_flag_inexact;
|
flags |= float_flag_inexact;
|
||||||
frac_addi(p, p, inc);
|
frac_addi(p, p, inc);
|
||||||
|
p->frac_lo &= ~round_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0;
|
exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user