summaryrefslogtreecommitdiff
path: root/ports/sysdeps/mips
diff options
context:
space:
mode:
Diffstat (limited to 'ports/sysdeps/mips')
-rw-r--r--ports/sysdeps/mips/bits/atomic.h2
-rw-r--r--ports/sysdeps/mips/bits/nan.h23
-rw-r--r--ports/sysdeps/mips/configure162
-rw-r--r--ports/sysdeps/mips/configure.ac15
-rw-r--r--ports/sysdeps/mips/configure.in6
-rw-r--r--ports/sysdeps/mips/dl-lookup.c5
-rw-r--r--ports/sysdeps/mips/dl-machine.h14
-rw-r--r--ports/sysdeps/mips/fpu/fegetround.c3
-rw-r--r--ports/sysdeps/mips/fpu/fesetround.c4
-rw-r--r--ports/sysdeps/mips/fpu_control.h33
-rw-r--r--ports/sysdeps/mips/math_private.h114
-rw-r--r--ports/sysdeps/mips/memset.S394
-rw-r--r--ports/sysdeps/mips/mips32/fpu/e_sqrt.c1
-rw-r--r--ports/sysdeps/mips/mips32/fpu/e_sqrtf.c1
-rw-r--r--ports/sysdeps/mips/mips64/memset.S90
-rw-r--r--ports/sysdeps/mips/mips64/n32/fpu/e_sqrt.c1
-rw-r--r--ports/sysdeps/mips/mips64/n32/fpu/e_sqrtf.c1
-rw-r--r--ports/sysdeps/mips/mips64/n64/fpu/e_sqrt.c1
-rw-r--r--ports/sysdeps/mips/mips64/n64/fpu/e_sqrtf.c1
-rw-r--r--ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h18
-rw-r--r--ports/sysdeps/mips/shlib-versions4
-rw-r--r--ports/sysdeps/mips/soft-fp/sfp-machine.h18
22 files changed, 727 insertions, 184 deletions
diff --git a/ports/sysdeps/mips/bits/atomic.h b/ports/sysdeps/mips/bits/atomic.h
index 7c735f7262..b31444f575 100644
--- a/ports/sysdeps/mips/bits/atomic.h
+++ b/ports/sysdeps/mips/bits/atomic.h
@@ -84,7 +84,7 @@ typedef uintmax_t uatomic_max_t;
support for their efficient implementation was added only in GCC 4.8.
We still want to use them even with GCC 4.7 for MIPS16 code where we
have no assembly alternative available and want to avoid the __sync_*
- if at all possible. */
+ builtins if at all possible. */
/* Compare and exchange.
For all "bool" routines, we return FALSE if exchange succesful. */
diff --git a/ports/sysdeps/mips/bits/nan.h b/ports/sysdeps/mips/bits/nan.h
index 80f7866a97..c322523275 100644
--- a/ports/sysdeps/mips/bits/nan.h
+++ b/ports/sysdeps/mips/bits/nan.h
@@ -22,10 +22,11 @@
/* IEEE Not A Number. */
-/* Note that MIPS has the qNaN and sNaN patterns reversed compared to most
- other architectures. IEEE 754-1985 left the definition of this open to
- implementations, and for MIPS the top bit of the mantissa must be SET to
- indicate a sNaN. */
+/* In legacy-NaN mode MIPS has the qNaN and sNaN patterns reversed
+ compared to most other architectures. IEEE 754-1985 left the
+ definition of this open to implementations, and for MIPS the top bit
+ of the mantissa must be SET to indicate a sNaN. In 2008-NaN mode
+ MIPS aligned to IEEE 754-2008. */
#if __GNUC_PREREQ(3,3)
@@ -33,6 +34,8 @@
#elif defined __GNUC__
+/* No 2008-NaN mode support in any GCC version before 4.9. */
+
# define NAN \
(__extension__ \
((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; }) \
@@ -43,10 +46,18 @@
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
-# define __qnan_bytes { 0x7f, 0xbf, 0xff, 0xff }
+# ifdef __mips_nan2008
+# define __qnan_bytes { 0x7f, 0xc0, 0, 0 }
+# else
+# define __qnan_bytes { 0x7f, 0xbf, 0xff, 0xff }
+# endif
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
-# define __qnan_bytes { 0xff, 0xff, 0xbf, 0x7f }
+# ifdef __mips_nan2008
+# define __qnan_bytes { 0, 0, 0xc0, 0x7f }
+# else
+# define __qnan_bytes { 0xff, 0xff, 0xbf, 0x7f }
+# endif
# endif
static union { unsigned char __c[4]; float __d; } __qnan_union
diff --git a/ports/sysdeps/mips/configure b/ports/sysdeps/mips/configure
index 898e4c3f20..f3f5d2e00d 100644
--- a/ports/sysdeps/mips/configure
+++ b/ports/sysdeps/mips/configure
@@ -1,3 +1,163 @@
-# This file is generated from configure.in by Autoconf. DO NOT EDIT!
+# This file is generated from configure.ac 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
diff --git a/ports/sysdeps/mips/configure.ac b/ports/sysdeps/mips/configure.ac
new file mode 100644
index 0000000000..bcbdaffd9f
--- /dev/null
+++ b/ports/sysdeps/mips/configure.ac
@@ -0,0 +1,15 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/mips.
+
+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
diff --git a/ports/sysdeps/mips/configure.in b/ports/sysdeps/mips/configure.in
deleted file mode 100644
index be9672d823..0000000000
--- a/ports/sysdeps/mips/configure.in
+++ /dev/null
@@ -1,6 +0,0 @@
-GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
-# Local configure fragment for sysdeps/mips.
-
-dnl No MIPS GCC supports accessing static and hidden symbols in an
-dnl position independent way.
-dnl AC_DEFINE(PI_STATIC_AND_HIDDEN)
diff --git a/ports/sysdeps/mips/dl-lookup.c b/ports/sysdeps/mips/dl-lookup.c
index 6d8f744246..2b7bf15cde 100644
--- a/ports/sysdeps/mips/dl-lookup.c
+++ b/ports/sysdeps/mips/dl-lookup.c
@@ -113,8 +113,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
/* Print some debugging info if wanted. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
_dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
- undef_name,
- DSO_FILENAME (map->l_name),
+ undef_name, DSO_FILENAME (map->l_name),
map->l_ns);
/* If the hash table is empty there is nothing to do here. */
@@ -764,7 +763,7 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
contain the needed symbol. This code is never reached
for unversioned lookups. */
assert (version != NULL);
- const char *reference_name = undef_map ? undef_map->l_name : NULL;
+ const char *reference_name = undef_map ? undef_map->l_name : "";
/* XXX We cannot translate the message. */
_dl_signal_cerror (0, DSO_FILENAME (reference_name),
diff --git a/ports/sysdeps/mips/dl-machine.h b/ports/sysdeps/mips/dl-machine.h
index dae938f039..722c8a0ba8 100644
--- a/ports/sysdeps/mips/dl-machine.h
+++ b/ports/sysdeps/mips/dl-machine.h
@@ -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(Ehdr) *ehdr)
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:
diff --git a/ports/sysdeps/mips/fpu/fegetround.c b/ports/sysdeps/mips/fpu/fegetround.c
index 61217a7c08..011d27f295 100644
--- a/ports/sysdeps/mips/fpu/fegetround.c
+++ b/ports/sysdeps/mips/fpu/fegetround.c
@@ -28,5 +28,6 @@ fegetround (void)
/* Get control word. */
_FPU_GETCW (cw);
- return cw & 0x3;
+ return cw & _FPU_RC_MASK;
}
+libm_hidden_def (fegetround)
diff --git a/ports/sysdeps/mips/fpu/fesetround.c b/ports/sysdeps/mips/fpu/fesetround.c
index 7c25f43b79..c6fdd6622f 100644
--- a/ports/sysdeps/mips/fpu/fesetround.c
+++ b/ports/sysdeps/mips/fpu/fesetround.c
@@ -25,7 +25,7 @@ fesetround (int round)
{
fpu_control_t cw;
- if ((round & ~0x3) != 0)
+ if ((round & ~_FPU_RC_MASK) != 0)
/* ROUND is no valid rounding mode. */
return 1;
@@ -33,7 +33,7 @@ fesetround (int round)
_FPU_GETCW (cw);
/* Set rounding bits. */
- cw &= ~0x3;
+ cw &= ~_FPU_RC_MASK;
cw |= round;
/* Set new state. */
_FPU_SETCW (cw);
diff --git a/ports/sysdeps/mips/fpu_control.h b/ports/sysdeps/mips/fpu_control.h
index 770cbb31d8..ee774153f2 100644
--- a/ports/sysdeps/mips/fpu_control.h
+++ b/ports/sysdeps/mips/fpu_control.h
@@ -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
@@ -69,32 +71,45 @@ extern fpu_control_t __fpu_control;
#else /* __mips_soft_float */
-/* masking of interrupts */
+/* Masks for interrupts. */
#define _FPU_MASK_V 0x0800 /* Invalid operation */
#define _FPU_MASK_Z 0x0400 /* Division by zero */
#define _FPU_MASK_O 0x0200 /* Overflow */
#define _FPU_MASK_U 0x0100 /* Underflow */
#define _FPU_MASK_I 0x0080 /* Inexact operation */
-/* flush denormalized numbers to zero */
+/* Flush denormalized numbers to zero. */
#define _FPU_FLUSH_TZ 0x1000000
-/* rounding control */
+/* 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
+/* Mask for rounding control. */
+#define _FPU_RC_MASK 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
-#define _FPU_DEFAULT 0x00000000
-
-/* IEEE: same as above, but exceptions */
-#define _FPU_IEEE 0x00000F80
+/* 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__)));
diff --git a/ports/sysdeps/mips/math_private.h b/ports/sysdeps/mips/math_private.h
index f0ba4ee706..4f029b0a6c 100644
--- a/ports/sysdeps/mips/math_private.h
+++ b/ports/sysdeps/mips/math_private.h
@@ -18,9 +18,121 @@
#ifndef _MATH_PRIVATE_H
+#ifdef __mips_nan2008
+/* MIPS aligned to IEEE 754-2008. */
+#else
/* One of the few architectures where the meaning of the quiet/signaling bit is
inverse to IEEE 754-2008 (as well as common practice for IEEE 754-1985). */
-#define HIGH_ORDER_BIT_IS_SET_FOR_SNAN
+# define HIGH_ORDER_BIT_IS_SET_FOR_SNAN
+#endif
+
+/* Inline functions to speed up the math library implementation. The
+ default versions of these routines are in generic/math_private.h
+ and call fesetround, feholdexcept, etc. These routines use inlined
+ code instead. */
+
+#ifdef __mips_hard_float
+
+# include <fenv.h>
+# include <fenv_libc.h>
+# include <fpu_control.h>
+
+static __always_inline void
+libc_feholdexcept_mips (fenv_t *envp)
+{
+ fpu_control_t cw;
+
+ /* Save the current state. */
+ _FPU_GETCW (cw);
+ envp->__fp_control_register = cw;
+
+ /* Clear all exception enable bits and flags. */
+ cw &= ~(_FPU_MASK_V|_FPU_MASK_Z|_FPU_MASK_O|_FPU_MASK_U|_FPU_MASK_I|FE_ALL_EXCEPT);
+ _FPU_SETCW (cw);
+}
+# define libc_feholdexcept libc_feholdexcept_mips
+# define libc_feholdexceptf libc_feholdexcept_mips
+# define libc_feholdexceptl libc_feholdexcept_mips
+
+static __always_inline void
+libc_fesetround_mips (int round)
+{
+ fpu_control_t cw;
+
+ /* Get current state. */
+ _FPU_GETCW (cw);
+
+ /* Set rounding bits. */
+ cw &= ~_FPU_RC_MASK;
+ cw |= round;
+
+ /* Set new state. */
+ _FPU_SETCW (cw);
+}
+# define libc_fesetround libc_fesetround_mips
+# define libc_fesetroundf libc_fesetround_mips
+# define libc_fesetroundl libc_fesetround_mips
+
+static __always_inline void
+libc_feholdexcept_setround_mips (fenv_t *envp, int round)
+{
+ fpu_control_t cw;
+
+ /* Save the current state. */
+ _FPU_GETCW (cw);
+ envp->__fp_control_register = cw;
+
+ /* Clear all exception enable bits and flags. */
+ cw &= ~(_FPU_MASK_V|_FPU_MASK_Z|_FPU_MASK_O|_FPU_MASK_U|_FPU_MASK_I|FE_ALL_EXCEPT);
+
+ /* Set rounding bits. */
+ cw &= ~_FPU_RC_MASK;
+ cw |= round;
+
+ /* Set new state. */
+ _FPU_SETCW (cw);
+}
+# define libc_feholdexcept_setround libc_feholdexcept_setround_mips
+# define libc_feholdexcept_setroundf libc_feholdexcept_setround_mips
+# define libc_feholdexcept_setroundl libc_feholdexcept_setround_mips
+
+static __always_inline void
+libc_fesetenv_mips (fenv_t *envp)
+{
+ fpu_control_t cw;
+
+ /* Read current state to flush fpu pipeline. */
+ _FPU_GETCW (cw);
+
+ _FPU_SETCW (envp->__fp_control_register);
+}
+# define libc_fesetenv libc_fesetenv_mips
+# define libc_fesetenvf libc_fesetenv_mips
+# define libc_fesetenvl libc_fesetenv_mips
+
+static __always_inline void
+libc_feupdateenv_mips (fenv_t *envp)
+{
+ int temp;
+
+ /* Save current exceptions. */
+ _FPU_GETCW (temp);
+
+ /* Set flag bits (which are accumulative), and *also* set the
+ cause bits. The setting of the cause bits is what actually causes
+ the hardware to generate the exception, if the corresponding enable
+ bit is set as well. */
+ temp &= FE_ALL_EXCEPT;
+ temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT);
+
+ /* Set new state. */
+ _FPU_SETCW (temp);
+}
+# define libc_feupdateenv libc_feupdateenv_mips
+# define libc_feupdateenvf libc_feupdateenv_mips
+# define libc_feupdateenvl libc_feupdateenv_mips
+
+#endif
#include_next <math_private.h>
diff --git a/ports/sysdeps/mips/memset.S b/ports/sysdeps/mips/memset.S
index 85062fe2e2..d30b1f0e64 100644
--- a/ports/sysdeps/mips/memset.S
+++ b/ports/sysdeps/mips/memset.S
@@ -1,6 +1,5 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -16,70 +15,353 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
-#include <sysdep.h>
+#ifdef ANDROID_CHANGES
+# include "machine/asm.h"
+# include "machine/regdef.h"
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _LIBC
+# include <sysdep.h>
+# include <regdef.h>
+# include <sys/asm.h>
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _COMPILING_NEWLIB
+# include "machine/asm.h"
+# include "machine/regdef.h"
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#else
+# include <regdef.h>
+# include <sys/asm.h>
+#endif
- .set nomips16
+/* Check to see if the MIPS architecture we are compiling for supports
+ prefetching. */
+
+#if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64)
+# ifndef DISABLE_PREFETCH
+# define USE_PREFETCH
+# endif
+#endif
+
+#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
+# ifndef DISABLE_DOUBLE
+# define USE_DOUBLE
+# endif
+#endif
+
+#ifndef USE_DOUBLE
+# ifndef DISABLE_DOUBLE_ALIGN
+# define DOUBLE_ALIGN
+# endif
+#endif
+
+/* Some asm.h files do not have the L macro definition. */
+#ifndef L
+# if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+# else
+# define L(label) .L ## label
+# endif
+#endif
+
+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
+#ifndef PTR_ADDIU
+# ifdef USE_DOUBLE
+# define PTR_ADDIU daddiu
+# else
+# define PTR_ADDIU addiu
+# endif
+#endif
-/* void *memset(void *s, int c, size_t n). */
+/* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
+ or PREFETCH_STORE_STREAMED offers a large performance advantage
+ but PREPAREFORSTORE has some special restrictions to consider.
-#if __MIPSEB
-# define SWHI swl /* high part is left in big-endian */
+ Prefetch with the 'prepare for store' hint does not copy a memory
+ location into the cache, it just allocates a cache line and zeros
+ it out. This means that if you do not write to the entire cache
+ line before writing it out to memory some data will get zero'ed out
+ when the cache line is written back to memory and data will be lost.
+
+ There are ifdef'ed sections of this memcpy to make sure that it does not
+ do prefetches on cache lines that are not going to be completely written.
+ This code is only needed and only used when PREFETCH_STORE_HINT is set to
+ PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are
+ less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will
+ not work correctly. */
+
+#ifdef USE_PREFETCH
+# define PREFETCH_HINT_STORE 1
+# define PREFETCH_HINT_STORE_STREAMED 5
+# define PREFETCH_HINT_STORE_RETAINED 7
+# define PREFETCH_HINT_PREPAREFORSTORE 30
+
+/* If we have not picked out what hints to use at this point use the
+ standard load and store prefetch hints. */
+# ifndef PREFETCH_STORE_HINT
+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
+# endif
+
+/* We double everything when USE_DOUBLE is true so we do 2 prefetches to
+ get 64 bytes in that case. The assumption is that each individual
+ prefetch brings in 32 bytes. */
+# ifdef USE_DOUBLE
+# define PREFETCH_CHUNK 64
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
+ pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
+# else
+# define PREFETCH_CHUNK 32
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*32(reg)
+# endif
+
+/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
+ than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size
+ of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
+ hint is used, the code will not work correctly. If PREPAREFORSTORE is not
+ used than MAX_PREFETCH_SIZE does not matter. */
+# define MAX_PREFETCH_SIZE 128
+/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
+ than 5 on a STORE prefetch and that a single prefetch can never be larger
+ than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because
+ we actually do two prefetches in that case, one 32 bytes after the other. */
+# ifdef USE_DOUBLE
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
+# else
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
+# endif
+
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
+ && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
+/* We cannot handle this because the initial prefetches may fetch bytes that
+ are before the buffer being copied. We start copies with an offset
+ of 4 so avoid this situation when using PREPAREFORSTORE. */
+# error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
+# endif
+#else /* USE_PREFETCH not defined */
+# define PREFETCH_FOR_STORE(offset, reg)
+#endif
+
+/* Allow the routine to be named something else if desired. */
+#ifndef MEMSET_NAME
+# define MEMSET_NAME memset
+#endif
+
+/* We load/store 64 bits at a time when USE_DOUBLE is true.
+ The C_ prefix stands for CHUNK and is used to avoid macro name
+ conflicts with system header files. */
+
+#ifdef USE_DOUBLE
+# define C_ST sd
+# if __MIPSEB
+# define C_STHI sdl /* high part is left in big-endian */
+# else
+# define C_STHI sdr /* high part is right in little-endian */
+# endif
#else
-# define SWHI swr /* high part is right in little-endian */
+# define C_ST sw
+# if __MIPSEB
+# define C_STHI swl /* high part is left in big-endian */
+# else
+# define C_STHI swr /* high part is right in little-endian */
+# endif
#endif
-ENTRY (memset)
+/* Bookkeeping values for 32 vs. 64 bit mode. */
+#ifdef USE_DOUBLE
+# define NSIZE 8
+# define NSIZEMASK 0x3f
+# define NSIZEDMASK 0x7f
+#else
+# define NSIZE 4
+# define NSIZEMASK 0x1f
+# define NSIZEDMASK 0x3f
+#endif
+#define UNIT(unit) ((unit)*NSIZE)
+#define UNITM1(unit) (((unit)*NSIZE)-1)
+
+#ifdef ANDROID_CHANGES
+LEAF(MEMSET_NAME,0)
+#else
+LEAF(MEMSET_NAME)
+#endif
+
+ .set nomips16
.set noreorder
+/* If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of
+ size, copy dst pointer to v0 for the return value. */
+ slti t2,a2,(2 * NSIZE)
+ bne t2,zero,L(lastb)
+ move v0,a0
+
+/* If memset value is not zero, we copy it to all the bytes in a 32 or 64
+ bit word. */
+ beq a1,zero,L(set0) /* If memset value is zero no smear */
+ PTR_SUBU a3,zero,a0
+ nop
+
+ /* smear byte into 32 or 64 bit word */
+#if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2)
+# ifdef USE_DOUBLE
+ dins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
+ dins a1, a1, 16, 16 /* Replicate fill byte into word. */
+ dins a1, a1, 32, 32 /* Replicate fill byte into dbl word. */
+# else
+ ins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
+ ins a1, a1, 16, 16 /* Replicate fill byte into word. */
+# endif
+#else
+# ifdef USE_DOUBLE
+ and a1,0xff
+ dsll t2,a1,8
+ or a1,t2
+ dsll t2,a1,16
+ or a1,t2
+ dsll t2,a1,32
+ or a1,t2
+# else
+ and a1,0xff
+ sll t2,a1,8
+ or a1,t2
+ sll t2,a1,16
+ or a1,t2
+# endif
+#endif
+
+/* If the destination address is not aligned do a partial store to get it
+ aligned. If it is already aligned just jump to L(aligned). */
+L(set0):
+ andi t2,a3,(NSIZE-1) /* word-unaligned address? */
+ beq t2,zero,L(aligned) /* t2 is the unalignment count */
+ PTR_SUBU a2,a2,t2
+ C_STHI a1,0(a0)
+ PTR_ADDU a0,a0,t2
+
+L(aligned):
+/* If USE_DOUBLE is not set we may still want to align the data on a 16
+ byte boundry instead of an 8 byte boundry to maximize the opportunity
+ of proAptiv chips to do memory bonding (combining two sequential 4
+ byte stores into one 8 byte store). We know there are at least 4 bytes
+ left to store or we would have jumped to L(lastb) earlier in the code. */
+#ifdef DOUBLE_ALIGN
+ andi t2,a3,4
+ beq t2,zero,L(double_aligned)
+ PTR_SUBU a2,a2,t2
+ sw a1,0(a0)
+ PTR_ADDU a0,a0,t2
+L(double_aligned):
+#endif
- slti t1, a2, 8 # Less than 8?
- bne t1, zero, L(last8)
- move v0, a0 # Setup exit value before too late
-
- beq a1, zero, L(ueven) # If zero pattern, no need to extend
- andi a1, 0xff # Avoid problems with bogus arguments
- sll t0, a1, 8
- or a1, t0
- sll t0, a1, 16
- or a1, t0 # a1 is now pattern in full word
-
-L(ueven):
- subu t0, zero, a0 # Unaligned address?
- andi t0, 0x3
- beq t0, zero, L(chkw)
- subu a2, t0
- SWHI a1, 0(a0) # Yes, handle first unaligned part
- addu a0, t0 # Now both a0 and a2 are updated
+/* Now the destination is aligned to (word or double word) aligned address
+ Set a2 to count how many bytes we have to copy after all the 64/128 byte
+ chunks are copied and a3 to the dest pointer after all the 64/128 byte
+ chunks have been copied. We will loop, incrementing a0 until it equals
+ a3. */
+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
+ beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */
+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
+/* When in the loop we may prefetch with the 'prepare to store' hint,
+ in this case the a0+x should not be past the "t0-32" address. This
+ means: for x=128 the last "safe" a0 address is "t0-160". Alternatively,
+ for x=64 the last "safe" a0 address is "t0-96" In the current version we
+ will use "prefetch hint,128(a0)", so "t0-160" is the limit. */
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
+#endif
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
+ PREFETCH_FOR_STORE (1, a0)
+ PREFETCH_FOR_STORE (2, a0)
+ PREFETCH_FOR_STORE (3, a0)
+#endif
+
+L(loop16w):
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */
+ bgtz v1,L(skip_pref)
+ nop
+#endif
+ PREFETCH_FOR_STORE (4, a0)
+ PREFETCH_FOR_STORE (5, a0)
+L(skip_pref):
+ C_ST a1,UNIT(0)(a0)
+ C_ST a1,UNIT(1)(a0)
+ C_ST a1,UNIT(2)(a0)
+ C_ST a1,UNIT(3)(a0)
+ C_ST a1,UNIT(4)(a0)
+ C_ST a1,UNIT(5)(a0)
+ C_ST a1,UNIT(6)(a0)
+ C_ST a1,UNIT(7)(a0)
+ C_ST a1,UNIT(8)(a0)
+ C_ST a1,UNIT(9)(a0)
+ C_ST a1,UNIT(10)(a0)
+ C_ST a1,UNIT(11)(a0)
+ C_ST a1,UNIT(12)(a0)
+ C_ST a1,UNIT(13)(a0)
+ C_ST a1,UNIT(14)(a0)
+ C_ST a1,UNIT(15)(a0)
+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
+ bne a0,a3,L(loop16w)
+ nop
+ move a2,t8
+
+/* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go.
+ Check for a 32(64) byte chunk and copy if if there is one. Otherwise
+ jump down to L(chk1w) to handle the tail end of the copy. */
L(chkw):
- andi t0, a2, 0x7 # Enough left for one loop iteration?
- beq t0, a2, L(chkl)
- subu a3, a2, t0
- addu a3, a0 # a3 is last loop address +1
- move a2, t0 # a2 is now # of bytes left after loop
-L(loopw):
- addiu a0, 8 # Handle 2 words pr. iteration
- sw a1, -8(a0)
- bne a0, a3, L(loopw)
- sw a1, -4(a0)
-
-L(chkl):
- andi t0, a2, 0x4 # Check if there is at least a full
- beq t0, zero, L(last8) # word remaining after the loop
- subu a2, t0
- sw a1, 0(a0) # Yes...
- addiu a0, 4
-
-L(last8):
- blez a2, L(exit) # Handle last 8 bytes (if cnt>0)
- addu a3, a2, a0 # a3 is last address +1
-L(lst8l):
- addiu a0, 1
- bne a0, a3, L(lst8l)
- sb a1, -1(a0)
-L(exit):
- j ra # Bye, bye
+ andi t8,a2,NSIZEMASK /* is there a 32-byte/64-byte chunk. */
+ /* the t8 is the reminder count past 32-bytes */
+ beq a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */
+ nop
+ C_ST a1,UNIT(0)(a0)
+ C_ST a1,UNIT(1)(a0)
+ C_ST a1,UNIT(2)(a0)
+ C_ST a1,UNIT(3)(a0)
+ C_ST a1,UNIT(4)(a0)
+ C_ST a1,UNIT(5)(a0)
+ C_ST a1,UNIT(6)(a0)
+ C_ST a1,UNIT(7)(a0)
+ PTR_ADDIU a0,a0,UNIT(8)
+
+/* Here we have less than 32(64) bytes to set. Set up for a loop to
+ copy one word (or double word) at a time. Set a2 to count how many
+ bytes we have to copy after all the word (or double word) chunks are
+ copied and a3 to the dest pointer after all the (d)word chunks have
+ been copied. We will loop, incrementing a0 until a0 equals a3. */
+L(chk1w):
+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
+ beq a2,t8,L(lastb)
+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
+
+/* copying in words (4-byte or 8 byte chunks) */
+L(wordCopy_loop):
+ PTR_ADDIU a0,a0,UNIT(1)
+ bne a0,a3,L(wordCopy_loop)
+ C_ST a1,UNIT(-1)(a0)
+
+/* Copy the last 8 (or 16) bytes */
+L(lastb):
+ blez a2,L(leave)
+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
+L(lastbloop):
+ PTR_ADDIU a0,a0,1
+ bne a0,a3,L(lastbloop)
+ sb a1,-1(a0)
+L(leave):
+ j ra
nop
+ .set at
.set reorder
-END (memset)
-libc_hidden_builtin_def (memset)
+END(MEMSET_NAME)
+#ifndef ANDROID_CHANGES
+# ifdef _LIBC
+libc_hidden_builtin_def (MEMSET_NAME)
+# endif
+#endif
diff --git a/ports/sysdeps/mips/mips32/fpu/e_sqrt.c b/ports/sysdeps/mips/mips32/fpu/e_sqrt.c
new file mode 100644
index 0000000000..81f4e77697
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/fpu/e_sqrt.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrt.c>
diff --git a/ports/sysdeps/mips/mips32/fpu/e_sqrtf.c b/ports/sysdeps/mips/mips32/fpu/e_sqrtf.c
new file mode 100644
index 0000000000..fb0700d45c
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/fpu/e_sqrtf.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrtf.c>
diff --git a/ports/sysdeps/mips/mips64/memset.S b/ports/sysdeps/mips/mips64/memset.S
deleted file mode 100644
index 6453335266..0000000000
--- a/ports/sysdeps/mips/mips64/memset.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
- Ported to mips3 n32/n64 by Alexandre Oliva <aoliva@redhat.com>
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library. If not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <sysdep.h>
-#include <sys/asm.h>
-
-
-/* void *memset(void *s, int c, size_t n);
-
- This could probably be optimized further. */
-
-#if __MIPSEB
-# define SDHI sdl /* high part is left in big-endian */
-#else
-# define SDHI sdr /* high part is right in little-endian */
-#endif
-
-ENTRY (memset)
- .set noreorder
-
- slti ta1, a2, 16 # Less than 16?
- bne ta1, zero, L(last16)
- move v0, a0 # Setup exit value before too late
-
- beq a1, zero, L(ueven) # If zero pattern, no need to extend
- andi a1, 0xff # Avoid problems with bogus arguments
- dsll ta0, a1, 8
- or a1, ta0
- dsll ta0, a1, 16
- or a1, ta0 # a1 is now pattern in full word
- dsll ta0, a1, 32
- or a1, ta0 # a1 is now pattern in double word
-
-L(ueven):
- PTR_SUBU ta0, zero, a0 # Unaligned address?
- andi ta0, 0x7
- beq ta0, zero, L(chkw)
- PTR_SUBU a2, ta0
- SDHI a1, 0(a0) # Yes, handle first unaligned part
- PTR_ADDU a0, ta0 # Now both a0 and a2 are updated
-
-L(chkw):
- andi ta0, a2, 0xf # Enough left for one loop iteration?
- beq ta0, a2, L(chkl)
- PTR_SUBU a3, a2, ta0
- PTR_ADDU a3, a0 # a3 is last loop address +1
- move a2, ta0 # a2 is now # of bytes left after loop
-L(loopw):
- PTR_ADDIU a0, 16 # Handle 2 dwords pr. iteration
- sd a1, -16(a0)
- bne a0, a3, L(loopw)
- sd a1, -8(a0)
-
-L(chkl):
- andi ta0, a2, 0x8 # Check if there is at least a double
- beq ta0, zero, L(last16) # word remaining after the loop
- PTR_SUBU a2, ta0
- sd a1, 0(a0) # Yes...
- PTR_ADDIU a0, 8
-
-L(last16):
- blez a2, L(exit) # Handle last 16 bytes (if cnt>0)
- PTR_ADDU a3, a2, a0 # a3 is last address +1
-L(lst16l):
- PTR_ADDIU a0, 1
- bne a0, a3, L(lst16l)
- sb a1, -1(a0)
-L(exit):
- j ra # Bye, bye
- nop
-
- .set reorder
-END (memset)
-libc_hidden_builtin_def (memset)
diff --git a/ports/sysdeps/mips/mips64/n32/fpu/e_sqrt.c b/ports/sysdeps/mips/mips64/n32/fpu/e_sqrt.c
new file mode 100644
index 0000000000..81f4e77697
--- /dev/null
+++ b/ports/sysdeps/mips/mips64/n32/fpu/e_sqrt.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrt.c>
diff --git a/ports/sysdeps/mips/mips64/n32/fpu/e_sqrtf.c b/ports/sysdeps/mips/mips64/n32/fpu/e_sqrtf.c
new file mode 100644
index 0000000000..fb0700d45c
--- /dev/null
+++ b/ports/sysdeps/mips/mips64/n32/fpu/e_sqrtf.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrtf.c>
diff --git a/ports/sysdeps/mips/mips64/n64/fpu/e_sqrt.c b/ports/sysdeps/mips/mips64/n64/fpu/e_sqrt.c
new file mode 100644
index 0000000000..81f4e77697
--- /dev/null
+++ b/ports/sysdeps/mips/mips64/n64/fpu/e_sqrt.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrt.c>
diff --git a/ports/sysdeps/mips/mips64/n64/fpu/e_sqrtf.c b/ports/sysdeps/mips/mips64/n64/fpu/e_sqrtf.c
new file mode 100644
index 0000000000..fb0700d45c
--- /dev/null
+++ b/ports/sysdeps/mips/mips64/n64/fpu/e_sqrtf.c
@@ -0,0 +1 @@
+#include <sysdeps/mips/fpu/e_sqrtf.c>
diff --git a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
index 9cfd6fbb7b..5be50927d0 100644
--- a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
@@ -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. */
diff --git a/ports/sysdeps/mips/shlib-versions b/ports/sysdeps/mips/shlib-versions
index 780939369b..b153732c27 100644
--- a/ports/sysdeps/mips/shlib-versions
+++ b/ports/sysdeps/mips/shlib-versions
@@ -3,7 +3,11 @@ mips.*-.*-linux.* libm=6 GLIBC_2.0 GLIBC_2.2
# 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
diff --git a/ports/sysdeps/mips/soft-fp/sfp-machine.h b/ports/sysdeps/mips/soft-fp/sfp-machine.h
index a60bef7665..fff3b3c613 100644
--- a/ports/sysdeps/mips/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/soft-fp/sfp-machine.h
@@ -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. */