mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
alpha: determine tininess after rounding in the FP emulation
IEEE 754 lets an architecture determine tininess of a floating-point
result either before or after rounding, but requires the same choice for
every operation. Alpha determines it after rounding, and stdlib's
tst-tininess confirms the hardware does so for the results it produces
itself.
The soft-fp emulation has no notion of the distinction and always
determines tininess before rounding, so a result that the hardware would
not consider tiny is reported as underflowing whenever the instruction
happens to trap for software completion. The two paths then disagree on
the same machine. A multiply of the largest subnormal double by
1 + 2^-52 rounds up to the smallest normal and raises no underflow when
the operands are normal, but raises it when an operand is subnormal and
the instruction traps:
glibc math testsuite, test-float32x-float64-mul:
Failure: mul_double (0x3.ffffffffffffcp-1024, 0x1.0000000000001p+0):
Exception "Underflow" set
Add _FP_TININESS_AFTER_ROUNDING, as glibc's copy of soft-fp has, and set
it for alpha. It determines tininess by rounding a copy of the result as
if the exponent range were unbounded, which is what the definition asks
for. A plain check of whether the rounded result came out normal is not
equivalent: it differs for values that are still tiny once rounded with
an unbounded exponent range but reach the smallest normal on the coarser
subnormal grid. That plain check is what the hardware itself does (it
decides tininess from the delivered result), and it is why a divide such
as -0x4p-128 / 0x1.000002p+0 in FE_DOWNWARD delivers -0x1p-126 and raises
nothing although the result is tiny after rounding. Such cases do not
trap, so the emulation never sees them; where it does get control, it
follows the definition rather than reproducing that deviation, which is
what glibc's soft-fp does as well.
The macro defaults to zero, so powerpc, sh and sparc keep determining
tininess before rounding as they do now.
Cc: stable@vger.kernel.org # 5.15+
Reviewed-by: Magnus Lindholm <linmag7@gmail.com>
Tested-by: Magnus Lindholm <linmag7@gmail.com>
Link: https://lore.kernel.org/r/20260803-alpha-fp-exceptions-v1-3-c99d75608e60@gmail.com
Signed-off-by: Matt Turner <mattst88@gmail.com>
This commit is contained in:
parent
c03c1a1450
commit
b74843b38d
|
|
@ -59,6 +59,10 @@
|
|||
R##_c = FP_CLS_NAN; \
|
||||
} while (0)
|
||||
|
||||
/* Alpha determines tininess after rounding, so the emulation must do the
|
||||
same as the hardware does for the results it produces itself. */
|
||||
#define _FP_TININESS_AFTER_ROUNDING 1
|
||||
|
||||
/* Obtain the current rounding mode. */
|
||||
#define FP_ROUNDMODE mode
|
||||
#define FP_RND_NEAREST (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT)
|
||||
|
|
|
|||
|
|
@ -135,6 +135,24 @@ do { \
|
|||
else \
|
||||
{ \
|
||||
/* we've got a denormalized number */ \
|
||||
int _FP_PACK_CANONICAL_is_tiny = 1; \
|
||||
if (_FP_TININESS_AFTER_ROUNDING && X##_e == 0) \
|
||||
{ \
|
||||
/* Architectures that detect tininess after rounding \
|
||||
only signal underflow if the result is still \
|
||||
subnormal once rounded as if the exponent range \
|
||||
were unbounded. Round a copy to find out. */ \
|
||||
FP_DECL_##fs(_FP_PACK_CANONICAL_T); \
|
||||
/* The class field is not used by the rounding below, \
|
||||
and is unused entirely where this block is dead. */ \
|
||||
(void)_FP_PACK_CANONICAL_T##_c; \
|
||||
_FP_FRAC_COPY_##wc(_FP_PACK_CANONICAL_T, X); \
|
||||
_FP_PACK_CANONICAL_T##_s = X##_s; \
|
||||
_FP_PACK_CANONICAL_T##_e = X##_e; \
|
||||
_FP_ROUND(wc, _FP_PACK_CANONICAL_T); \
|
||||
if (_FP_FRAC_OVERP_##wc(fs, _FP_PACK_CANONICAL_T)) \
|
||||
_FP_PACK_CANONICAL_is_tiny = 0; \
|
||||
} \
|
||||
X##_e = -X##_e + 1; \
|
||||
if (X##_e <= _FP_WFRACBITS_##fs) \
|
||||
{ \
|
||||
|
|
@ -161,8 +179,9 @@ do { \
|
|||
_FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
|
||||
} \
|
||||
} \
|
||||
if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \
|
||||
(FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \
|
||||
if (_FP_PACK_CANONICAL_is_tiny \
|
||||
&& ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \
|
||||
(FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))) \
|
||||
FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \
|
||||
} \
|
||||
else \
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@
|
|||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
/* Whether the architecture determines tininess of a floating-point
|
||||
result after rounding rather than before it. IEEE 754 permits either
|
||||
but requires the same choice for every operation, so this has to agree
|
||||
with what the hardware does for the results it produces itself. */
|
||||
#ifndef _FP_TININESS_AFTER_ROUNDING
|
||||
#define _FP_TININESS_AFTER_ROUNDING 0
|
||||
#endif
|
||||
|
||||
#define _FP_WORKBITS 3
|
||||
#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3)
|
||||
#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user