Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: math-emu: Add IEEE Std 754-2008 NaN encoding emulation

Implement IEEE Std 754-2008 NaN encoding wired to the state of the
FCSR.NAN2008 bit. Make the interpretation of the quiet bit in NaN data
as follows:

* in the legacy mode originally defined by the MIPS architecture the
value of 1 denotes an sNaN whereas the value of 0 denotes a qNaN,

* in the 2008 mode introduced with revision 5 of the MIPS architecture
the value of 0 denotes an sNaN whereas the value of 1 denotes a qNaN,
following the definition of the preferred NaN encoding introduced with
IEEE Std 754-2008.

In the 2008 mode, following the requirement of the said standard, quiet
an sNaN where needed by setting the quiet bit to 1 and leaving all the
NaN payload bits unchanged.

Update format conversion operations according to the rules set by IEEE
Std 754-2008 and the MIPS architecture. Specifically:

* propagate NaN payload bits through conversions between floating-point
formats such that as much information as possible is preserved and
specifically a conversion from a narrower format to a wider format and
then back to the original format does not change a qNaN payload in any
way,

* conversions from a floating-point to an integer format where the
source is a NaN, infinity or a value that would convert to an integer
outside the range of the result format produce, under the default
exception handling, the respective values defined by the MIPS
architecture.

In full FPU emulation set the FIR.HAS2008 bit to 1, however do not make
any further FCSR bits writable.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Matthew Fortune <Matthew.Fortune@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/11477/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Maciej W. Rozycki and committed by
Ralf Baechle
90d53a91 198f7058

