Patchwork MIPS: IEEE 754-2008 features support

login
register
mail settings
Submitter Maciej W. Rozycki
Date July 15, 2013, 11:30 p.m.
Message ID <alpine.DEB.1.10.1307151634220.20590@tp.orcam.me.uk>
Download mbox | patch
Permalink /patch/259305/
State New
Headers show

Comments

Maciej W. Rozycki - July 15, 2013, 11:30 p.m.
Hi,

 Complementing the binutils change recently committed here's one adding 
IEEE 754-2008 NaN features support to GCC.  Two features are supported:

1. IEEE 754-2008 NaN encoding.

 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.

 As from Sep 2012 the MIPS Architecture provides for processors that 
support the IEEE 754-2008 preferred NaN encoding format.

 Options have been provided to select between the two formats (further 
referred to as "legacy NaN" and "2008 NaN"), both at the run time and as 
an initial default.  The options are only available when IEEE 754-2008 NaN 
encoding is also supported by the binutils version used.  The requirement 
comes from the necessity to annotate binaries with the NaN encoding 
convention selected so as to prevent from linking incompatible binary 
objects together.

 The run-time selection options are -mnan=2008 and -mnan=legacy for the 
2008 NaN and the legacy NaN mode respectively.  The binary patterns of NaN 
data produced by compiler builtins or otherwise is adjusted accordingly, 
as is a `.nan' directive included now with the assembly source produced, 
used by GAS to set the NAN2008 ELF file header flag appropriately.  These 
options are also passed down to GAS by the GCC driver so that user 
assembly sources have the said NAN2008 flag set correctly in the absence 
of a `.nan' directive.  Finally the name of the dynamic linker is changed 
accordingly if the driver is used to invoke the linker.

 The default encoding mode is selected with the --with-nan=2008 and 
--with-nan=legacy `configure' script options.  The latter differs subtly 
from the lack of either option in that in the absence of --with-nan= no 
-mnan=legacy option is passed down to the assembler by the GCC driver, as 
suitable for older versions of binutils that do not support the IEEE 
754-2008 NaN encoding feature.

 Test cases have been included to make sure correct bit patterns are 
generated.

2. IEEE 754-2008 non-arithmetic ABS and NEG instructions.

 As many of you have been aware MIPS ABS.fmt and NEG.fmt instructions have 
not supported correct standard-compliant operation on a NaN argument as 
the architecture has considered them arithmetic and required to signal an 
Invalid Operation exception (that may or may not be trapped; in the latter 
case a quiet NaN is produced).  As a result in cases where standard 
compliance is required GCC has to emit longer sequences to move the value 
given from the FPU to the CPU, use an integer logical operation to adjust 
the sign bit manually, and then move the result back to FPU.

 As from Sep 2012 the MIPS Architecture provides for processors that 
support the IEEE 754-2008 requirement that operations on bit strings, that 
among others include ABS and NEG, are non-arithmetic and never signal an 
exception.

 Options have been provided to select between the two modes; these are 
-mabs=2008 and -mabs=legacy for the 2008 ABS and the legacy ABS mode 
respectively.

 Test cases have been included to make sure the ABS.fmt and NEG.fmt 
instructions are or are not generated, as appropriate for the hardware 
compliance mode selected.

 I have regression-tested this change successfully with the mips-linux-gnu 
target, o32 ABI.  Comments or questions?  OK to apply?

2013-07-15  Maciej W. Rozycki  <macro@codesourcery.com>

	gcc/
	* config/mips/linux.h (GLIBC_DYNAMIC_LINKER): Handle `-mnan=2008'.
	(UCLIBC_DYNAMIC_LINKER): New macro.
	* config/mips/linux64.h (GLIBC_DYNAMIC_LINKER32): Handle 
	`-mnan=2008'.
	(GLIBC_DYNAMIC_LINKER64, GLIBC_DYNAMIC_LINKERN32): Likewise.
	(UCLIBC_DYNAMIC_LINKER32): Undefine macro first.  Handle 
	`-mnan=2008'.
	(UCLIBC_DYNAMIC_LINKER64): Redefine macro.
	(UCLIBC_DYNAMIC_LINKERN32): Likewise.
	* config/mips/mips-modes.def: Remove RESET_FLOAT_FORMAT calls
	for SF and DF modes.  Use ieee_quad_format for TF mode.
	* config/mips/mips-opts.h (mips_abs_setting): New enum.
	(mips_nan_setting): Likewise.
	* config/mips/mips.c (mips_file_start) [HAVE_AS_NAN]: Output a 
	`.nan' directive.
	(mips_option_override): Handle `-mnan=legacy'.
	* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Handle 
	`-mabs=2008' and `-mnan=2008'.
	(OPTION_DEFAULT_SPECS): Add "nan" default.
	(ASM_SPEC): Handle `-mnan='.
	* config/mips/mips.md (abs<mode>2): Handle `-mabs=2008', update
	comment accordingly.
	(neg<mode>2): Likewise.
	* config/mips/mips.opt (mabs, mnan): New options.
	* doc/install.texi (Configuration): Document `--with-nan=' option.
	* doc/invoke.texi (Option Summary): List MIPS `-mabs=' and 
	`-mnan=' options.
	(MIPS Options): Document them.
	* config.gcc <mips*-*-*>: Handle `--with-nan='.
	* configure.ac <mips*-*-*>: Check for GAS `-mnan=2008' support.
	* configure: Regenerate.
	* config.in: Regenerate.

	gcc/testsuite/
	* gcc.target/mips/fabs-2008.c: New test case.
	* gcc.target/mips/fabs-legacy.c: New test case.
	* gcc.target/mips/fabsf-2008.c: New test case.
	* gcc.target/mips/fabsf-legacy.c: New test case.
	* gcc.target/mips/fneg-2008.c: New test case.
	* gcc.target/mips/fneg-legacy.c: New test case.
	* gcc.target/mips/fneg-2008.c: New test case.
	* gcc.target/mips/fneg-legacy.c: New test case.
	* gcc.target/mips/nan-2008.c: New test case.
	* gcc.target/mips/nan-legacy.c: New test case.
	* gcc.target/mips/nanf-2008.c: New test case.
	* gcc.target/mips/nanf-legacy.c: New test case.
	* gcc.target/mips/nans-2008.c: New test case.
	* gcc.target/mips/nans-legacy.c: New test case.
	* gcc.target/mips/nansf-2008.c: New test case.
	* gcc.target/mips/nansf-legacy.c: New test case.
	* gcc.target/mips/mips.exp: Handle `-mabs=' and `-mnan='.
	* lib/target-supports.exp (check_effective_target_mips_nan): New 
	procedure.

  Maciej

