This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC][PATCH] MIPS: IEEE 754-2008 NaN encoding support
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <libc-ports at sourceware dot org>, <libc-alpha at sourceware dot org>
- Cc: Doug Gilmore <Doug dot Gilmore at imgtec dot com>
- Date: Fri, 23 Aug 2013 00:52:43 +0100
- Subject: [RFC][PATCH] MIPS: IEEE 754-2008 NaN encoding support
Hi,
This change is sent as an RFC only at this time, because it relies on
Linux kernel functionality that has not been integrated upstream yet.
The minimum kernel version required set in this change has been therefore
artificially fixed at 3.11.0, the current version number of the Linux
kernel. This requirement will be adjusted appropriately in the final
version of this change. Feedback is welcome on this implementation so
that it can be swiftly integrated once the required kernel support has
been put in place.
Also I would appreciate if we could keep sysdeps/generic/ldconfig.h cache
flag slots 0x0c00, 0x0d00 and 0x0e00 reserved from now on and until this
change has been finally accepted.
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 [1] 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.
As from revision 3.50 [2][3] the MIPS Architecture 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 will have to provide support for the
two formats to help people avoid using incompatible binary modules. Here
is the glibc part.
The change is comprised of two functional groups of features, both of
which are required for correct support.
1. Dynamic linker support.
To enforce the NaN encoding requirement in dynamic linking a new ELF
file header flag has been defined. This flag is set for 2008-NaN
shared modules and executables and clear for legacy-NaN ones. The
dynamic linker silently ignores any incompatible modules it encounters
in dependency processing.
To avoid unnecessary processing of incompatible modules in the presence
of a shared module cache, a set of new cache flags has been defined to
mark 2008-NaN modules for the three ABIs supported. Changes to
sysdeps/unix/sysv/linux/mips/readelflib.c have been made following
an earlier code quality suggestion made here:
http://sourceware.org/ml/libc-ports/2009-03/msg00036.html
and are therefore a little bit more extensive than the minimum
required.
Finally a new name has been defined for the dynamic linker so that
2008-NaN and legacy-NaN binaries can coexist on a single system that
supports dual-mode operation and that a legacy dynamic linker that
does not support verifying the 2008-NaN ELF file header flag is not
chosen to interpret a 2008-NaN binary by accident.
2. Floating environment support.
IEEE 754-2008 features are controlled in the Floating-Point Control and
Status (FCSR) register and updates are needed to floating environment
support so that the 2008-NaN flag is set correctly and the kernel
default, inferred from the 2008-NaN ELF file header flag at the time
an executable is loaded, respected.
As the NaN encoding format is a property of GCC code generation that is
both a user-selected GCC configuration default and can be overridden with
GCC options, code that needs to know what NaN encoding standard it has
been configured for checks for the __mips_nan2008 macro that is defined
internally by GCC whenever the 2008-NaN mode has been selected. This mode
is determined at the glibc configuration time and therefore a few
consistency checks have been added to catch cases where compilation flags
have been overridden by the user.
The 2008 NaN set of features relies on kernel support as the in-kernel
floating-point emulator needs to be aware of the NaN encoding used even on
hard-float processors and configure the FPU context according to the value
of the 2008 NaN ELF file header flag of the executable being started.
Therefore the minimum version supported has been adjusted where glibc is
built for the 2008 NaN encoding. Legacy NaN encoding support is
unaffected, older kernel versions remain supported.
Preliminary mips-linux-gnu testing with the o32, n64 and n32 ABIs, legacy
NaN showed no regressions.
Questions, comments?
References:
[1] "IEEE Standard for Floating-Point Arithmetic", IEEE Computer Society,
IEEE Std 754-2008, 29 August 2008
[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
MIPS32 Architecture", MIPS Technologies, Inc., Document Number:
MD00082, Revision 3.50, September 20, 2012
[3] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
MD00083, Revision 3.50, September 20, 2012
2012-08-22 Maciej W. Rozycki <macro@codesourcery.com>
ChangeLog:
* config.h.in (HAVE_MIPS_NAN2008): New macro.
* elf/elf.h (EF_MIPS_NAN2008): Likewise.
* sysdeps/generic/ldconfig.h (FLAG_MIPS_LIB32_NAN2008): Likewise.
(FLAG_MIPS64_LIBN32_NAN2008): Likewise.
(FLAG_MIPS64_LIBN64_NAN2008): Likewise.
* elf/cache.c (print_entry): Handle the new cache flags.
ports/ChangeLog.mips
* sysdeps/mips/dl-machine.h (ELF_MACHINE_NAN2008): New macro.
(elf_machine_matches_host): Reject objects that use a different
NaN encoding convention.
* sysdeps/mips/fpu_control.h: Document IEEE 754-2008 feature
control bits.
(_FPU_ABS2008, _FPU_NAN2008): New macros.
(_FPU_RESERVED): Clear bits #20 and #19.
(_FPU_DEFAULT) [__mips_nan2008]: Set bit #18.
(_FPU_IEEE) [__mips_nan2008]: Likewise.
* sysdeps/mips/mips64/soft-fp/sfp-machine.h [__mips_nan2008]
(_FP_NANFRAC_S, _FP_NANFRAC_D, _FP_NANFRAC_Q): Define 2008-NaN
payloads.
(_FP_QNANNEGATEDP): Set to 0.
* sysdeps/mips/soft-fp/sfp-machine.h [__mips_nan2008]
(_FP_NANFRAC_S, _FP_NANFRAC_D, _FP_NANFRAC_Q): Define 2008-NaN
payloads.
(_FP_QNANNEGATEDP): Set to 0.
* sysdeps/unix/sysv/linux/mips/dl-cache.h (_DL_CACHE_DEFAULT_ID):
Define 2008 NaN encoding values.
* sysdeps/mips/fpu/fesetenv.c (fesetenv): Do not allow to flip
the _FPU_NAN2008 bit.
* sysdeps/unix/sysv/linux/mips/readelflib.c (process_elf_file):
Handle 2008-NaN libraries.
* sysdeps/mips/shlib-versions [HAVE_MIPS_NAN2008]: Set
ld=ld-linux-mipsn8.so.1.
* sysdeps/mips/configure.in: Define HAVE_MIPS_NAN2008 if the
2008 NaN encoding is used.
* sysdeps/unix/sysv/linux/mips/configure.in: Set
arch_minimum_kernel to 3.11.0 if 2008 NaN encoding is used.
* sysdeps/mips/configure: Regenerate.
* sysdeps/unix/sysv/linux/mips/configure: Regenerate.
Maciej
glibc-mips-nan2008.diff
Index: glibc-fsf-trunk-quilt/config.h.in
===================================================================
--- glibc-fsf-trunk-quilt.orig/config.h.in 2013-08-20 15:18:10.000000000 +0100
+++ glibc-fsf-trunk-quilt/config.h.in 2013-08-22 10:32:05.447640501 +0100
@@ -241,4 +241,8 @@
/* The pt_chown binary is being built and used by grantpt. */
#undef HAVE_PT_CHOWN
+/* ports/sysdeps/mips/configure.in */
+/* Define if using the IEEE 754-2008 NaN encoding on the MIPS target. */
+#undef HAVE_MIPS_NAN2008
+
#endif
Index: glibc-fsf-trunk-quilt/elf/cache.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/elf/cache.c 2013-05-21 00:20:30.000000000 +0100
+++ glibc-fsf-trunk-quilt/elf/cache.c 2013-08-22 10:32:05.447640501 +0100
@@ -105,6 +105,15 @@ print_entry (const char *lib, int flag,
case FLAG_ARM_LIBSF:
fputs (",soft-float", stdout);
break;
+ case FLAG_MIPS_LIB32_NAN2008:
+ fputs (",nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN32_NAN2008:
+ fputs (",N32,nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN64_NAN2008:
+ fputs (",64bit,nan2008", stdout);
+ break;
case 0:
break;
default:
Index: glibc-fsf-trunk-quilt/elf/elf.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/elf/elf.h 2013-06-26 18:42:44.000000000 +0100
+++ glibc-fsf-trunk-quilt/elf/elf.h 2013-08-22 10:32:05.447640501 +0100
@@ -1383,6 +1383,7 @@ typedef struct
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
/* Legal values for MIPS architecture level. */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/configure
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/configure 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/configure 2013-08-22 10:32:05.447640501 +0100
@@ -1,3 +1,163 @@
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
# Local configure fragment for sysdeps/mips.
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler is using the 2008 NaN encoding" >&5
+$as_echo_n "checking whether the compiler is using the 2008 NaN encoding... " >&6; }
+if ${libc_cv_mips_nan2008+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+dnl
+#ifdef __mips_nan2008
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ libc_cv_mips_nan2008=yes
+else
+ libc_cv_mips_nan2008=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_nan2008" >&5
+$as_echo "$libc_cv_mips_nan2008" >&6; }
+if test x$libc_cv_mips_nan2008 = xyes; then
+ $as_echo "#define HAVE_MIPS_NAN2008 1" >>confdefs.h
+
+fi
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/configure.in
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/configure.in 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/configure.in 2013-08-22 10:32:05.447640501 +0100
@@ -4,3 +4,12 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the
dnl No MIPS GCC supports accessing static and hidden symbols in an
dnl position independent way.
dnl AC_DEFINE(PI_STATIC_AND_HIDDEN)
+
+AC_CACHE_CHECK([whether the compiler is using the 2008 NaN encoding],
+ libc_cv_mips_nan2008, [AC_EGREP_CPP(yes, [dnl
+#ifdef __mips_nan2008
+yes
+#endif], libc_cv_mips_nan2008=yes, libc_cv_mips_nan2008=no)])
+if test x$libc_cv_mips_nan2008 = xyes; then
+ AC_DEFINE(HAVE_MIPS_NAN2008)
+fi
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/dl-machine.h 2013-05-30 00:49:41.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-machine.h 2013-08-22 10:32:05.447640501 +0100
@@ -73,6 +73,16 @@ do { if ((l)->l_info[DT_MIPS (RLD_MAP)])
(ElfW(Addr)) (r); \
} while (0)
+#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \
+ || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008))
+# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?"
+#endif
+#ifdef __mips_nan2008
+# define ELF_MACHINE_NAN2008 EF_MIPS_NAN2008
+#else
+# define ELF_MACHINE_NAN2008 0
+#endif
+
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int __attribute_used__
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
@@ -83,6 +93,10 @@ elf_machine_matches_host (const ElfW(Ehd
return 0;
#endif
+ /* Don't link 2008-NaN and legacy-NaN objects together. */
+ if ((ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008)
+ return 0;
+
switch (ehdr->e_machine)
{
case EM_MIPS:
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/fesetenv.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/fpu/fesetenv.c 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/fesetenv.c 2013-08-22 10:32:05.447640501 +0100
@@ -25,15 +25,16 @@ fesetenv (const fenv_t *envp)
{
fpu_control_t cw;
- /* Read first current state to flush fpu pipeline. */
_FPU_GETCW (cw);
if (envp == FE_DFL_ENV)
- _FPU_SETCW (_FPU_DEFAULT);
+ cw = _FPU_DEFAULT;
else if (envp == FE_NOMASK_ENV)
- _FPU_SETCW (_FPU_IEEE);
+ cw = _FPU_IEEE;
else
- _FPU_SETCW (envp->__fp_control_register);
+ cw = (cw & _FPU_NAN2008) | (envp->__fp_control_register & ~_FPU_NAN2008);
+
+ _FPU_SETCW (cw);
/* Success. */
return 0;
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu_control.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/fpu_control.h 2013-08-21 07:35:44.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu_control.h 2013-08-22 10:32:05.447640501 +0100
@@ -29,7 +29,9 @@
* available for MIPS III and newer.
* 23 -> Condition bit
* 22-21 -> reserved for architecture implementers
- * 20-18 -> reserved (read as 0, write with 0)
+ * 20 -> reserved (read as 0, write with 0)
+ * 19 -> IEEE 754-2008 non-arithmetic ABS.fmt and NEG.fmt enable
+ * 18 -> IEEE 754-2008 recommended NaN encoding enable
* 17 -> cause bit for unimplemented operation
* 16 -> cause bit for invalid exception
* 15 -> cause bit for division by zero exception
@@ -79,22 +81,33 @@ extern fpu_control_t __fpu_control;
/* flush denormalized numbers to zero */
#define _FPU_FLUSH_TZ 0x1000000
+/* IEEE 754-2008 compliance control. */
+#define _FPU_ABS2008 0x80000
+#define _FPU_NAN2008 0x40000
+
/* rounding control */
#define _FPU_RC_NEAREST 0x0 /* RECOMMENDED */
#define _FPU_RC_ZERO 0x1
#define _FPU_RC_UP 0x2
#define _FPU_RC_DOWN 0x3
-#define _FPU_RESERVED 0xfe9c0000 /* Reserved bits in cw */
+#define _FPU_RESERVED 0xfe840000 /* Reserved bits in cw, incl NAN2008. */
/* The fdlibm code requires strict IEEE double precision arithmetic,
and no interrupts for exceptions, rounding to nearest. */
-
+#ifdef __mips_nan2008
+#define _FPU_DEFAULT 0x00040000
+#else
#define _FPU_DEFAULT 0x00000000
+#endif
-/* IEEE: same as above, but exceptions */
+/* IEEE: same as above, but exceptions. */
+#ifdef __mips_nan2008
+#define _FPU_IEEE 0x00040F80
+#else
#define _FPU_IEEE 0x00000F80
+#endif
/* Type of the control word. */
typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h 2013-08-20 15:18:10.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h 2013-08-22 10:32:05.447640501 +0100
@@ -24,15 +24,25 @@
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
-#define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
-#define _FP_NANFRAC_D (_FP_QNANBIT_D - 1)
-#define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
+# define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
+#else
+# define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D (_FP_QNANBIT_D - 1)
+# define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1
+#endif
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
-#define _FP_QNANNEGATEDP 1
+#ifdef __mips_nan2008
+# define _FP_QNANNEGATEDP 0
+#else
+# define _FP_QNANNEGATEDP 1
+#endif
/* From my experiments it seems X is chosen unless one of the
NaNs is sNaN, in which case the result is NANSIGN/NANFRAC. */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/shlib-versions
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/shlib-versions 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/shlib-versions 2013-08-22 10:32:05.447640501 +0100
@@ -3,7 +3,11 @@ mips.*-.*-linux.* libm=6 GLIBC_2.0 GLI
# Working mips versions were never released between 2.0 and 2.2.
mips.*-.*-linux.* libc=6 GLIBC_2.0 GLIBC_2.2
+%ifdef HAVE_MIPS_NAN2008
+mips.*-.*-linux.* ld=ld-linux-mipsn8.so.1 GLIBC_2.0 GLIBC_2.2
+%else
mips.*-.*-linux.* ld=ld.so.1 GLIBC_2.0 GLIBC_2.2
+%endif
mips.*-.*-linux.* libdl=2 GLIBC_2.0 GLIBC_2.2
mips.*-.*-linux.* libresolv=2 GLIBC_2.0 GLIBC_2.2
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/soft-fp/sfp-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/soft-fp/sfp-machine.h 2013-08-20 15:18:10.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/soft-fp/sfp-machine.h 2013-08-22 10:32:05.447640501 +0100
@@ -21,15 +21,25 @@
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
-#define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
-#define _FP_NANFRAC_D (_FP_QNANBIT_D - 1), -1
-#define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1, -1, -1
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
+# define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#else
+# define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D (_FP_QNANBIT_D - 1), -1
+# define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1, -1, -1
+#endif
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
-#define _FP_QNANNEGATEDP 1
+#ifdef __mips_nan2008
+# define _FP_QNANNEGATEDP 0
+#else
+# define _FP_QNANNEGATEDP 1
+#endif
/* From my experiments it seems X is chosen unless one of the
NaNs is sNaN, in which case the result is NANSIGN/NANFRAC. */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/configure
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/configure 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/configure 2013-08-22 10:39:07.378109215 +0100
@@ -137,4 +137,165 @@ case "$prefix" in
esac
esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler is using the 2008 NaN encoding" >&5
+$as_echo_n "checking whether the compiler is using the 2008 NaN encoding... " >&6; }
+if ${libc_cv_mips_nan2008+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+dnl
+#ifdef __mips_nan2008
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ libc_cv_mips_nan2008=yes
+else
+ libc_cv_mips_nan2008=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_nan2008" >&5
+$as_echo "$libc_cv_mips_nan2008" >&6; }
+
libc_cv_gcc_unwind_find_fde=yes
+
+if test -z "$arch_minimum_kernel"; then
+ if test x$libc_cv_mips_nan2008 = xyes; then
+ arch_minimum_kernel=3.11.0
+ fi
+fi
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/configure.in
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/configure.in 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/configure.in 2013-08-22 10:35:13.417814395 +0100
@@ -75,4 +75,16 @@ case "$prefix" in
esac
esac
+AC_CACHE_CHECK([whether the compiler is using the 2008 NaN encoding],
+ libc_cv_mips_nan2008, [AC_EGREP_CPP(yes, [dnl
+#ifdef __mips_nan2008
+yes
+#endif], libc_cv_mips_nan2008=yes, libc_cv_mips_nan2008=no)])
+
libc_cv_gcc_unwind_find_fde=yes
+
+if test -z "$arch_minimum_kernel"; then
+ if test x$libc_cv_mips_nan2008 = xyes; then
+ arch_minimum_kernel=3.11.0
+ fi
+fi
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h 2013-08-22 10:32:05.447640501 +0100
@@ -18,11 +18,27 @@
#include <ldconfig.h>
-/* Redefine the cache ID for new ABIs; o32 keeps using the generic check. */
-#if _MIPS_SIM == _ABI64
-# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6)
-#elif _MIPS_SIM == _ABIN32
-# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6)
+#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \
+ || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008))
+# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?"
+#endif
+
+/* Redefine the cache ID for new ABIs and 2008 NaN support; legacy o32
+ keeps using the generic check. */
+#ifdef __mips_nan2008
+# if _MIPS_SIM == _ABIO32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABI64
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64_NAN2008 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABIN32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32_NAN2008 | FLAG_ELF_LIBC6)
+# endif
+#else
+# if _MIPS_SIM == _ABI64
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABIN32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6)
+# endif
#endif
#ifdef _DL_CACHE_DEFAULT_ID
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/readelflib.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/readelflib.c 2013-05-16 18:17:13.000000000 +0100
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/readelflib.c 2013-08-22 10:32:05.447640501 +0100
@@ -33,19 +33,32 @@ process_elf_file (const char *file_name,
unsigned int *osversion, char **soname, void *file_contents,
size_t file_length)
{
- ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
+ union
+ {
+ Elf64_Ehdr *eh64;
+ Elf32_Ehdr *eh32;
+ ElfW(Ehdr) *eh;
+ }
+ elf_header;
int ret;
- if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
+ elf_header.eh = file_contents;
+ if (elf_header.eh->e_ident [EI_CLASS] == ELFCLASS32)
{
- Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
-
ret = process_elf32_file (file_name, lib, flag, osversion, soname,
file_contents, file_length);
+ if (!ret)
+ {
+ Elf32_Word flags = elf_header.eh32->e_flags;
+ int nan2008 = (flags & EF_MIPS_NAN2008) != 0;
- /* n32 libraries are always libc.so.6+. */
- if (!ret && (elf32_header->e_flags & EF_MIPS_ABI2) != 0)
- *flag = FLAG_MIPS64_LIBN32|FLAG_ELF_LIBC6;
+ /* n32 libraries are always libc.so.6+, o32 only if 2008 NaN. */
+ if ((flags & EF_MIPS_ABI2) != 0)
+ *flag = (nan2008 ? FLAG_MIPS64_LIBN32_NAN2008
+ : FLAG_MIPS64_LIBN32) | FLAG_ELF_LIBC6;
+ else if (nan2008)
+ *flag = FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6;
+ }
}
else
{
@@ -53,7 +66,13 @@ process_elf_file (const char *file_name,
file_contents, file_length);
/* n64 libraries are always libc.so.6+. */
if (!ret)
- *flag = FLAG_MIPS64_LIBN64|FLAG_ELF_LIBC6;
+ {
+ Elf64_Word flags = elf_header.eh64->e_flags;
+ int nan2008 = (flags & EF_MIPS_NAN2008) != 0;
+
+ *flag = (nan2008 ? FLAG_MIPS64_LIBN64_NAN2008
+ : FLAG_MIPS64_LIBN64) | FLAG_ELF_LIBC6;
+ }
}
return ret;
Index: glibc-fsf-trunk-quilt/sysdeps/generic/ldconfig.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/sysdeps/generic/ldconfig.h 2013-05-21 00:20:30.000000000 +0100
+++ glibc-fsf-trunk-quilt/sysdeps/generic/ldconfig.h 2013-08-22 10:32:05.447640501 +0100
@@ -21,24 +21,27 @@
#include <stdint.h>
-#define FLAG_ANY -1
-#define FLAG_TYPE_MASK 0x00ff
-#define FLAG_LIBC4 0x0000
-#define FLAG_ELF 0x0001
-#define FLAG_ELF_LIBC5 0x0002
-#define FLAG_ELF_LIBC6 0x0003
-#define FLAG_REQUIRED_MASK 0xff00
-#define FLAG_SPARC_LIB64 0x0100
-#define FLAG_IA64_LIB64 0x0200
-#define FLAG_X8664_LIB64 0x0300
-#define FLAG_S390_LIB64 0x0400
-#define FLAG_POWERPC_LIB64 0x0500
-#define FLAG_MIPS64_LIBN32 0x0600
-#define FLAG_MIPS64_LIBN64 0x0700
-#define FLAG_X8664_LIBX32 0x0800
-#define FLAG_ARM_LIBHF 0x0900
-#define FLAG_AARCH64_LIB64 0x0a00
-#define FLAG_ARM_LIBSF 0x0b00
+#define FLAG_ANY -1
+#define FLAG_TYPE_MASK 0x00ff
+#define FLAG_LIBC4 0x0000
+#define FLAG_ELF 0x0001
+#define FLAG_ELF_LIBC5 0x0002
+#define FLAG_ELF_LIBC6 0x0003
+#define FLAG_REQUIRED_MASK 0xff00
+#define FLAG_SPARC_LIB64 0x0100
+#define FLAG_IA64_LIB64 0x0200
+#define FLAG_X8664_LIB64 0x0300
+#define FLAG_S390_LIB64 0x0400
+#define FLAG_POWERPC_LIB64 0x0500
+#define FLAG_MIPS64_LIBN32 0x0600
+#define FLAG_MIPS64_LIBN64 0x0700
+#define FLAG_X8664_LIBX32 0x0800
+#define FLAG_ARM_LIBHF 0x0900
+#define FLAG_AARCH64_LIB64 0x0a00
+#define FLAG_ARM_LIBSF 0x0b00
+#define FLAG_MIPS_LIB32_NAN2008 0x0c00
+#define FLAG_MIPS64_LIBN32_NAN2008 0x0d00
+#define FLAG_MIPS64_LIBN64_NAN2008 0x0e00
/* Name of auxiliary cache. */
#define _PATH_LDCONFIG_AUX_CACHE "/var/cache/ldconfig/aux-cache"