+93 -42
+2
arch/mips/kernel/cpu-probe.c
··· 113 113 if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 114 114 MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) 115 115 value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W; 116 + if (c->options & MIPS_CPU_NAN_2008) 117 + value |= MIPS_FPIR_HAS2008; 116 118 c->fpu_id = value; 117 119 } 118 120
+6 -3
arch/mips/math-emu/dp_tint.c
··· 38 38 switch (xc) { 39 39 case IEEE754_CLASS_SNAN: 40 40 case IEEE754_CLASS_QNAN: 41 - case IEEE754_CLASS_INF: 42 41 ieee754_setcx(IEEE754_INVALID_OPERATION); 43 42 return ieee754si_indef(); 43 + 44 + case IEEE754_CLASS_INF: 45 + ieee754_setcx(IEEE754_INVALID_OPERATION); 46 + return ieee754si_overflow(xs); 44 47 45 48 case IEEE754_CLASS_ZERO: 46 49 return 0; ··· 56 53 /* Set invalid. We will only use overflow for floating 57 54 point overflow */ 58 55 ieee754_setcx(IEEE754_INVALID_OPERATION); 59 - return ieee754si_indef(); 56 + return ieee754si_overflow(xs); 60 57 } 61 58 /* oh gawd */ 62 59 if (xe > DP_FBITS) { ··· 96 93 if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { 97 94 /* This can happen after rounding */ 98 95 ieee754_setcx(IEEE754_INVALID_OPERATION); 99 - return ieee754si_indef(); 96 + return ieee754si_overflow(xs); 100 97 } 101 98 if (round || sticky) 102 99 ieee754_setcx(IEEE754_INEXACT);
+6 -3
arch/mips/math-emu/dp_tlong.c
··· 38 38 switch (xc) { 39 39 case IEEE754_CLASS_SNAN: 40 40 case IEEE754_CLASS_QNAN: 41 - case IEEE754_CLASS_INF: 42 41 ieee754_setcx(IEEE754_INVALID_OPERATION); 43 42 return ieee754di_indef(); 43 + 44 + case IEEE754_CLASS_INF: 45 + ieee754_setcx(IEEE754_INVALID_OPERATION); 46 + return ieee754di_overflow(xs); 44 47 45 48 case IEEE754_CLASS_ZERO: 46 49 return 0; ··· 59 56 /* Set invalid. We will only use overflow for floating 60 57 point overflow */ 61 58 ieee754_setcx(IEEE754_INVALID_OPERATION); 62 - return ieee754di_indef(); 59 + return ieee754di_overflow(xs); 63 60 } 64 61 /* oh gawd */ 65 62 if (xe > DP_FBITS) { ··· 100 97 if ((xm >> 63) != 0) { 101 98 /* This can happen after rounding */ 102 99 ieee754_setcx(IEEE754_INVALID_OPERATION); 103 - return ieee754di_indef(); 100 + return ieee754di_overflow(xs); 104 101 } 105 102 if (round || sticky) 106 103 ieee754_setcx(IEEE754_INEXACT);
+4 -2
arch/mips/math-emu/ieee754.c
··· 59 59 DPCNST(1, 3, 0x4000000000000ULL), /* - 10.0 */ 60 60 DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL), /* + infinity */ 61 61 DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL), /* - infinity */ 62 - DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + indef quiet Nan */ 62 + DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL), /* + ind legacy qNaN */ 63 + DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL), /* + indef 2008 qNaN */ 63 64 DPCNST(0, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* + max */ 64 65 DPCNST(1, DP_EMAX, 0xFFFFFFFFFFFFFULL), /* - max */ 65 66 DPCNST(0, DP_EMIN, 0x0000000000000ULL), /* + min normal */ ··· 83 82 SPCNST(1, 3, 0x200000), /* - 10.0 */ 84 83 SPCNST(0, SP_EMAX + 1, 0x000000), /* + infinity */ 85 84 SPCNST(1, SP_EMAX + 1, 0x000000), /* - infinity */ 86 - SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef quiet Nan */ 85 + SPCNST(0, SP_EMAX + 1, 0x3FFFFF), /* + indef legacy quiet NaN */ 86 + SPCNST(0, SP_EMAX + 1, 0x400000), /* + indef 2008 quiet NaN */ 87 87 SPCNST(0, SP_EMAX, 0x7FFFFF), /* + max normal */ 88 88 SPCNST(1, SP_EMAX, 0x7FFFFF), /* - max normal */ 89 89 SPCNST(0, SP_EMIN, 0x000000), /* + min normal */
+29 -13
arch/mips/math-emu/ieee754.h
··· 221 221 #define IEEE754_SPCVAL_NTEN 5 /* -10.0 */ 222 222 #define IEEE754_SPCVAL_PINFINITY 6 /* +inf */ 223 223 #define IEEE754_SPCVAL_NINFINITY 7 /* -inf */ 224 - #define IEEE754_SPCVAL_INDEF 8 /* quiet NaN */ 225 - #define IEEE754_SPCVAL_PMAX 9 /* +max norm */ 226 - #define IEEE754_SPCVAL_NMAX 10 /* -max norm */ 227 - #define IEEE754_SPCVAL_PMIN 11 /* +min norm */ 228 - #define IEEE754_SPCVAL_NMIN 12 /* -min norm */ 229 - #define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ 230 - #define IEEE754_SPCVAL_NMIND 14 /* -min denorm */ 231 - #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ 232 - #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ 224 + #define IEEE754_SPCVAL_INDEF_LEG 8 /* legacy quiet NaN */ 225 + #define IEEE754_SPCVAL_INDEF_2008 9 /* IEEE 754-2008 quiet NaN */ 226 + #define IEEE754_SPCVAL_PMAX 10 /* +max norm */ 227 + #define IEEE754_SPCVAL_NMAX 11 /* -max norm */ 228 + #define IEEE754_SPCVAL_PMIN 12 /* +min norm */ 229 + #define IEEE754_SPCVAL_NMIN 13 /* -min norm */ 230 + #define IEEE754_SPCVAL_PMIND 14 /* +min denorm */ 231 + #define IEEE754_SPCVAL_NMIND 15 /* -min denorm */ 232 + #define IEEE754_SPCVAL_P1E31 16 /* + 1.0e31 */ 233 + #define IEEE754_SPCVAL_P1E63 17 /* + 1.0e63 */ 233 234 234 235 extern const union ieee754dp __ieee754dp_spcvals[]; 235 236 extern const union ieee754sp __ieee754sp_spcvals[]; ··· 244 243 #define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 245 244 #define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 246 245 #define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 247 - #define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) 246 + #define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \ 247 + ieee754_csr.nan2008]) 248 248 #define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 249 249 #define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 250 250 #define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) ··· 256 254 #define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 257 255 #define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 258 256 #define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 259 - #define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) 257 + #define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \ 258 + ieee754_csr.nan2008]) 260 259 #define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 261 260 #define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 262 261 #define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) ··· 269 266 */ 270 267 static inline int ieee754si_indef(void) 271 268 { 272 - return INT_MAX; 269 + return ieee754_csr.nan2008 ? 0 : INT_MAX; 273 270 } 274 271 275 272 static inline s64 ieee754di_indef(void) 276 273 { 277 - return S64_MAX; 274 + return ieee754_csr.nan2008 ? 0 : S64_MAX; 275 + } 276 + 277 + /* 278 + * Overflow integer value 279 + */ 280 + static inline int ieee754si_overflow(int xs) 281 + { 282 + return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX; 283 + } 284 + 285 + static inline s64 ieee754di_overflow(int xs) 286 + { 287 + return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX; 278 288 } 279 289 280 290 /* result types for xctx.rt */
+10 -2
arch/mips/math-emu/ieee754dp.c
··· 37 37 38 38 static inline int ieee754dp_issnan(union ieee754dp x) 39 39 { 40 + int qbit; 41 + 40 42 assert(ieee754dp_isnan(x)); 41 - return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); 43 + qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); 44 + return ieee754_csr.nan2008 ^ qbit; 42 45 } 43 46 44 47 ··· 54 51 assert(ieee754dp_issnan(r)); 55 52 56 53 ieee754_setcx(IEEE754_INVALID_OPERATION); 57 - return ieee754dp_indef(); 54 + if (ieee754_csr.nan2008) 55 + DPMANT(r) |= DP_MBIT(DP_FBITS - 1); 56 + else 57 + r = ieee754dp_indef(); 58 + 59 + return r; 58 60 } 59 61 60 62 static u64 ieee754dp_get_rounding(int sn, u64 xm)
+6 -6
arch/mips/math-emu/ieee754int.h
··· 63 63 if (ve == SP_EMAX+1+SP_EBIAS) { \ 64 64 if (vm == 0) \ 65 65 vc = IEEE754_CLASS_INF; \ 66 - else if (vm & SP_MBIT(SP_FBITS-1)) \ 67 - vc = IEEE754_CLASS_SNAN; \ 68 - else \ 66 + else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \ 69 67 vc = IEEE754_CLASS_QNAN; \ 68 + else \ 69 + vc = IEEE754_CLASS_SNAN; \ 70 70 } else if (ve == SP_EMIN-1+SP_EBIAS) { \ 71 71 if (vm) { \ 72 72 ve = SP_EMIN; \ ··· 97 97 if (ve == DP_EMAX+1+DP_EBIAS) { \ 98 98 if (vm == 0) \ 99 99 vc = IEEE754_CLASS_INF; \ 100 - else if (vm & DP_MBIT(DP_FBITS-1)) \ 101 - vc = IEEE754_CLASS_SNAN; \ 102 - else \ 100 + else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \ 103 101 vc = IEEE754_CLASS_QNAN; \ 102 + else \ 103 + vc = IEEE754_CLASS_SNAN; \ 104 104 } else if (ve == DP_EMIN-1+DP_EBIAS) { \ 105 105 if (vm) { \ 106 106 ve = DP_EMIN; \
+10 -2
arch/mips/math-emu/ieee754sp.c
··· 37 37 38 38 static inline int ieee754sp_issnan(union ieee754sp x) 39 39 { 40 + int qbit; 41 + 40 42 assert(ieee754sp_isnan(x)); 41 - return SPMANT(x) & SP_MBIT(SP_FBITS - 1); 43 + qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1); 44 + return ieee754_csr.nan2008 ^ qbit; 42 45 } 43 46 44 47 ··· 54 51 assert(ieee754sp_issnan(r)); 55 52 56 53 ieee754_setcx(IEEE754_INVALID_OPERATION); 57 - return ieee754sp_indef(); 54 + if (ieee754_csr.nan2008) 55 + SPMANT(r) |= SP_MBIT(SP_FBITS - 1); 56 + else 57 + r = ieee754sp_indef(); 58 + 59 + return r; 58 60 } 59 61 60 62 static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
+8 -5
arch/mips/math-emu/sp_fdp.c
··· 44 44 45 45 switch (xc) { 46 46 case IEEE754_CLASS_SNAN: 47 - return ieee754sp_nanxcpt(ieee754sp_nan_fdp(xs, xm)); 48 - 47 + x = ieee754dp_nanxcpt(x); 48 + EXPLODEXDP; 49 + /* Fall through. */ 49 50 case IEEE754_CLASS_QNAN: 50 51 y = ieee754sp_nan_fdp(xs, xm); 51 - EXPLODEYSP; 52 - if (!ieee754_class_nan(yc)) 53 - y = ieee754sp_indef(); 52 + if (!ieee754_csr.nan2008) { 53 + EXPLODEYSP; 54 + if (!ieee754_class_nan(yc)) 55 + y = ieee754sp_indef(); 56 + } 54 57 return y; 55 58 56 59 case IEEE754_CLASS_INF:
+6 -3
arch/mips/math-emu/sp_tint.c
··· 38 38 switch (xc) { 39 39 case IEEE754_CLASS_SNAN: 40 40 case IEEE754_CLASS_QNAN: 41 - case IEEE754_CLASS_INF: 42 41 ieee754_setcx(IEEE754_INVALID_OPERATION); 43 42 return ieee754si_indef(); 43 + 44 + case IEEE754_CLASS_INF: 45 + ieee754_setcx(IEEE754_INVALID_OPERATION); 46 + return ieee754si_overflow(xs); 44 47 45 48 case IEEE754_CLASS_ZERO: 46 49 return 0; ··· 59 56 /* Set invalid. We will only use overflow for floating 60 57 point overflow */ 61 58 ieee754_setcx(IEEE754_INVALID_OPERATION); 62 - return ieee754si_indef(); 59 + return ieee754si_overflow(xs); 63 60 } 64 61 /* oh gawd */ 65 62 if (xe > SP_FBITS) { ··· 100 97 if ((xm >> 31) != 0) { 101 98 /* This can happen after rounding */ 102 99 ieee754_setcx(IEEE754_INVALID_OPERATION); 103 - return ieee754si_indef(); 100 + return ieee754si_overflow(xs); 104 101 } 105 102 if (round || sticky) 106 103 ieee754_setcx(IEEE754_INEXACT);
+6 -3
arch/mips/math-emu/sp_tlong.c
··· 39 39 switch (xc) { 40 40 case IEEE754_CLASS_SNAN: 41 41 case IEEE754_CLASS_QNAN: 42 - case IEEE754_CLASS_INF: 43 42 ieee754_setcx(IEEE754_INVALID_OPERATION); 44 43 return ieee754di_indef(); 44 + 45 + case IEEE754_CLASS_INF: 46 + ieee754_setcx(IEEE754_INVALID_OPERATION); 47 + return ieee754di_overflow(xs); 45 48 46 49 case IEEE754_CLASS_ZERO: 47 50 return 0; ··· 60 57 /* Set invalid. We will only use overflow for floating 61 58 point overflow */ 62 59 ieee754_setcx(IEEE754_INVALID_OPERATION); 63 - return ieee754di_indef(); 60 + return ieee754di_overflow(xs); 64 61 } 65 62 /* oh gawd */ 66 63 if (xe > SP_FBITS) { ··· 97 94 if ((xm >> 63) != 0) { 98 95 /* This can happen after rounding */ 99 96 ieee754_setcx(IEEE754_INVALID_OPERATION); 100 - return ieee754di_indef(); 97 + return ieee754di_overflow(xs); 101 98 } 102 99 if (round || sticky) 103 100 ieee754_setcx(IEEE754_INEXACT);