gcc-mips-nan2008.diff
Richard Sandiford - July 16, 2013, 7:47 p.m.
"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>  The run-time selection options are -mnan=2008 and -mnan=legacy for the 
> 2008 NaN and the legacy NaN mode respectively.  The binary patterns of NaN 
> data produced by compiler builtins or otherwise is adjusted accordingly, 
> as is a `.nan' directive included now with the assembly source produced, 
> used by GAS to set the NAN2008 ELF file header flag appropriately.  These 
> options are also passed down to GAS by the GCC driver so that user 
> assembly sources have the said NAN2008 flag set correctly in the absence 
> of a `.nan' directive.  Finally the name of the dynamic linker is changed 
> accordingly if the driver is used to invoke the linker.

I was a bit surprised that a change to the NaN format requires a change
to the dynamic linker, but I suppose that's the consequence of forcing
every ELF object to fall on one side of the fence?

I assume eventually there'll be an -mmac={legacy|2008} option too,
although of course it's good that that's a separate patch.  But then
the question is: is there a plan for handling all 8 possible combinations
of -mnan, -mabs and -mmac?  How would the FCSR be set up?

Even if we do plan to have all three be separately configurable,
I imagine most people will want them all set the same way, so it would
probably make sense to have something like -mfp-model={legacy|2008}
for that case.  And then my inclination would be to start with that
option and only add the split-out versions if we have a specific
(rather than theoretical) use case for them.

The patch mostly looks good apart from that, but please use a single
enum for the 2008/legacy thing, both in mips.h and mips.opt.

> +;; On pre IEEE 754-2008 processors abs.fmt is an arithmetic instruction
> +;; and treats all NaN inputs as invalid; it does not clear their sign bit.
> +;; We therefore can't use abs.fmt unless in the IEEE 754-2008 mode or if
> +;; the signs of NaNs matter.

"don't matter".  Or maybe to avoid the double negative:

;; The "legacy" (as opposed to "2008") form of ABS.FMT is an arithmetic
;; instruction that treats all NaN inputs as invalid; it does not flip
;; their sign bit.  We therefore can't use that form if the signs of
;; NaNs matter.

