[PATCH v2] MIPS: NaN encoding fixes and IEEE 754-2008 updates

Maciej W. Rozycki macro@codesourcery.com
Fri Mar 21 20:20:00 GMT 2014


Hi,

 As many of you have been aware it has been a long practice for software
using IEEE 754 floating-point arithmetic run on MIPS processors to use an
encoding of Not-a-Number (NaN) data different to one used by software run
on other processors.  And as of IEEE 754-2008 revision this encoding does
not follow one recommended in the standard, as specified in section 6.2.1,
where it is stated that quiet NaNs should have the first bit (d1) of their
significand set to 1 while signalling NaNs should have that bit set to 0,
but MIPS software interprets the two bits in the opposite manner.

 A recent MIPS Architecture revision[1][2] provides for processors that 
support the IEEE 754-2008 preferred NaN encoding format.  As the two 
formats (further referred to as "legacy NaN" and "2008 NaN") are 
incompatible to each other, tools have been updated to provide support for 
the two formats to help people avoid using incompatible binary modules.  
In particular GCC versions that produce the 2008 NaN encoding predefine 
the `__mips_nan2008' macro that can be used to select code to compile at 
the preprocessor level.

 This change corrects inconsistencies for the MIPS target in NaN encodings 
between endiannesses and makes sure the correct encodings are used both in 
the legacy-NaN and the 2008-NaN mode.

 This code unconditionally expects floating-point types having the 
significand field width of 24, 53, 64 and 113 bits to be present.  
Additionally the 64-bit format expects the leading significand bit to be 
explicitly encoded as in Intel x86/x87 FPUs.  Having no better choice I 
have implemented the handling of these extra data types as they might be 
reasonably implemented by MIPS hardware.  Ideally this code should be 
audited and dead pieces disabled for targets that do not use them.

 Furthermore some macros are present that encode constants comprising 
whole or parts of NaN data of different widths.  They use different 
encodings and data formats between endiannesses, apparently implying the 
Intel x86/x87 format for the little endianness and Motorola M68k format 
for the big endianness.  Neither fully applies for MIPS targets, so I have 
added separate definitions for the values that make sense and are actually 
referred to from code elsewhere.  Any future references to the currently 
unused macros defined for non-MIPS targets to support a long double data 
type will cause a build failure on MIPS, which is exactly what we want.

 For nan and nanf I decided to switch to __builtin_nan and __builtin_nanf 
respectively as the implementation where available -- which is always true 
for GCC versions that support the 2008-NaN encoding on the MIPS target.  
These built-ins guarantee the correct NaN encoding for all platforms and 
compilation options and are already used elsewhere in Newlib (which is 
where I copied the preprocessor condition from).

 For MIPS, additionally, in many cases they produce slightly better or at 
worst identical code; unfortunately in some other ones GCC misses the 
opportunity to inline the value loaded -- it looks to me like with these 
built-ins the compiler always insists to put the value loaded in memory.  
I don't think this should stop us from using them regardless though, the 
maintainability gain is too high compared to the memory loss, which is on 
the order of 4 to 8 bytes.

 FWIW I have regression-tested the change with the mips-sde-elf target, 
although I can't say this provides much value as the newlib test suite 
doesn't seem to cover much of IEEE arithmetic.  However this change has 
been used for ~1yr with the Mentor CodeBench toolchain with no problems 
spotted.

 Please apply.

2013-03-21  Maciej W. Rozycki  <macro@codesourcery.com>

	newlib/
	* libc/stdlib/gd_qnan.h (f_QNAN, d_QNAN0, d_QNAN1): Add MIPS
	versions.
	(ld_QNAN0, ld_QNAN1, ld_QNAN2, ld_QNAN3): Don't define for MIPS.
	(ldus_QNAN0, ldus_QNAN1, ldus_QNAN2, ldus_QNAN3, ldus_QNAN4):
	Likewise.
	* libc/stdlib/ldtoa.c (nan113, nan64, nan53, nan24): Add MIPS
	versions.
	(enan): Handle legacy MIPS payloads.
	* libm/common/s_nan.c (nan): Use __builtin_nan if supported by
	the compiler.
	* libm/common/sf_nan.c (nanf): Likewise.

  Maciej

 References:

[1] "MIPS Architecture For Programmers, Volume I-A: Introduction to the 
     MIPS32 Architecture", MIPS Technologies, Inc., Document Number: 
     MD00082, Revision 5.03, Sept. 9, 2013, Section 5.4.1.5 "Quiet 
     Non-Number (QNaN)", p. 71,

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
     MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
     MD00083, Revision 5.03, Sept. 9, 2013, Section 5.4.1.5 "Quiet 
     Non-Number (QNaN)", p. 74.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: newlib-mips-nan2008.diff
Type: text/x-diff
Size: 6191 bytes
Desc: 
URL: <http://sourceware.org/pipermail/newlib/attachments/20140321/9f6020de/attachment.bin>


More information about the Newlib mailing list