diff mbox

[PATCHv3,MIPS] Implement O32 ABI extensions (GCC)

Message ID 6D39441BF12EF246A7ABCE6654B0235320F6B4ED@LEMAIL01.le.imgtec.org
State New
Headers show

Commit Message

Matthew Fortune Nov. 5, 2014, 5:19 p.m. UTC
Hi Catherine,

The full patch is attached and the delta from v2 is inline below.

Testing (O32):

MIPS I - FP32, MIPS II - FP32, MIPS II - FPXX
MIPS32 - FP32, MIPS32 - FPXX, MIPS32 - FPXX ODDSPREG,
MIPS32R2 - FP32, MIPS32R2 - FPXX, MIPS32R2 - FPXX ODDSPREG,
MIPS32R2 - FP64, MIPS32R2 - FP64A

One of the new tests fails in the two ODDSPREG configurations but I don't
plan to resolve that as it makes very little sense to pre-configure
GCC to explicitly use -modd-spreg (it only makes sense to use -mno-odd-spreg).
The failure is merely that the expected behaviour does not match up because
of the implicit -modd-spreg option. This same issue affects one of the
pre-existing loongson tests in the same configurations but I am leaving that
for the same reason.

The FP64 configurations enable extra tests which failed before for FP64 and
still fail after so will be cleaned up in later work. In particular there
are some missed vectorization cases which are to do with loongson.

Testing (N64):

The testsuite is still running after a rebase but it had no regressions last
time.

Changes (on top of addressing all comments):

* Handle the fact that -msingle-float, -msoft-float, -mfp32, -mfpxx, -mfp64
  are all part of the FPU ABI selection. As such if one of these is
  given which conflicts with an implicit option then the implicit option is
  not added.  This is necessary to provide a stable and consistent behaviour
  when writing assembly code such that (for example) building a file with
  -msoft-float and using .set hardfloat gets you into the standard hard-float
  ABI which is FP32. This issue was identified as part of resolving kernel
  issues when built with FPXX/.MIPS.abiflags aware tools:
  http://www.linux-mips.org/archives/linux-mips/2014-10/msg00886.html
  There are lots of other strange specs issues to resolve for MIPS but this
  is a step in the right direction.
* Fix a build warning
* Fix a testcase for FP64 configs

OK to commit (pending successful results for the N64 testrun)?

Thanks,
Matthew

---
 gcc/config.in                              |  2 +-
 gcc/config/mips/mips.c                     | 49 +++++++++++++++-------------
 gcc/config/mips/mips.h                     | 51 +++++++++++++++++-------------
 gcc/config/mips/mips.md                    |  8 ++---
 gcc/config/mips/mips.opt                   |  2 +-
 gcc/config/mips/mti-elf.h                  |  6 ++--
 gcc/config/mips/mti-linux.h                |  6 ++--
 gcc/configure                              | 20 ++++++------
 gcc/configure.ac                           | 12 +++----
 gcc/doc/invoke.texi                        | 17 +++++-----
 gcc/testsuite/gcc.target/mips/oddspreg-3.c |  2 +-
 11 files changed, 93 insertions(+), 82 deletions(-)
diff mbox

Patch

diff --git a/gcc/config.in b/gcc/config.in
index 40dd6f5..8fd0e0e 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -474,7 +474,7 @@ 
 
 /* Define if the assembler understands .module. */
 #ifndef USED_FOR_TARGET
-#undef HAVE_AS_MODULE
+#undef HAVE_AS_DOT_MODULE
 #endif
 
 
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 2dc6725..46f3890 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -5466,7 +5466,7 @@  mips_function_arg_boundary (machine_mode mode, const_tree type)
 static machine_mode
 mips_get_reg_raw_mode (int regno)
 {
-  if (mips_abi == ABI_32 && !TARGET_FLOAT32 && FP_REG_P (regno))
+  if (TARGET_FLOATXX && FP_REG_P (regno))
     return DFmode;
   return default_get_reg_raw_mode (regno);
 }