> +These options control the treatment of the special not-a-number (NaN)
> +IEEE 754 floating-point data with the @code{abs.@i{fmt}} and
> +@code{neg.@i{fmt}} machine instructions.
> +
> +By default or when the @option{-mabs=legacy} is used the legacy
> +treatment is selected.  In this case these instructions are considered
> +arithmetic and avoided where correct operation is required and the
> +input operand might be a NaN.  A longer sequence of instructions that
> +manipulate the sign bit of floating-point datum manually is used
> +instead unless the @option{-ffinite-math-only} option has also been
> +specified.
> +
> +The @option{-mabs=2008} option selects the IEEE 754-2008 treatment.  In

I think it reads better without the "-2008" bit, since even the 1985
version suggested this behaviour in the appendix.

> +The @option{-mnan=legacy} option selects the legacy encoding.  In this
> +case quiet NaNs (qNaNs) are denoted by the first bit of their trailing
> +significand field being 0, whereas signalling NaNs (sNaNs) are denoted
> +by the first bit of their trailing significand field being 1.
> +
> +The @option{-mnan=2008} option selects the IEEE 754-2008 encoding.  In
> +this case qNaNs are denoted by the first bit of their trailing
> +significand field being 1, whereas sNaNs are denoted by the first bit of
> +their trailing significand field being 0.

Very minor, but I'd prefer this without the "trailing"s.

> +These options are only supported on targets using the ELF binary format.

Let's drop that bit.  We don't support non-ELF on MIPS.

> +/* { dg-do compile } */
> +/* { dg-options "-mhard-float -mabs=2008" } */

Please instead make "-mabs=" imply "-mhard-float" in mips.exp.
(It is an "imply"; you can still test for -msoft-float -mabs=...
if you want.)

> +# Return 1 if this is a MIPS target supporting -mnan=.
> +# Old versions of binutils may not support this option.
> +
> +proc check_effective_target_mips_nan { } {
> +    if { ![istarget mips*-*-*] } {
> +	return 0
> +    }
> +    return [check_no_compiler_messages mips_nan object {
> +	int dummy;
> +    } "-mnan=2008"]
> +}

The tests you added are dg-do compile tests, which stop after assembly
generation, so this guard shouldn't be needed.  FWIW, if you did have
dg-do assemble or dg-do run tests, the mips.exp approach would be to
downgrade them to dg-do compile rather than skip them altogether.
We can add that later if we need it though...

Thanks,
Richard

Patch

Index: gcc-fsf-trunk-quilt/gcc/config.gcc
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config.gcc	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config.gcc	2013-07-14 11:42:31.249972860 +0100
@@ -3483,7 +3483,7 @@  case "${target}" in
 		;;
 
 	mips*-*-*)
-		supported_defaults="abi arch arch_32 arch_64 float tune tune_32 tune_64 divide llsc mips-plt synci"
+		supported_defaults="abi arch arch_32 arch_64 float nan tune tune_32 tune_64 divide llsc mips-plt synci"
 
 		case ${with_float} in
 		"" | soft | hard)
@@ -3495,6 +3495,16 @@  case "${target}" in
 			;;
 		esac
 
+		case ${with_nan} in
+		"" | 2008 | legacy)
+			# OK
+			;;
+		*)
+			echo "Unknown NaN encoding used in --with-nan=$with_nan" 1>&2
+			exit 1
+			;;
+		esac
+
 		case ${with_abi} in
 		"" | 32 | o64 | n32 | 64 | eabi)
 			# OK
@@ -3852,7 +3862,7 @@  case ${target} in
 esac
 
 t=
-all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu divide llsc mips-plt synci tls"
+all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float nan mode fpu divide llsc mips-plt synci tls"
 for option in $all_defaults
 do
 	eval "val=\$with_"`echo $option | sed s/-/_/g`
Index: gcc-fsf-trunk-quilt/gcc/config.in
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config.in	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config.in	2013-07-14 11:42:31.249972860 +0100
@@ -417,6 +417,12 @@ 
 #endif
 
 