@@ -5796,19 +5796,24 @@  mips_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
 static bool
 mips_function_value_regno_p (const unsigned int regno)
 {
+  /* Most types only require one GPR or one FPR for return values but for
+     hard-float two FPRs can be used for _Complex types (for all ABIs)
+     and long doubles (for n64).  */
   if (regno == GP_RETURN
       || regno == FP_RETURN
-      || regno == FP_RETURN + 2
-      || (LONG_DOUBLE_TYPE_SIZE == 128
-	  && FP_RETURN != GP_RETURN
+      || (FP_RETURN != GP_RETURN
 	  && regno == FP_RETURN + 2))
     return true;
 
-  if ((regno == FP_RETURN + 1
-      || regno == FP_RETURN + 3)
+  /* For o32 FP32, _Complex double will be returned in four 32-bit registers.
+     This does not apply to o32 FPXX as floating-point function argument and
+     return registers are described as 64-bit even though floating-point
+     registers are primarily described as 32-bit internally.
+     See: mips_get_reg_raw_mode.  */
+  if ((mips_abi == ABI_32 && TARGET_FLOAT32)
       && FP_RETURN != GP_RETURN
-      && (mips_abi == ABI_32 && TARGET_FLOAT32)
-      && FP_REG_P (regno))
+      && (regno == FP_RETURN + 1
+	  || regno == FP_RETURN + 3))
     return true;
 
   return false;
@@ -8723,14 +8728,13 @@  mips_dwarf_register_span (rtx reg)
   machine_mode mode;
 
   /* TARGET_FLOATXX is implemented as 32-bit floating-point registers but
-     ensures that double precision registers are treated as if they were
+     ensures that double-precision registers are treated as if they were
      64-bit physical registers.  The code will run correctly with 32-bit or
-     64-bit registers which means that dwarf information cannot be precisely
-     correct for all scenarios.  We choose to state that the 64-bit values
-     are stored in a single 64-bit 'piece'.  This slightly unusual
-     construct can then be interpreted as either a pair of registers if the
-     registers are 32-bit or a single 64-bit register depending on
-     hardware.  */
+     64-bit registers which means that dwarf information cannot be precise
+     for all scenarios.  We choose to state that the 64-bit values are stored
+     in a single 64-bit 'piece'.  This slightly unusual construct can then be
+     interpreted as either a pair of registers if the registers are 32-bit or
+     a single 64-bit register depending on hardware.  */
   mode = GET_MODE (reg);
   if (FP_REG_P (REGNO (reg))
       && TARGET_FLOATXX
@@ -9047,7 +9051,7 @@  mips_file_start (void)
     fprintf (asm_out_file, "\t.nan\t%s\n",
 	     mips_nan == MIPS_IEEE_754_2008 ? "2008" : "legacy");
 
-#ifdef HAVE_AS_MODULE
+#ifdef HAVE_AS_DOT_MODULE
   /* Record the FP ABI.  See below for comments.  */
   if (TARGET_NO_FLOAT)
 #ifdef HAVE_AS_GNU_ATTRIBUTE
@@ -9087,7 +9091,7 @@  mips_file_start (void)
       attr = 2;
     /* 64-bit FP registers on a 32-bit target, -mips32r2 -mfp64.
        Reserved attr=4.
-       This case used 12 callee save double precision registers
+       This case used 12 callee-saved double-precision registers
        and is deprecated.  */
     /* 64-bit or 32-bit FP registers on a 32-bit target, -mfpxx.  */
     else if (TARGET_FLOATXX)
@@ -11888,9 +11892,8 @@  mips_hard_regno_mode_ok_p (unsigned int regno, machine_mode mode)
 	  || (MIN_FPRS_PER_FMT == 1 && size <= UNITS_PER_FPREG)))
     {
       /* Deny use of odd-numbered registers for 32-bit data for
-	 the O32 FP64A ABI.  */
-      if (mips_abi == ABI_32 && TARGET_FLOAT64 && !TARGET_ODD_SPREG
-	  && size <= 4 && (regno & 1) != 0)
+	 the o32 FP64A ABI.  */
+      if (TARGET_O32_FP64A_ABI && size <= 4 && (regno & 1) != 0)
 	return false;
 
       /* Allow 64-bit vector modes for Loongson-2E/2F.  */
@@ -12259,7 +12262,7 @@  mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
 
   if (((class1 == FP_REGS) != (class2 == FP_REGS))
       && ((TARGET_FLOATXX && !ISA_HAS_MXHC1)
-	  || (mips_abi == ABI_32 && TARGET_FLOAT64 && !TARGET_ODD_SPREG))
+	  || TARGET_O32_FP64A_ABI)
       && GET_MODE_SIZE (mode) >= 8)
     return true;
 
@@ -17281,7 +17284,7 @@  mips_option_override (void)
      line, set MASK_ODD_SPREG based on the ISA and ABI.  */
   if ((target_flags_explicit & MASK_ODD_SPREG) == 0)
     {
-      /* Disable TARGET_ODD_SPREG when using the O32 FPXX ABI.  */
+      /* Disable TARGET_ODD_SPREG when using the o32 FPXX ABI.  */
       if (!ISA_HAS_ODD_SPREG || TARGET_FLOATXX)
 	target_flags &= ~MASK_ODD_SPREG;
       else
@@ -17294,6 +17297,8 @@  mips_option_override (void)
   if (!TARGET_ODD_SPREG && TARGET_64BIT)
     {
       error ("unsupported combination: %s", "-mgp64 -mno-odd-spreg");
+      /* Allow compilation to continue further even though invalid output
+         will be produced.  */
       target_flags |= MASK_ODD_SPREG;
     }
 
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 2f7dcd4..f71d472 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -327,6 +327,11 @@  struct mips_cpu_info {
    -mfpxx, derive TARGET_FLOAT32 to represent -mfp32.  */
 #define TARGET_FLOAT32 (!TARGET_FLOAT64 && !TARGET_FLOATXX)
 
+/* TARGET_O32_FP64A_ABI represents all the conditions that form the
+   o32 FP64A ABI extension (-mabi=32 -mfp64 -mno-odd-spreg).  */
+#define TARGET_O32_FP64A_ABI (mips_abi == ABI_32 && TARGET_FLOAT64 \
+			      && !TARGET_ODD_SPREG)
+
 /* False if SC acts as a memory barrier with respect to itself,
    otherwise a SYNC will be emitted after SC for atomic operations
    that require ordering between the SC and following loads and
@@ -762,8 +767,8 @@  struct mips_cpu_info {
 #define MIPS_32BIT_OPTION_SPEC \
   "mips1|mips2|mips32*|mgp32"
 
-/* A spec condition that matches architectures should be targetted with
-   O32 FPXX for compatibility reasons.  */
+/* A spec condition that matches architectures should be targeted with
+   o32 FPXX for compatibility reasons.  */
 #define MIPS_FPXX_OPTION_SPEC \
   "mips2|mips3|mips4|mips5|mips32|mips32r2|mips32r3|mips32r5| \
    mips64|mips64r2|mips64r3|mips64r5"
@@ -792,9 +797,12 @@  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-fpu is ignored if -msoft-float, -msingle-float or -mdouble-float are
+     specified.
    --with-nan is ignored if -mnan is specified.
-   --with-fp-32 is ignored if -mfp is specified.
-   --with-odd-spreg-32 is ignored if -modd-spreg or -mno-odd-spreg are specified.
+   --with-fp-32 is ignored if -msoft-float, -msingle-float or -mfp are specified.
+   --with-odd-spreg-32 is ignored if -msoft-float, -msingle-float, -modd-spreg
+     or -mno-odd-spreg are specified.
    --with-divide is ignored if -mdivide-traps or -mdivide-breaks are
      specified. */
 #define OPTION_DEFAULT_SPECS \
@@ -806,10 +814,12 @@  struct mips_cpu_info {
   {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
-  {"fpu", "%{!msingle-float:%{!mdouble-float:-m%(VALUE)-float}}" }, \
+  {"fpu", "%{!msoft-float:%{!msingle-float:%{!mdouble-float:-m%(VALUE)-float}}}" }, \
   {"nan", "%{!mnan=*:-mnan=%(VALUE)}" }, \
-  {"fp_32", "%{" OPT_ARCH32 ":%{!mfp*:-mfp%(VALUE)}}" }, \
-  {"odd_spreg_32", "%{" OPT_ARCH32 ":%{!modd-spreg:%{!mno-odd-spreg:-m%(VALUE)}}}" }, \
+  {"fp_32", "%{" OPT_ARCH32 \
+	    ":%{!msoft-float:%{!msingle-float:%{!mfp*:-mfp%(VALUE)}}}}" }, \
+  {"odd_spreg_32", "%{" OPT_ARCH32 ":%{!msoft-float:%{!msingle-float:" \
+		   "%{!modd-spreg:%{!mno-odd-spreg:-m%(VALUE)}}}}}" }, \
   {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
   {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }, \
   {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }, \
@@ -1794,11 +1804,11 @@  struct mips_cpu_info {
 #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \
   mips_hard_regno_caller_save_mode (REGNO, NREGS, MODE)
 
-/* Odd-numbered single-precision registers are not considered call saved
-   for O32 FPXX as they will be clobbered when run on an FR=1 FPU.  */
+/* Odd-numbered single-precision registers are not considered callee-saved
+   for o32 FPXX as they will be clobbered when run on an FR=1 FPU.  */
 #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE)			\
   (TARGET_FLOATXX && hard_regno_nregs[REGNO][MODE] == 1			\
-   && FP_REG_P (REGNO) && (REGNO & 1))
+   && FP_REG_P (REGNO) && ((REGNO) & 1))
 
 #define MODES_TIEABLE_P mips_modes_tieable_p
 
@@ -2133,19 +2143,16 @@  enum reg_class
 #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X)			\
   mips_secondary_reload_class (CLASS, MODE, X, false)
 
-/* When targetting the O32 FPXX ABI then all doubleword or greater moves
-   to/from FP registers must be performed by FR-mode-aware instructions.
-   This can be achieved using mfhc1/mthc1 when these instructions are
+/* When targeting the o32 FPXX ABI, all moves with a length of doubleword
+   or greater must be performed by FR-mode-aware instructions.
+   This can be achieved using MFHC1/MTHC1 when these instructions are
    available but otherwise moves must go via memory.
-   For the O32 FP64A ABI then all odd-numbered doubleword or greater
-   moves to/from FP registers must move via memory as it is not permitted
-   to access the lower-half of these registers with mtc1/mfc1 since that
-   constitutes a single-precision access (which is forbidden).  This is
-   implemented by requiring all double-word moves to move via memory
-   as this check is register class based and not register based.
-   Splitting the FP_REGS into even and odd classes would allow the
-   precise restriction to be represented but this would have a
-   significant effect on other areas of the backend.  */
+   For the o32 FP64A ABI, all odd-numbered moves with a length of
+   doubleword or greater are required to use memory.  Using MTC1/MFC1
+   to access the lower-half of these registers would require a forbidden
+   single-precision access.  We require all double-word moves to use
+   memory because adding even and odd floating-point registers classes
+   would have a significant impact on the backend.  */
 #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE)			\
   mips_secondary_memory_needed ((CLASS1), (CLASS2), (MODE))
 
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index e33f309..647bf85 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -433,17 +433,13 @@  (define_attr "compression" "none,all,micromips"
   (const_string "none"))
 
 (define_attr "enabled" "no,yes"
-  (cond [;; The O32 FPXX and FP64A ABI extensions prohibit direct moves between
+  (cond [;; The o32 FPXX and FP64A ABI extensions prohibit direct moves between
 	 ;; GR_REG and FR_REG for 64-bit values.
 	 (and (eq_attr "move_type" "mtc,mfc")
 	      (match_test "(TARGET_FLOATXX && !ISA_HAS_MXHC1)
-			   || (mips_abi == ABI_32
-			       && TARGET_FLOAT64 && !TARGET_ODD_SPREG)")
+			   || TARGET_O32_FP64A_ABI")
 	      (eq_attr "dword_mode" "yes"))
 	 (const_string "no")
-
-	 ;; The micromips compressed instruction alternatives should only be
-	 ;; considered when targetting micromips.
 	 (and (eq_attr "compression" "micromips")
 	      (match_test "!TARGET_MICROMIPS"))
 	 (const_string "no")]
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 3558171..146961e 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -199,7 +199,7 @@  Use 32-bit floating-point registers
 
 mfpxx
 Target Report RejectNegative Mask(FLOATXX)
-Follow the O32 FPXX ABI
+Conform to the o32 FPXX ABI
 
 mfp64
 Target Report RejectNegative Mask(FLOAT64)
diff --git a/gcc/config/mips/mti-elf.h b/gcc/config/mips/mti-elf.h
index 9b8076c..d6dc1bb 100644
--- a/gcc/config/mips/mti-elf.h
+++ b/gcc/config/mips/mti-elf.h
@@ -34,8 +34,10 @@  along with GCC; see the file COPYING3.  If not see
      or -mgp setting.  */						\
   "%{!mabi=*: %{" MIPS_32BIT_OPTION_SPEC ": -mabi=32;: -mabi=n32}}",	\
 									\
-  /* If no FP option is specified, infer one from the ABI/ISA level.  */\
-  "%{!mfp*: %{mabi=32: %{" MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}",		\
+  /* If no FP ABI option is specified, infer one from the		\
+     ABI/ISA level.  */							\
+  "%{!msoft-float: %{!msingle-float: %{!mfp*: %{mabi=32: %{"		\
+  MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}}}",				\
 									\
   /* Make sure that an endian option is always present.  This makes	\
      things like LINK_SPEC easier to write.  */				\
diff --git a/gcc/config/mips/mti-linux.h b/gcc/config/mips/mti-linux.h
index ea98740..98d6582 100644
--- a/gcc/config/mips/mti-linux.h
+++ b/gcc/config/mips/mti-linux.h
@@ -39,8 +39,10 @@  along with GCC; see the file COPYING3.  If not see
      or -mgp setting.  */						\
   "%{!mabi=*: %{" MIPS_32BIT_OPTION_SPEC ": -mabi=32;: -mabi=n32}}",	\
 									\
-  /* If no FP option is specified, infer one from the ABI/ISA level.  */\
-  "%{!mfp*: %{mabi=32: %{" MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}",		\
+  /* If no FP ABI option is specified, infer one from the		\
+     ABI/ISA level.  */							\
+  "%{!msoft-float: %{!msingle-float: %{!mfp*: %{mabi=32: %{"		\
+  MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}}}",				\
 									\
   /* Base SPECs.  */							\
   BASE_DRIVER_SELF_SPECS						\
diff --git a/gcc/configure b/gcc/configure
index b83c954..a680933 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -26118,10 +26118,10 @@  fi
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .module support" >&5
 $as_echo_n "checking assembler for .module support... " >&6; }
-if test "${gcc_cv_as_mips_module+set}" = set; then :
+if test "${gcc_cv_as_mips_dot_module+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  gcc_cv_as_mips_module=no
+  gcc_cv_as_mips_dot_module=no
   if test x$gcc_cv_as != x; then
     $as_echo '.module fp=32' > conftest.s
     if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
@@ -26131,7 +26131,7 @@  else
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; }
     then
-	gcc_cv_as_mips_module=yes
+	gcc_cv_as_mips_dot_module=yes
     else
       echo "configure: failed program was" >&5
       cat conftest.s >&5
@@ -26139,16 +26139,16 @@  else
     rm -f conftest.o conftest.s
   fi
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mips_module" >&5
-$as_echo "$gcc_cv_as_mips_module" >&6; }
-if test $gcc_cv_as_mips_module = yes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mips_dot_module" >&5
+$as_echo "$gcc_cv_as_mips_dot_module" >&6; }
+if test $gcc_cv_as_mips_dot_module = yes; then
 
-$as_echo "#define HAVE_AS_MODULE 1" >>confdefs.h
+$as_echo "#define HAVE_AS_DOT_MODULE 1" >>confdefs.h
 
 fi
-    if test x$gcc_cv_as_mips_module = xno \
-       && test x$with_fp != x; then
-      as_fn_error "Requesting --with-fp= requires assembler support for .module." "$LINENO" 5
+    if test x$gcc_cv_as_mips_dot_module = xno \
+       && test x$with_fp_32 != x; then
+      as_fn_error "Requesting --with-fp-32= requires assembler support for .module." "$LINENO" 5
     fi
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 9fc9708..63ce54c 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4238,14 +4238,14 @@  LCF0:
 	  [Define if your assembler supports .gnu_attribute.])])
 
     gcc_GAS_CHECK_FEATURE([.module support],
-      gcc_cv_as_mips_module,,,
+      gcc_cv_as_mips_dot_module,,,
       [.module fp=32],,
-      [AC_DEFINE(HAVE_AS_MODULE, 1,
-	  [Define if yout assembler supports .module.])])
-    if test x$gcc_cv_as_mips_module = xno \
-       && test x$with_fp != x; then
+      [AC_DEFINE(HAVE_AS_DOT_MODULE, 1,
+	  [Define if your assembler supports .module.])])
+    if test x$gcc_cv_as_mips_dot_module = xno \
+       && test x$with_fp_32 != x; then
       AC_MSG_ERROR(
-	[Requesting --with-fp= requires assembler support for .module.])
+	[Requesting --with-fp-32= requires assembler support for .module.])
     fi
 
     gcc_GAS_CHECK_FEATURE([.micromips support],
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7b45f5e..756a85d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -786,7 +786,7 @@  Objective-C and Objective-C++ Dialects}.
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
--mgp32  -mgp64  -mfp32  mfpxx -mfp64  -mhard-float  -msoft-float @gol
+-mgp32  -mgp64  -mfp32  -mfpxx  -mfp64  -mhard-float  -msoft-float @gol
 -mno-float  -msingle-float  -mdouble-float @gol
 -modd-spreg -mno-odd-spreg @gol
 -mabs=@var{mode}  -mnan=@var{encoding} @gol
@@ -17717,12 +17717,12 @@  floating-point values are returned in @samp{$f0} only, not a
 remains the same in that the even-numbered double-precision registers
 are saved.
 
-A further two variants of the o32 ABI are also supported to enable
+Two additional variants of the o32 ABI are supported to enable
 a transition from 32-bit to 64-bit registers.  These are FPXX
 (@option{-mfpxx}) and FP64A (@option{-mfp64} @option{-mno-odd-spreg}).
 The FPXX extension mandates that all code must execute correctly
-whether run using 32-bit or 64-bit registers.  The code can also
-interlink with either FP32 or FP64, but not both simulataneously.
+when run using 32-bit or 64-bit registers.  The code can be interlinked
+with either FP32 or FP64, but not both.
 The FP64A extension is similar to the FP64 extension but forbids the
 use of odd-numbered single-precision registers.  This can be used
 in conjunction with the @code{FRE} mode of FPUs in MIPS32R5
@@ -17818,8 +17818,7 @@  Assume that floating-point registers are 64 bits wide.
 
 @item -mfpxx
 @opindex mfpxx
-Do not assume that floating-point registers are specifically 32 bits or
-64 bits wide.
+Do not assume the width of floating-point registers.
 
 @item -mhard-float
 @opindex mhard-float
@@ -17857,9 +17856,9 @@  operations.  This is the default.
 @opindex modd-spreg
 @opindex mno-odd-spreg
 Enable the use of odd-numbered single-precision floating-point registers
-for the o32 ABI.  This is the default for specific processors that are
-known to support these registers, however the o32 FPXX extension sets
-@code{-mno-odd-spreg} by default.
+for the o32 ABI.  This is the default for processors that are known to
+known to support these registers.  When using the o32 FPXX ABI,
+@code{-mno-odd-spreg} is set by default.
 
 @item -mabs=2008
 @itemx -mabs=legacy
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-3.c b/gcc/testsuite/gcc.target/mips/oddspreg-3.c
index 8a2eb63..f287eb6 100644
--- a/gcc/testsuite/gcc.target/mips/oddspreg-3.c
+++ b/gcc/testsuite/gcc.target/mips/oddspreg-3.c
@@ -1,6 +1,6 @@ 
 /* Check that we disable odd-numbered single precision registers.  */
 /* { dg-skip-if "needs asm output" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
-/* { dg-options "-mabi=32 -march=loongson3a -mhard-float" } */
+/* { dg-options "-mabi=32 -mfp32 -march=loongson3a -mhard-float" } */
 
 void
 foo ()