+/* Define if the assembler understands -mnan=. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_NAN
+#endif
+
+
 /* Define if your assembler supports the -no-mul-bug-abort option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_NO_MUL_BUG_ABORT_OPTION
Index: gcc-fsf-trunk-quilt/gcc/config/mips/linux.h
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/linux.h	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/linux.h	2013-07-14 11:42:31.249972860 +0100
@@ -17,4 +17,9 @@  You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-#define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+#define GLIBC_DYNAMIC_LINKER \
+  "%{mnan=2008:/lib/ld-linux-mipsn8.so.1;:/lib/ld.so.1}"
+
+#undef UCLIBC_DYNAMIC_LINKER
+#define UCLIBC_DYNAMIC_LINKER \
+  "%{mnan=2008:/lib/ld-uClibc-mipsn8.so.0;:/lib/ld-uClibc.so.0}"
Index: gcc-fsf-trunk-quilt/gcc/config/mips/linux64.h
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/linux64.h	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/linux64.h	2013-07-14 11:42:31.249972860 +0100
@@ -22,10 +22,22 @@  along with GCC; see the file COPYING3.  
 #define GNU_USER_LINK_EMULATION64 "elf64%{EB:b}%{EL:l}tsmip"
 #define GNU_USER_LINK_EMULATIONN32 "elf32%{EB:b}%{EL:l}tsmipn32"
 
-#define GLIBC_DYNAMIC_LINKER32 "/lib/ld.so.1"
-#define GLIBC_DYNAMIC_LINKER64 "/lib64/ld.so.1"
-#define GLIBC_DYNAMIC_LINKERN32 "/lib32/ld.so.1"
-#define UCLIBC_DYNAMIC_LINKERN32 "/lib32/ld-uClibc.so.0"
+#define GLIBC_DYNAMIC_LINKER32 \
+  "%{mnan=2008:/lib/ld-linux-mipsn8.so.1;:/lib/ld.so.1}"
+#define GLIBC_DYNAMIC_LINKER64 \
+  "%{mnan=2008:/lib64/ld-linux-mipsn8.so.1;:/lib64/ld.so.1}"
+#define GLIBC_DYNAMIC_LINKERN32 \
+  "%{mnan=2008:/lib32/ld-linux-mipsn8.so.1;:/lib32/ld.so.1}"
+
+#undef UCLIBC_DYNAMIC_LINKER32
+#define UCLIBC_DYNAMIC_LINKER32 \
+  "%{mnan=2008:/lib/ld-uClibc-mipsn8.so.0;:/lib/ld-uClibc.so.0}"
+#undef UCLIBC_DYNAMIC_LINKER64
+#define UCLIBC_DYNAMIC_LINKER64 \
+  "%{mnan=2008:/lib/ld64-uClibc-mipsn8.so.0;:/lib/ld64-uClibc.so.0}"
+#define UCLIBC_DYNAMIC_LINKERN32 \
+  "%{mnan=2008:/lib32/ld-uClibc-mipsn8.so.0;:/lib32/ld-uClibc.so.0}"
+
 #define BIONIC_DYNAMIC_LINKERN32 "/system/bin/linker32"
 #define GNU_USER_DYNAMIC_LINKERN32 \
   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKERN32, UCLIBC_DYNAMIC_LINKERN32, \
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips-modes.def
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips-modes.def	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips-modes.def	2013-07-14 11:42:31.249972860 +0100
@@ -17,12 +17,7 @@  You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-/* MIPS has a quirky almost-IEEE format for all its
-   floating point.  */
-RESET_FLOAT_FORMAT (SF, mips_single_format);
-RESET_FLOAT_FORMAT (DF, mips_double_format);
-
-FLOAT_MODE (TF, 16, mips_quad_format);
+FLOAT_MODE (TF, 16, ieee_quad_format);
 
 /* Vector modes.  */
 VECTOR_MODES (INT, 4);        /* V4QI  V2HI      */
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips-opts.h
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips-opts.h	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips-opts.h	2013-07-14 11:42:31.249972860 +0100
@@ -27,6 +27,18 @@  enum mips_code_readable_setting {
   CODE_READABLE_YES
 };
 
+/* Enumerates the setting of the -mabs option.  */
+enum mips_abs_setting {
+  MIPS_ABS_LEGACY,
+  MIPS_ABS_2008
+};
+
+/* Enumerates the setting of the -mnan option.  */
+enum mips_nan_setting {
+  MIPS_NAN_LEGACY,
+  MIPS_NAN_2008
+};
+
 /* Enumerates the setting of the -mr10k-cache-barrier option.  */
 enum mips_r10k_cache_barrier_setting {
   R10K_CACHE_BARRIER_NONE,
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips.c
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips.c	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips.c	2013-07-16 00:13:41.260863651 +0100
@@ -8846,6 +8846,12 @@  mips_file_start (void)
     fprintf (asm_out_file, "\t.section .gcc_compiled_long%d\n"
 	     "\t.previous\n", TARGET_LONG64 ? 64 : 32);
 
+#ifdef HAVE_AS_NAN
+  /* Record the NaN encoding.  */
+  fprintf (asm_out_file, "\t.nan\t%s\n",
+	   mips_nan == MIPS_NAN_2008 ? "2008" : "legacy");
+#endif
+
 #ifdef HAVE_AS_GNU_ATTRIBUTE
   {
     int attr;
@@ -16978,6 +16984,15 @@  mips_option_override (void)
 	}
     }
 
+  /* Pre-IEEE 754-2008 MIPS hardware has a quirky almost-IEEE format
+     for all its floating point.  */
+  if (mips_nan != MIPS_NAN_2008)
+    {
+      REAL_MODE_FORMAT (SFmode) = &mips_single_format;
+      REAL_MODE_FORMAT (DFmode) = &mips_double_format;
+      REAL_MODE_FORMAT (TFmode) = &mips_quad_format;
+    }
+
   /* Make sure that the user didn't turn off paired single support when
      MIPS-3D support is requested.  */
   if (TARGET_MIPS3D
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips.h
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips.h	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips.h	2013-07-16 00:13:41.260863651 +0100
@@ -507,6 +507,12 @@  struct mips_cpu_info {
       if (TARGET_PAIRED_SINGLE_FLOAT)					\
 	builtin_define ("__mips_paired_single_float");			\
 									\
+      if (mips_abs == MIPS_ABS_2008)					\
+	builtin_define ("__mips_abs2008");				\
+									\
+      if (mips_nan == MIPS_NAN_2008)					\
+	builtin_define ("__mips_nan2008");				\
+									\
       if (TARGET_BIG_ENDIAN)						\
 	{								\
 	  builtin_define_std ("MIPSEB");				\
@@ -743,6 +749,7 @@  struct mips_cpu_info {
    --with-abi is ignored if -mabi is specified.
    --with-float is ignored if -mhard-float or -msoft-float are
      specified.
+   --with-nan is ignored if -mnan is specified.
    --with-divide is ignored if -mdivide-traps or -mdivide-breaks are
      specified. */
 #define OPTION_DEFAULT_SPECS \
@@ -754,6 +761,7 @@  struct mips_cpu_info {
   {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
+  {"nan", "%{!mnan=*:-mnan=%(VALUE)}" }, \
   {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
   {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }, \
   {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }, \
@@ -1162,7 +1170,7 @@  struct mips_cpu_info {
 %(subtarget_asm_debugging_spec) \
 %{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
 %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \
-%{mfp32} %{mfp64} \
+%{mfp32} %{mfp64} %{mnan=*} \
 %{mshared} %{mno-shared} \
 %{msym32} %{mno-sym32} \
 %{mtune=*} \
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips.md
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips.md	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips.md	2013-07-16 00:13:41.260863651 +0100
@@ -2711,14 +2711,15 @@ 
 ;; Do not use the integer abs macro instruction, since that signals an
 ;; exception on -2147483648 (sigh).
 
-;; abs.fmt is an arithmetic instruction and treats all NaN inputs as
-;; invalid; it does not clear their sign bits.  We therefore can't use
-;; abs.fmt if the signs of NaNs matter.
+;; On pre IEEE 754-2008 processors abs.fmt is an arithmetic instruction
+;; and treats all NaN inputs as invalid; it does not clear their sign bit.
+;; We therefore can't use abs.fmt unless in the IEEE 754-2008 mode or if
+;; the signs of NaNs matter.
 
 (define_insn "abs<mode>2"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
-  "!HONOR_NANS (<MODE>mode)"
+  "mips_abs == MIPS_ABS_2008 || !HONOR_NANS (<MODE>mode)"
   "abs.<fmt>\t%0,%1"
   [(set_attr "type" "fabs")
    (set_attr "mode" "<UNITMODE>")])
@@ -2793,14 +2794,15 @@ 
   [(set_attr "alu_type"	"sub")
    (set_attr "mode"	"DI")])
 
-;; neg.fmt is an arithmetic instruction and treats all NaN inputs as
-;; invalid; it does not flip their sign bit.  We therefore can't use
-;; neg.fmt if the signs of NaNs matter.
+;; On pre IEEE 754-2008 processors neg.fmt is an arithmetic instruction
+;; and treats all NaN inputs as invalid; it does not flip their sign bit.
+;; We therefore can't use neg.fmt unless in the IEEE 754-2008 mode or if
+;; the signs of NaNs matter.
 
 (define_insn "neg<mode>2"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
-  "!HONOR_NANS (<MODE>mode)"
+  "mips_abs == MIPS_ABS_2008 || !HONOR_NANS (<MODE>mode)"
   "neg.<fmt>\t%0,%1"
   [(set_attr "type" "fneg")
    (set_attr "mode" "<UNITMODE>")])
Index: gcc-fsf-trunk-quilt/gcc/config/mips/mips.opt
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/config/mips/mips.opt	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/config/mips/mips.opt	2013-07-14 14:03:26.640605952 +0100
@@ -205,6 +205,34 @@  mfused-madd
 Target Report Mask(FUSED_MADD)
 Generate floating-point multiply-add instructions
 
+mabs=
+Target RejectNegative Joined Enum(mips_abs) Var(mips_abs) Init(MIPS_ABS_LEGACY)
+-mabs=MODE	Select the IEEE 754 ABS/NEG instruction compliance mode
+
+Enum
+Name(mips_abs) Type(int)
+Known compliance modes (for use with the -mabs= option):
+
+EnumValue
+Enum(mips_abs) String(2008) Value(MIPS_ABS_2008)
+
+EnumValue
+Enum(mips_abs) String(legacy) Value(MIPS_ABS_LEGACY)
+
+mnan=
+Target RejectNegative Joined Enum(mips_nan) Var(mips_nan) Init(MIPS_NAN_LEGACY) Condition(HAVE_AS_NAN)
+-mnan=ENCODING	Select the IEEE 754 NaN data encoding
+
+Enum
+Name(mips_nan) Type(int)
+Known encodings (for use with the -mnan= option):
+
+EnumValue
+Enum(mips_nan) String(2008) Value(MIPS_NAN_2008)
+
+EnumValue
+Enum(mips_nan) String(legacy) Value(MIPS_NAN_LEGACY)
+
 mgp32
 Target Report RejectNegative InverseMask(64BIT)
 Use 32-bit general registers
Index: gcc-fsf-trunk-quilt/gcc/configure
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/configure	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/configure	2013-07-14 11:42:31.249972860 +0100
@@ -26019,6 +26019,41 @@  $as_echo "$gcc_cv_ld_mips_personality_re
 $as_echo "#define HAVE_LD_PERSONALITY_RELAXATION 1" >>confdefs.h
 
     fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for -mnan= support" >&5
+$as_echo_n "checking assembler for -mnan= support... " >&6; }
+if test "${gcc_cv_as_mips_nan+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_mips_nan=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags -mnan=2008 -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_mips_nan=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mips_nan" >&5
+$as_echo "$gcc_cv_as_mips_nan" >&6; }
+if test $gcc_cv_as_mips_nan = yes; then
+
+$as_echo "#define HAVE_AS_NAN 1" >>confdefs.h
+
+fi
+    if test x$gcc_cv_as_mips_nan = xno \
+       && test x$with_nan != x; then
+      as_fn_error "Requesting --with-nan= requires assembler support for -mnan=" "$LINENO" 5
+    fi
     ;;
 esac
 
Index: gcc-fsf-trunk-quilt/gcc/configure.ac
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/configure.ac	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/configure.ac	2013-07-14 11:42:31.249972860 +0100
@@ -4168,6 +4168,17 @@  EOF
       [Define if your linker can relax absolute .eh_frame personality
 pointers into PC-relative form.])
     fi
+
+    gcc_GAS_CHECK_FEATURE([-mnan= support],
+      gcc_cv_as_mips_nan,,
+      [-mnan=2008],,,
+      [AC_DEFINE(HAVE_AS_NAN, 1,
+		 [Define if the assembler understands -mnan=.])])
+    if test x$gcc_cv_as_mips_nan = xno \
+       && test x$with_nan != x; then
+      AC_MSG_ERROR(
+	[Requesting --with-nan= requires assembler support for -mnan=])
+    fi
     ;;
 esac
 
Index: gcc-fsf-trunk-quilt/gcc/doc/install.texi
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/doc/install.texi	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/doc/install.texi	2013-07-16 00:14:53.270859664 +0100
@@ -1221,6 +1221,24 @@  ISA for floating-point arithmetics.  You
 enables @option{-msse2} or @samp{avx} which enables @option{-mavx} by default.
 This option is only supported on i386 and x86-64 targets.
 
+@item --with-nan=@var{encoding}
+On MIPS targets, set the default encoding convention to use for the
+special not-a-number (NaN) IEEE 754 floating-point data.  The
+possibilities for @var{encoding} are:
+@table @code
+@item legacy
+Use the legacy encoding, as with the @option{-mnan=legacy} command-line
+option.
+@item 2008
+Use the 754-2008 encoding, as with the @option{-mnan=2008} command-line
+option.
+@end table
+To use this configuration option you must have an assembler version
+installed that supports the @option{-mnan=} command-line option too.
+In the absence of this configuration option the default convention is
+the legacy encoding, as when neither of the @option{-mnan=2008} and
+@option{-mnan=legacy} command-line options has been used.
+
 @item --with-divide=@var{type}
 Specify how the compiler should generate code for checking for
 division by zero.  This option is only supported on the MIPS target.
Index: gcc-fsf-trunk-quilt/gcc/doc/invoke.texi
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/doc/invoke.texi	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/doc/invoke.texi	2013-07-14 11:42:31.249972860 +0100
@@ -750,7 +750,8 @@  Objective-C and Objective-C++ Dialects}.
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
 -mgp32  -mgp64  -mfp32  -mfp64  -mhard-float  -msoft-float @gol
--mno-float -msingle-float  -mdouble-float  @gol
+-mno-float  -msingle-float  -mdouble-float @gol
+-mabs=@var{mode}  -mnan=@var{encoding} @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
 -meva -mno-eva @gol
@@ -16313,6 +16314,50 @@  operations.
 Assume that the floating-point coprocessor supports double-precision
 operations.  This is the default.
 
+@item -mabs=2008
+@itemx -mabs=legacy
+@opindex mabs=2008
+@opindex mabs=legacy
+These options control the treatment of the special not-a-number (NaN)
+IEEE 754 floating-point data with the @code{abs.@i{fmt}} and
+@code{neg.@i{fmt}} machine instructions.
+
+By default or when the @option{-mabs=legacy} is used the legacy
+treatment is selected.  In this case these instructions are considered
+arithmetic and avoided where correct operation is required and the
+input operand might be a NaN.  A longer sequence of instructions that
+manipulate the sign bit of floating-point datum manually is used
+instead unless the @option{-ffinite-math-only} option has also been
+specified.
+
+The @option{-mabs=2008} option selects the IEEE 754-2008 treatment.  In
+this case these instructions are considered non-arithmetic and therefore
+operating correctly in all cases, including in particular where the
+input operand is a NaN.  These instructions are therefore always used
+for the respective operations.
+
+@item -mnan=2008
+@itemx -mnan=legacy
+@opindex mnan=2008
+@opindex mnan=legacy
+These options control the encoding of the special not-a-number (NaN)
+IEEE 754 floating-point data.
+
+The @option{-mnan=legacy} option selects the legacy encoding.  In this
+case quiet NaNs (qNaNs) are denoted by the first bit of their trailing
+significand field being 0, whereas signalling NaNs (sNaNs) are denoted
+by the first bit of their trailing significand field being 1.
+
+The @option{-mnan=2008} option selects the IEEE 754-2008 encoding.  In
+this case qNaNs are denoted by the first bit of their trailing
+significand field being 1, whereas sNaNs are denoted by the first bit of
+their trailing significand field being 0.
+
+The default is @option{-mnan=legacy} unless GCC has been configured with
+@option{--with-nan=2008}.
+
+These options are only supported on targets using the ELF binary format.
+
 @item -mllsc
 @itemx -mno-llsc
 @opindex mllsc
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabs-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabs-2008.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=2008" } */
+
+NOMIPS16 double
+fabs_2008 (double d)
+{
+  return __builtin_fabs (d);
+}
+
+/* { dg-final { scan-assembler "\tabs\.d\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabs-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabs-legacy.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=legacy" } */
+
+NOMIPS16 double
+fabs_legacy (double d)
+{
+  return __builtin_fabs (d);
+}
+
+/* { dg-final { scan-assembler-not "\tabs\.d\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabsf-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabsf-2008.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=2008" } */
+
+NOMIPS16 float
+fabsf_2008 (float f)
+{
+  return __builtin_fabsf (f);
+}
+
+/* { dg-final { scan-assembler "\tabs\.s\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabsf-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fabsf-legacy.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=legacy" } */
+
+NOMIPS16 float
+fabsf_legacy (float f)
+{
+  return __builtin_fabsf (f);
+}
+
+/* { dg-final { scan-assembler-not "\tabs\.s\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fneg-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fneg-2008.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=2008" } */
+
+NOMIPS16 double
+fneg_2008 (double d)
+{
+  return -d;
+}
+
+/* { dg-final { scan-assembler "\tneg\.d\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fneg-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fneg-legacy.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=legacy" } */
+
+NOMIPS16 double
+fneg_legacy (double d)
+{
+  return -d;
+}
+
+/* { dg-final { scan-assembler-not "\tneg\.d\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fnegf-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fnegf-2008.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=2008" } */
+
+NOMIPS16 float
+fnegf_2008 (float f)
+{
+  return -f;
+}
+
+/* { dg-final { scan-assembler "\tneg\.s\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fnegf-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/fnegf-legacy.c	2013-07-14 14:02:14.630969480 +0100
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -mabs=legacy" } */
+
+NOMIPS16 float
+fnegf_legacy (float f)
+{
+  return -f;
+}
+
+/* { dg-final { scan-assembler-not "\tneg\.s\t" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/testsuite/gcc.target/mips/mips.exp	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/mips.exp	2013-07-14 11:42:31.249972860 +0100
@@ -276,8 +276,10 @@  foreach option {
 
 # Add -mfoo= options to mips_option_groups.
 foreach option {
+    abs
     branch-cost
     code-readable
+    nan
     r10k-cache-barrier
     tune
 } {
@@ -705,6 +707,18 @@  proc mips-dg-init {} {
 	    "-msoft-float",
 	    #endif
 
+	    #ifdef __mips_abs2008
+	    "-mabs=2008",
+	    #else
+	    "-mabs=legacy",
+	    #endif
+
+	    #ifdef __mips_nan2008
+	    "-mnan=2008",
+	    #else
+	    "-mnan=legacy",
+	    #endif
+
 	    #if __mips_fpr == 64
 	    "-mfp64",
 	    #else
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nan-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nan-2008.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=2008 -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+double d = __builtin_nan ("");
+
+/* { dg-final { scan-assembler "\t\.nan\t2008\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2146959360\n\t.word\t0\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nan-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nan-legacy.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=legacy -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+double d = __builtin_nan ("");
+
+/* { dg-final { scan-assembler "\t\.nan\tlegacy\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2146959359\n\t.word\t-1\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nanf-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nanf-2008.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=2008 -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+float f = __builtin_nanf ("");
+
+/* { dg-final { scan-assembler "\t\.nan\t2008\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2143289344\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nanf-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nanf-legacy.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=legacy -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+float f = __builtin_nanf ("");
+
+/* { dg-final { scan-assembler "\t\.nan\tlegacy\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2143289343\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nans-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nans-2008.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=2008 -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+double ds = __builtin_nans ("");
+
+/* { dg-final { scan-assembler "\t\.nan\t2008\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2146697216\n\t.word\t0\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nans-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nans-legacy.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=legacy -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+double ds = __builtin_nans ("");
+
+/* { dg-final { scan-assembler "\t\.nan\tlegacy\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2147483647\n\t.word\t-1\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nansf-2008.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nansf-2008.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=2008 -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+float fs = __builtin_nansf ("");
+
+/* { dg-final { scan-assembler "\t\.nan\t2008\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2141192192\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nansf-legacy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-fsf-trunk-quilt/gcc/testsuite/gcc.target/mips/nansf-legacy.c	2013-07-14 11:42:31.249972860 +0100
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mnan=legacy -EB" } */
+/* { dg-require-effective-target mips_nan } */
+
+float fs = __builtin_nansf ("");
+
+/* { dg-final { scan-assembler "\t\.nan\tlegacy\n" } } */
+/* { dg-final { scan-assembler "\t\.word\t2147483647\n" } } */
Index: gcc-fsf-trunk-quilt/gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc-fsf-trunk-quilt.orig/gcc/testsuite/lib/target-supports.exp	2013-07-13 14:14:25.000000000 +0100
+++ gcc-fsf-trunk-quilt/gcc/testsuite/lib/target-supports.exp	2013-07-14 11:42:31.249972860 +0100
@@ -975,6 +975,18 @@  proc check_effective_target_mips_eabi { 
     }]
 }
 
+# Return 1 if this is a MIPS target supporting -mnan=.
+# Old versions of binutils may not support this option.
+
+proc check_effective_target_mips_nan { } {
+    if { ![istarget mips*-*-*] } {
+	return 0
+    }
+    return [check_no_compiler_messages mips_nan object {
+	int dummy;
+    } "-mnan=2008"]
+}
+
 # Return 1 if the current multilib does not generate PIC by default.
 
 proc check_effective_target_nonpic { } {