Hi Matthew,
Review comments are attached.  I will tackle the R6 patch next.
Thanks,
Catherine

> -----Original Message-----
> From: Matthew Fortune [mailto:matthew.fort...@imgtec.com]
> Sent: Friday, August 22, 2014 5:43 AM
> To: 'gcc-patches@gcc.gnu.org' (gcc-patches@gcc.gnu.org); Eric Christopher
> (echri...@gmail.com)
> Cc: Moore, Catherine; Richard Sandiford; Rich Fuhler; Rozycki, Maciej; Myers,
> Joseph
> Subject: [PATCHv2][MIPS] Implement O32 ABI extensions (GCC)
> 
> Updated patch covering all comments from the previous thread:
> https://gcc.gnu.org/ml/gcc-patches/2014-05/msg00401.html
> 
> This patch has merged together the odd-spreg work with the other ABI work
> as these two features are now inseparable due to the inclusion of a 4th FP
> ABI variant called FP64A. The wiki page describing these extensions has been
> updated and the patch is consistent with the features.
> 
> https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-
> _FR0_and_FR1_Interlinking
> 
> It is worth noting that LLVM 3.5 will include all ABI extensions described in 
> the
> wiki page with consistent options and behaviour.
> 
> The vast majority of this patch has been reviewed in detail already and
> testing has been ongoing for some time within teams at Imagination.
> This code has also been released for inclusion in the next Android NDK.
> 
> I have addressed one of the final concerns from Richard and Maciej regarding
> an inconsistency between the prologue FP callee-save and fixed-regs. I
> opted to resolve this in a very focussed manner to just address the impact of
> fixed-regs rather than the more general issue of occasionally saving more
> state than absolutely required. If there is a desire to improve this further
> then I am very keen to leave that to a future patch.
> 
> This work has been tested for both bare metal and linux based targets.
> There are no regressions.
> 
> This patch is dependent on two patches which are awaiting approval:
> 
> "Add target hook to override DWARF2 frame register size
> https://gcc.gnu.org/ml/gcc-patches/2014-08/msg01748.html
> 
> "Do not reload unallocated FP_REGS pseudos via GR_REGS"
> https://gcc.gnu.org/ml/gcc-patches/2014-08/msg01745.html
> 
> Regards,
> Matthew
> 
> 2014-07-31  Matthew Fortune  <matthew.fort...@imgtec.com>
> 
> gcc/
>       * common/config/mips/mips-common.c (mips_handle_option):
> Ensure
>       that -mfp32, -mfp64 disable -mfpxx and -mfpxx disables -mfp64.
>       * config.gcc (--with-fp-32): New option.
>       (--with-odd-spreg-32): Likewise.
>       * config.in (HAVE_AS_MODULE): New config define.
>       * config/mips/mips-protos.h
>       (mips_secondary_memory_needed): New prototype.
>       (mips_hard_regno_caller_save_mode): Likewise.
>       * config/mips/mips.c (mips_get_reg_raw_mode): New static
> prototype.
>       (mips_get_arg_info): Assert that V2SFmode is only handled specially
>       with TARGET_PAIRED_SINGLE_FLOAT.
>       (mips_return_mode_in_fpr_p): Likewise.
>       (mips16_call_stub_mode_suffix): Likewise.
>       (mips_get_reg_raw_mode): New static function.
>       (mips_return_fpr_pair): O32 return values span two registers.
>       (mips16_build_call_stub): Likewise.
>       (mips_function_value_regno_p): Support both FP return registers.
>       (mips_output_64bit_xfer): Use mthc1 whenever
> TARGET_HAS_MXHC1.  Add
>       specific cases for TARGET_FPXX to move via memory.
>       (mips_dwarf_register_span): For TARGET_FPXX pretend that modes
> larger
>       than UNITS_PER_FPREG 'span' one register.
>       (mips_dwarf_frame_reg_mode): New static function.
>       (mips_file_start): Switch to using .module instead of .gnu_attribute.
>       No longer support FP ABI 4 (-mips32r2 -mfp64), replace with FP ABI 6.
>       Add FP ABI 5 (-mfpxx) and FP ABI 7 (-mfp64 -mno-odd-spreg).
>       (mips_save_reg, mips_restore_reg): Always represent DFmode
> frame
>       slots with two CFI directives even for O32 FP64.
>       (mips_for_each_saved_gpr_and_fpr): Account for fixed_regs when
>       saving/restoring callee-saved registers.
>       (mips_hard_regno_mode_ok_p): Implement O32 FP64A extension.
>       (mips_secondary_memory_needed): New function.
>       (mips_option_override): ABI check for TARGET_FLOATXX.  Disable
>       odd-numbered single-precision registers when using
> TARGET_FLOATXX.
>       Implement -modd-spreg and defaults.
>       (mips_conditional_register_usage): Redefine O32 FP64 to match O32
> FP32
>       callee-saved behaviour.
>       (mips_hard_regno_caller_save_mode): Implement.
>       (TARGET_GET_RAW_RESULT_MODE): Define target hook.
>       (TARGET_GET_RAW_ARG_MODE): Define target hook.
>       (TARGET_DWARF_FRAME_REG_MODE): Define target hook.
>       * config/mips/mips.h (TARGET_FLOAT32): New macro.
>       (TARGET_CPU_CPP_BUILTINS): TARGET_FPXX is __mips_fpr==0.
> Add
>       _MIPS_SPFPSET builtin define.
>       (MIPS_FPXX_OPTION_SPEC): New macro.
>       (OPTION_DEFAULT_SPECS): Pass through --with-fp-32=* to -mfp and
>       --with-odd-spreg-32=* to -m[no-]odd-spreg.
>       (ISA_HAS_ODD_SPREG): New macro.
>       (ISA_HAS_MXHC1): True for anything other than -mfp32.
>       (ASM_SPEC): Pass through mfpxx, mfp64, -mno-odd-spreg and -
> modd-spreg.
>       (MIN_FPRS_PER_FMT): Redefine in terms of TARGET_ODD_SPREG.
>       (HARD_REGNO_CALLER_SAVE_MODE): Define.  Implement O32
> FPXX extension
>       (HARD_REGNO_CALL_PART_CLOBBERED): Likewise.
>       (SECONDARY_MEMORY_NEEDED): Likewise.
>       (FUNCTION_ARG_REGNO_P): Update for O32 FPXX and FP64
> extensions.
>       * config/mips/mips.md (define_attr enabled): Implement O32 FPXX
> and
>       FP64A ABI extensions.
>       (move_doubleword_fpr<mode>): Use ISA_HAS_MXHC1 instead of
>       TARGET_FLOAT64.
>       * config/mips/mips.opt (mfpxx): New target option.
>       (modd-spreg): Likewise.
>       * config/mips/mti-elf.h (DRIVER_SELF_SPECS): Infer FP ABI from
> arch.
>       * config/mips/mti-linux.h (DRIVER_SELF_SPECS): Likewise and
> remove
>       fp64 sysroot.
>       * config/mips/t-mti-elf: Remove fp64 multilib.
>       * config/mips/t-mti-linux: Likewise.
>       * configure.ac: Detect .module support.
>       * configure: Regenerate.
>       * doc/invoke.texi: Document -mfpxx, -modd-spreg, -mno-odd-spreg
> option.
> 
> gcc/testsuite/
>       * gcc.target/mips/args-1.c: Handle __mips_fpr == 0.
>       * gcc.target/mips/call-clobbered-1.c: New.
>       * gcc.target/mips/call-clobbered-2.c: New.
>       * gcc.target/mips/call-clobbered-3.c: New.
>       * gcc.target/mips/call-clobbered-4.c: New.
>       * gcc.target/mips/call-clobbered-5.c: New.
>       * gcc.target/mips/call-saved-4.c: New.
>       * gcc.target/mips/call-saved-5.c: New.
>       * gcc.target/mips/call-saved-6.c: New.
>       * gcc.target/mips/mips.exp: Support -mfpxx, -ffixed-f*,
>       and -m[no-]odd-spreg.  Use _MIPS_SPFPSET to determine default
>       odd-spreg option.  Account for -modd-spreg in minimum arch code.
>       * gcc.target/mips/movdf-1.c: New.
>       * gcc.target/mips/movdf-2.c: New.
>       * gcc.target/mips/movdf-3.c: New.
>       * gcc.target/mips/oddspreg-1.c: New.
>       * gcc.target/mips/oddspreg-2.c: New.
>       * gcc.target/mips/oddspreg-3.c: New.
>       * gcc.target/mips/oddspreg-4.c: New.
>       * gcc.target/mips/oddspreg-5.c: New.
>       * gcc.target/mips/oddspreg-6.c: New.
> 
> libgcc/
>       * config/mips/mips16.S: Set .module when supported.  Update O32
>       FP64 calling convention and use for FPXX when possible.  Add FPXX
>       calling convention fallback case
>Index: libgcc/config/mips/mips16.S
>===================================================================
>--- libgcc/config/mips/mips16.S        (revision 216257)
>+++ libgcc/config/mips/mips16.S        (working copy)
>@@ -21,6 +21,8 @@ a copy of the GCC Runtime Library Exception along
> see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> <http://www.gnu.org/licenses/>.  */
> 
>+#include "auto-host.h"
>+
> #if defined(__mips_micromips) || defined(__mips_soft_float)
>   /* Do nothing because this code is only needed when linking
>      against mips16 hard-float objects.  Neither micromips code
>@@ -29,6 +31,16 @@ see the files COPYING3 and COPYING.RUNTIME respect
>      for those cases.  */
> #else
> 
>+#if defined(HAVE_AS_MODULE)
>+#if __mips_fpr == 32
>+      .module fp=32
>+#elif __mips_fpr == 0
>+      .module fp=xx
>+#elif __mips_fpr == 64
>+      .module fp=64
>+#endif
>+#endif
>+
> /* This file contains mips16 floating point support functions.  These
>    functions are called by mips16 code to handle floating point when
>    -msoft-float is not used.  They accept the arguments and return
>@@ -152,8 +164,6 @@ see the files COPYING3 and COPYING.RUNTIME respect
> /* The high 32 bits of $2 correspond to the second word in memory;
>    i.e. the imaginary part.  */
> #define MOVE_SC_RET(D, T) MERGE_GPR##D ($2, $f1, $f0); jr T
>-#elif __mips_fpr == 64
>-#define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f1)
> #else
> #define MOVE_SC_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##c1 $3,$f2)
> #endif
>@@ -174,16 +184,29 @@ see the files COPYING3 and COPYING.RUNTIME respect
> #define MOVE_DF_BYTE8(D) dm##D##c1 $5,$f13
> #define MOVE_DF_RET(D, T) DELAY##D (T, dm##D##c1 $2,$f0)
> #define MOVE_DC_RET(D, T) dm##D##c1 $3,$f1; MOVE_DF_RET (D, T)
>-#elif __mips_fpr == 64 && defined(__MIPSEB__)
>+#elif __mips_fpr != 32 && __mips_isa_rev >= 2 && defined(__MIPSEB__)
> #define MOVE_DF_BYTE0(D) m##D##c1 $5,$f12; m##D##hc1 $4,$f12
> #define MOVE_DF_BYTE8(D) m##D##c1 $7,$f14; m##D##hc1 $6,$f14
> #define MOVE_DF_RET(D, T) m##D##c1 $3,$f0; DELAY##D (T, m##D##hc1 $2,$f0)
>-#define MOVE_DC_RET(D, T) m##D##c1 $5,$f1; m##D##hc1 $4,$f1; MOVE_DF_RET (D, 
>T)
>-#elif __mips_fpr == 64
>+#define MOVE_DC_RET(D, T) m##D##c1 $5,$f2; m##D##hc1 $4,$f2; MOVE_DF_RET (D, 
>T)
>+#elif __mips_fpr != 32 && __mips_isa_rev >= 2
> #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f12; m##D##hc1 $5,$f12
> #define MOVE_DF_BYTE8(D) m##D##c1 $6,$f14; m##D##hc1 $7,$f14
> #define MOVE_DF_RET(D, T) m##D##c1 $2,$f0; DELAY##D (T, m##D##hc1 $3,$f0)
>-#define MOVE_DC_RET(D, T) m##D##c1 $4,$f1; m##D##hc1 $5,$f1; MOVE_DF_RET (D, 
>T)
>+#define MOVE_DC_RET(D, T) m##D##c1 $4,$f2; m##D##hc1 $5,$f2; MOVE_DF_RET (D, 
>T)
>+#elif __mips_fpr == 0
>+#define MOVE_DF_BYTE0t sw $4, 0($29); sw $5, 4($29); ldc1 $f12, 0($29)
>+#define MOVE_DF_BYTE0f sdc1 $f12, 0($29); lw $4, 0($29); lw $5, 4($29)
>+#define MOVE_DF_BYTE0(D) MOVE_DF_BYTE0##D
>+#define MOVE_DF_BYTE8t sw $6, 8($29); sw $7, 12($29); ldc1 $f14, 8($29)
>+#define MOVE_DF_BYTE8f sdc1 $f14, 8($29); lw $6, 8($29); lw $7, 12($29)
>+#define MOVE_DF_BYTE8(D) MOVE_DF_BYTE8##D
>+#define MOVE_DF_RETt(T) sw $2, 0($29); sw $3, 4($29); DELAYt (T, ldc1 $f0, 
>0($29))
>+#define MOVE_DF_RETf(T) sdc1 $f0, 0($29); lw $2, 0($29); DELAYf (T, lw $3, 
>4($29))
>+#define MOVE_DF_RET(D, T) MOVE_DF_RET##D(T)
>+#define MOVE_DC_RETt(T) sw $4, 8($29); sw $5, 12($29); ldc1 $f2, 8($29); 
>MOVE_DF_RETt(T)
>+#define MOVE_DC_RETf(T) sdc1 $f2, 8($29); lw $4, 8($29); lw $5, 12($29); 
>MOVE_DF_RETf(T)
>+#define MOVE_DC_RET(D, T) MOVE_DF_RET##D(T)
> #elif defined(__MIPSEB__)
> /* FPRs are little-endian.  */
> #define MOVE_DF_BYTE0(D) m##D##c1 $4,$f13; m##D##c1 $5,$f12
>Index: gcc/doc/invoke.texi
>===================================================================
>--- gcc/doc/invoke.texi        (revision 216257)
>+++ gcc/doc/invoke.texi        (working copy)
>@@ -785,8 +785,9 @@ 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  -mfp64  -mhard-float  -msoft-float @gol
>+-mgp32  -mgp64  -mfp32  mfpxx -mfp64  -mhard-float  -msoft-float @gol

Should be:
  -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
> -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
> -mmcu -mmno-mcu @gol
>@@ -17631,8 +17632,21 @@ same, but each scalar value is passed in a single
> rather than a pair of 32-bit registers.  For example, scalar
> floating-point values are returned in @samp{$f0} only, not a
> @samp{$f0}/@samp{$f1} pair.  The set of call-saved registers also
>-remains the same, but all 64 bits are saved.
>+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.

  The FPXX extension mandates that all code must execute correctly
  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
>+processors and allows both FP32 and FP64A code to interlink and
>+run in the same process without changing FPU modes.
>+
> @item -mabicalls
> @itemx -mno-abicalls
> @opindex mabicalls
>@@ -17720,6 +17734,11 @@ Assume that floating-point registers are 32 bits w
> @opindex mfp64
> 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
> Use floating-point coprocessor instructions.
>@@ -17751,6 +17770,15 @@ operations.
> Assume that the floating-point coprocessor supports double-precision
> operations.  This is the default.
> 
>+@item -modd-spreg
>+@itemx -mno-odd-spreg
>+@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.

        Enable the use of odd-numbered single-precision floating-point registers
        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
> @opindex mabs=2008
>Index: gcc/configure
>===================================================================
>--- gcc/configure      (revision 216257)
>+++ gcc/configure      (working copy)
>@@ -26115,6 +26115,41 @@ $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confd
> 
> 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 :
>+  $as_echo_n "(cached) " >&6
>+else
>+  gcc_cv_as_mips_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'
>+  { { 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_module=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_module" >&5
>+$as_echo "$gcc_cv_as_mips_module" >&6; }
>+if test $gcc_cv_as_mips_module = yes; then
>+
>+$as_echo "#define HAVE_AS_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
>+    fi
>+
>     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for 
> .micromips support" >&5
> $as_echo_n "checking assembler for .micromips support... " >&6; }
> if test "${gcc_cv_as_micromips_support+set}" = set; then :
>Index: gcc/testsuite/gcc.target/mips/movdf-1.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/movdf-1.c    (revision 0)
>+++ gcc/testsuite/gcc.target/mips/movdf-1.c    (revision 0)
>@@ -0,0 +1,14 @@
>+/* Check that we move DFmode values via memory between FP and GP.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "-mabi=32 -mfpxx isa=2" } */
>+
>+void bar (void);
>+
>+double
>+foo (int x, double a)
>+{
>+  return a;
>+}
>+/* { dg-final { scan-assembler-not "mthc1" } } */
>+/* { dg-final { scan-assembler-not "mtc1" } } */
>+/* { dg-final { scan-assembler-times "ldc1" 1 } } */
>Index: gcc/testsuite/gcc.target/mips/call-clobbered-5.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-clobbered-5.c   (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-clobbered-5.c   (revision 0)
>@@ -0,0 +1,21 @@
>+/* Check that we handle call-clobbered FPRs correctly.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "-mabi=32 -mfp64 -ffixed-f0 -ffixed-f1 -ffixed-f2 -ffixed-f3 
>-ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 -ffixed-f10 
>-ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 -ffixed-f16 
>-ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 -ffixed-f24 
>-ffixed-f26 -ffixed-f28 -ffixed-f30" } */
>+
>+void bar (void);
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  bar();
>+  return b;
>+}
>+/* { dg-final { scan-assembler-times "lwc1" 3 } } */
>+/* { dg-final { scan-assembler-times "swc1" 1 } } */
>+/* { dg-final { scan-assembler-not "sdc1" } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>+/* { dg-final { scan-assembler-not "mtc" } } */
>+/* { dg-final { scan-assembler-not "mfc" } } */
>+/* { dg-final { scan-assembler-not "mthc" } } */
>+/* { dg-final { scan-assembler-not "mfhc" } } */
>Index: gcc/testsuite/gcc.target/mips/movdf-2.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/movdf-2.c    (revision 0)
>+++ gcc/testsuite/gcc.target/mips/movdf-2.c    (revision 0)
>@@ -0,0 +1,14 @@
>+/* Check that we move DFmode values using mthc between FP and GP.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "-mabi=32 -mfpxx isa_rev=2" } */
>+
>+void bar (void);
>+
>+double
>+foo (int x, double a)
>+{
>+  return a;
>+}
>+/* { dg-final { scan-assembler "mthc1" } } */
>+/* { dg-final { scan-assembler "mtc1" } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>Index: gcc/testsuite/gcc.target/mips/mips.exp
>===================================================================
>--- gcc/testsuite/gcc.target/mips/mips.exp     (revision 216257)
>+++ gcc/testsuite/gcc.target/mips/mips.exp     (working copy)
>@@ -235,7 +235,7 @@ set mips_option_groups {
>     endianness "-E(L|B)|-me(l|b)"
>     float "-m(hard|soft)-float"
>     forbid_cpu "forbid_cpu=.*"
>-    fp "-mfp(32|64)"
>+    fp "-mfp(32|xx|64)"
>     gp "-mgp(32|64)"
>     long "-mlong(32|64)"
>     micromips "-mmicromips|-mno-micromips"
>@@ -248,6 +248,10 @@ set mips_option_groups {
>     dump "-fdump-.*"
> }
> 
>+for { set option 0 } { $option < 32 } { incr option } {
>+    lappend mips_option_groups "fixed-f$option" "-ffixed-f$option"
>+}
>+
> # Add -mfoo/-mno-foo options to mips_option_groups.
> foreach option {
>     abicalls
>@@ -270,6 +274,7 @@ foreach option {
>     synci
>     relax-pic-calls
>     mcount-ra-address
>+    odd-spreg
> } {
>     lappend mips_option_groups $option "-m(no-|)$option"
> }
>@@ -723,8 +728,12 @@ proc mips-dg-init {} {
>           #if __mips_fpr == 64
>           "-mfp64",
>           #else
>+          #if __mips_fpr == 0
>+          "-mfpxx",
>+          #else
>           "-mfp32",
>           #endif
>+          #endif
> 
>           #ifdef __mips64
>           "-mgp64",
>@@ -756,6 +765,12 @@ proc mips-dg-init {} {
>           "-mno-paired-single",
>           #endif
> 
>+          #if _MIPS_SPFPSET == 32
>+          "-modd-spreg",
>+          #else
>+          "-mno-odd-spreg",
>+          #endif
>+
>           #if __mips_abicalls
>           "-mabicalls",
>           #else
>@@ -841,6 +856,8 @@ proc mips-dg-finish {} {
> #            |                           |
> #         -mfp64                      -mfp32
> #            |                           |
>+#         -modd-spreg                 -mno-odd-spreg
>+#            |                           |
> #         -mabs=2008/-mabs=legacy     <no option>
> #            |                           |
> #         -mhard-float                -msoft-float
>@@ -930,6 +947,7 @@ proc mips-dg-options { args } {
>     mips_option_dependency options "-mips3d" "-mpaired-single"
>     mips_option_dependency options "-mpaired-single" "-mfp64"
>     mips_option_dependency options "-mfp64" "-mhard-float"
>+    mips_option_dependency options "-mfp64" "-modd-spreg"
>     mips_option_dependency options "-mabs=2008" "-mhard-float"
>     mips_option_dependency options "-mabs=legacy" "-mhard-float"
>     mips_option_dependency options "-mrelax-pic-calls" "-mno-plt"
>@@ -1046,10 +1064,13 @@ proc mips-dg-options { args } {
>         # We need a MIPS32 or MIPS64 ISA for:
>       #
>         #   - paired-single instructions(*)
>+        #   - odd numbered single precision registers
>         #
>       # (*) Note that we don't support MIPS V at the moment.
>       } elseif { $isa_rev < 1
>-                 && [mips_have_test_option_p options "-mpaired-single"] } {
>+                 && ([mips_have_test_option_p options "-mpaired-single"]
>+                     || ([mips_have_test_option_p options "-modd-spreg"]
>+                         && ![mips_have_test_option_p options "-mfp64"]))} {
>           if { $gp_size == 32 } {
>               mips_make_test_option options "-mips32"
>           } else {
>@@ -1071,7 +1092,9 @@ proc mips-dg-options { args } {
>       # (*) needed by both -mbranch-likely and -mfix-r10000
>       } elseif { $isa < 2
>                  && ([mips_have_test_option_p options "-mbranch-likely"]
>-                     || [mips_have_test_option_p options "-mfix-r10000"]) } {
>+                     || [mips_have_test_option_p options "-mfix-r10000"]
>+                     || ($gp_size == 32
>+                         && [mips_have_test_option_p options "-mfpxx"])) } {
>           mips_make_test_option options "-mips2"
>       # Check whether we need to switch from a 32-bit processor to the
>       # "nearest" 64-bit processor.
>@@ -1122,6 +1145,9 @@ proc mips-dg-options { args } {
>       } elseif { [mips_have_test_option_p options "-mlong64"]
>                  && [mips_long32_abi_p $abi] } {
>           set force_abi 1
>+      } elseif { [mips_have_test_option_p options "-mfpxx"]
>+                 && ![mips_same_option_p $abi "-mabi=32"] } {
>+          set force_abi 1
>       } else {
>           set force_abi 0
>       }
>@@ -1193,6 +1219,9 @@ proc mips-dg-options { args } {
>       }
>       if { $isa_rev < 1 } {
>           mips_make_test_option options "-mno-paired-single"
>+          if { ![mips_have_test_option_p options "-mgp64"] } {
>+              mips_make_test_option options "-mno-odd-spreg"
>+          }
>       }
>       if { $isa_rev < 2 } {
>           if { $gp_size == 32 } {
>@@ -1223,6 +1252,7 @@ proc mips-dg-options { args } {
>     mips_option_dependency options "-mplt" "-mno-shared"
>     mips_option_dependency options "-mno-shared" "-fno-pic"
>     mips_option_dependency options "-mfp32" "-mno-paired-single"
>+    mips_option_dependency options "-mfpxx" "-mno-paired-single"
>     mips_option_dependency options "-msoft-float" "-mno-paired-single"
>     mips_option_dependency options "-mno-paired-single" "-mno-mips3d"
> 
>@@ -1244,7 +1274,9 @@ proc mips-dg-options { args } {
>     foreach group $mips_abi_groups {
>       set old_option [mips_original_option $group]
>       set new_option [mips_option options $group]
>-      if { ![mips_same_option_p $old_option $new_option] } {
>+      if { ![mips_same_option_p $old_option $new_option]
>+           && ![mips_same_option_p $old_option "-mfpxx"]
>+           && ![mips_same_option_p $new_option "-mfpxx"] } {
>           switch -- [lindex $do_what 0] {
>               link -
>               run {
>Index: gcc/testsuite/gcc.target/mips/oddspreg-1.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-1.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-1.c (revision 0)
>@@ -0,0 +1,13 @@
>+/* Check that we enable odd-numbered single precision registers.  */
>+/* { dg-options "-mabi=32 -modd-spreg -mhard-float" } */
>+
>+#if _MIPS_SPFPSET != 32
>+#error "Incorrect number of single-precision registers reported"
>+#endif
>+
>+void
>+foo ()
>+{
>+  register float foo asm ("$f1");
>+  asm volatile ("" : "=f" (foo));
>+}
>Index: gcc/testsuite/gcc.target/mips/call-saved-4.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-saved-4.c       (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-saved-4.c       (revision 0)
>@@ -0,0 +1,32 @@
>+/* Check that we save the correct call-saved GPRs and FPRs.  */
>+/* { dg-options "isa>=2 -mabi=32 -mfp32" } */
>+
>+void bar (void);
>+
>+void
>+foo (int x)
>+{
>+  __builtin_unwind_init ();
>+  __builtin_eh_return (x, bar);
>+}
>+/* { dg-final { scan-assembler "\\\$16" } } */
>+/* { dg-final { scan-assembler "\\\$17" } } */
>+/* { dg-final { scan-assembler "\\\$18" } } */
>+/* { dg-final { scan-assembler "\\\$19" } } */
>+/* { dg-final { scan-assembler "\\\$20" } } */
>+/* { dg-final { scan-assembler "\\\$21" } } */
>+/* { dg-final { scan-assembler "\\\$22" } } */
>+/* { dg-final { scan-assembler "\\\$23" } } */
>+/* { dg-final { scan-assembler "\\\$(30|fp)" } } */
>+/* { dg-final { scan-assembler "\\\$f20" } } */
>+/* { dg-final { scan-assembler "\\\$f22" } } */
>+/* { dg-final { scan-assembler "\\\$f24" } } */
>+/* { dg-final { scan-assembler "\\\$f26" } } */
>+/* { dg-final { scan-assembler "\\\$f28" } } */
>+/* { dg-final { scan-assembler "\\\$f30" } } */
>+/* { dg-final { scan-assembler-not "\\\$f21" } } */
>+/* { dg-final { scan-assembler-not "\\\$f23" } } */
>+/* { dg-final { scan-assembler-not "\\\$f25" } } */
>+/* { dg-final { scan-assembler-not "\\\$f27" } } */
>+/* { dg-final { scan-assembler-not "\\\$f29" } } */
>+/* { dg-final { scan-assembler-not "\\\$f31" } } */
>Index: gcc/testsuite/gcc.target/mips/movdf-3.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/movdf-3.c    (revision 0)
>+++ gcc/testsuite/gcc.target/mips/movdf-3.c    (revision 0)
>@@ -0,0 +1,13 @@
>+/* Check that we move DFmode values using mtc1 between FP and GP.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "-mabi=32 -mfp32 isa=2" } */
>+
>+void bar (void);
>+
>+double
>+foo (int x, double a)
>+{
>+  return a;
>+}
>+/* { dg-final { scan-assembler-times "mtc1" 2 } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>Index: gcc/testsuite/gcc.target/mips/oddspreg-2.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-2.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-2.c (revision 0)
>@@ -0,0 +1,10 @@
>+/* Check that we disable odd-numbered single precision registers.  */
>+/* { dg-skip-if "needs asm output" { *-*-* } { "-fno-fat-lto-objects" } { "" 
>} } */
>+/* { dg-options "-mabi=32 -mno-odd-spreg -mhard-float" } */
>+
>+void
>+foo ()
>+{
>+  register float foo asm ("$f1"); /* { dg-error "isn't suitable for" } */
>+  asm volatile ("" : "=f" (foo));
>+}
>Index: gcc/testsuite/gcc.target/mips/call-saved-5.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-saved-5.c       (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-saved-5.c       (revision 0)
>@@ -0,0 +1,32 @@
>+/* Check that we save the correct call-saved GPRs and FPRs.  */
>+/* { dg-options "-mabi=32 -mfpxx" } */
>+
>+void bar (void);
>+
>+void
>+foo (int x)
>+{
>+  __builtin_unwind_init ();
>+  __builtin_eh_return (x, bar);
>+}
>+/* { dg-final { scan-assembler "\\\$16" } } */
>+/* { dg-final { scan-assembler "\\\$17" } } */
>+/* { dg-final { scan-assembler "\\\$18" } } */
>+/* { dg-final { scan-assembler "\\\$19" } } */
>+/* { dg-final { scan-assembler "\\\$20" } } */
>+/* { dg-final { scan-assembler "\\\$21" } } */
>+/* { dg-final { scan-assembler "\\\$22" } } */
>+/* { dg-final { scan-assembler "\\\$23" } } */
>+/* { dg-final { scan-assembler "\\\$(30|fp)" } } */
>+/* { dg-final { scan-assembler "\\\$f20" } } */
>+/* { dg-final { scan-assembler "\\\$f22" } } */
>+/* { dg-final { scan-assembler "\\\$f24" } } */
>+/* { dg-final { scan-assembler "\\\$f26" } } */
>+/* { dg-final { scan-assembler "\\\$f28" } } */
>+/* { dg-final { scan-assembler "\\\$f30" } } */
>+/* { dg-final { scan-assembler-not "\\\$f21" } } */
>+/* { dg-final { scan-assembler-not "\\\$f23" } } */
>+/* { dg-final { scan-assembler-not "\\\$f25" } } */
>+/* { dg-final { scan-assembler-not "\\\$f27" } } */
>+/* { dg-final { scan-assembler-not "\\\$f29" } } */
>+/* { dg-final { scan-assembler-not "\\\$f31" } } */
>Index: gcc/testsuite/gcc.target/mips/oddspreg-3.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-3.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-3.c (revision 0)
>@@ -0,0 +1,10 @@
>+/* 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" } */
>+
>+void
>+foo ()
>+{
>+  register float foo asm ("$f1"); /* { dg-error "isn't suitable for" } */
>+  asm volatile ("" : "=f" (foo));
>+}
>Index: gcc/testsuite/gcc.target/mips/call-saved-6.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-saved-6.c       (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-saved-6.c       (revision 0)
>@@ -0,0 +1,32 @@
>+/* Check that we save the correct call-saved GPRs and FPRs.  */
>+/* { dg-options "-mabi=32 -mfp64" } */
>+
>+void bar (void);
>+
>+void
>+foo (int x)
>+{
>+  __builtin_unwind_init ();
>+  __builtin_eh_return (x, bar);
>+}
>+/* { dg-final { scan-assembler "\\\$16" } } */
>+/* { dg-final { scan-assembler "\\\$17" } } */
>+/* { dg-final { scan-assembler "\\\$18" } } */
>+/* { dg-final { scan-assembler "\\\$19" } } */
>+/* { dg-final { scan-assembler "\\\$20" } } */
>+/* { dg-final { scan-assembler "\\\$21" } } */
>+/* { dg-final { scan-assembler "\\\$22" } } */
>+/* { dg-final { scan-assembler "\\\$23" } } */
>+/* { dg-final { scan-assembler "\\\$(30|fp)" } } */
>+/* { dg-final { scan-assembler "\\\$f20" } } */
>+/* { dg-final { scan-assembler "\\\$f22" } } */
>+/* { dg-final { scan-assembler "\\\$f24" } } */
>+/* { dg-final { scan-assembler "\\\$f26" } } */
>+/* { dg-final { scan-assembler "\\\$f28" } } */
>+/* { dg-final { scan-assembler "\\\$f30" } } */
>+/* { dg-final { scan-assembler-not "\\\$f21" } } */
>+/* { dg-final { scan-assembler-not "\\\$f23" } } */
>+/* { dg-final { scan-assembler-not "\\\$f25" } } */
>+/* { dg-final { scan-assembler-not "\\\$f27" } } */
>+/* { dg-final { scan-assembler-not "\\\$f29" } } */
>+/* { dg-final { scan-assembler-not "\\\$f31" } } */
>Index: gcc/testsuite/gcc.target/mips/oddspreg-4.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-4.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-4.c (revision 0)
>@@ -0,0 +1,15 @@
>+/* Check that we disable odd-numbered single precision registers and can
>+   still generate code.  */
>+/* { dg-options "-mabi=32 -mno-odd-spreg -mhard-float" } */
>+
>+#if _MIPS_SPFPSET != 16
>+#error "Incorrect number of single-precision registers reported"
>+#endif
>+
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  return b;
>+}
>Index: gcc/testsuite/gcc.target/mips/call-clobbered-1.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-clobbered-1.c   (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-clobbered-1.c   (revision 0)
>@@ -0,0 +1,21 @@
>+/* Check that we handle call-clobbered FPRs correctly.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "isa>=2 -mabi=32 -ffixed-f0 -ffixed-f1 -ffixed-f2 -ffixed-f3 
>-ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 -ffixed-f10 
>-ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 -ffixed-f16 
>-ffixed-f17 -ffixed-f18 -ffixed-f19" } */
>+
>+void bar (void);
>+double a;
>+double
>+foo ()
>+{
>+  double b = a + 1.0;
>+  bar();
>+  return b;
>+}
>+/* { dg-final { scan-assembler-not "lwc1" } } */
>+/* { dg-final { scan-assembler-not "swc1" } } */
>+/* { dg-final { scan-assembler-times "sdc1" 2 } } */
>+/* { dg-final { scan-assembler-times "ldc1" 4 } } */
>+/* { dg-final { scan-assembler-not "mtc" } } */
>+/* { dg-final { scan-assembler-not "mfc" } } */
>+/* { dg-final { scan-assembler-not "mthc" } } */
>+/* { dg-final { scan-assembler-not "mfhc" } } */
>Index: gcc/testsuite/gcc.target/mips/oddspreg-5.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-5.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-5.c (revision 0)
>@@ -0,0 +1,11 @@
>+/* Check that -mno-odd-spreg is not supported with -mabi=64.  */
>+/* { dg-options "-mabi=64 -mno-odd-spreg -mhard-float" } */
>+/* { dg-error "unsupported combination" "" { target *-*-* } 0 } */
>+
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  return b;
>+}
>Index: gcc/testsuite/gcc.target/mips/call-clobbered-2.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-clobbered-2.c   (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-clobbered-2.c   (revision 0)
>@@ -0,0 +1,21 @@
>+/* Check that we handle call-clobbered FPRs correctly.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* { dg-options "-mabi=32 -modd-spreg -mfp32 -ffixed-f0 -ffixed-f1 -ffixed-f2 
>-ffixed-f3 -ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 
>-ffixed-f10 -ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 
>-ffixed-f16 -ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 
>-ffixed-f24 -ffixed-f26 -ffixed-f28 -ffixed-f30" } */
>+
>+void bar (void);
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  bar();
>+  return b;
>+}
>+/* { dg-final { scan-assembler-times "lwc1" 4 } } */
>+/* { dg-final { scan-assembler-times "swc1" 2 } } */
>+/* { dg-final { scan-assembler-not "mtc" } } */
>+/* { dg-final { scan-assembler-not "mfc" } } */
>+/* { dg-final { scan-assembler-not "mthc" } } */
>+/* { dg-final { scan-assembler-not "mfhc" } } */
>+/* { dg-final { scan-assembler-not "sdc1" } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>Index: gcc/testsuite/gcc.target/mips/oddspreg-6.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/oddspreg-6.c (revision 0)
>+++ gcc/testsuite/gcc.target/mips/oddspreg-6.c (revision 0)
>@@ -0,0 +1,10 @@
>+/* Check that we disable odd-numbered single precision registers for FPXX.  */
>+/* { dg-skip-if "needs asm output" { *-*-* } { "-fno-fat-lto-objects" } { "" 
>} } */
>+/* { dg-options "-mabi=32 -mfpxx -mhard-float" } */
>+
>+void
>+foo ()
>+{
>+  register float foo asm ("$f1"); /* { dg-error "isn't suitable for" } */
>+  asm volatile ("" : "=f" (foo));
>+}
>Index: gcc/testsuite/gcc.target/mips/args-1.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/args-1.c     (revision 216257)
>+++ gcc/testsuite/gcc.target/mips/args-1.c     (working copy)
>@@ -5,7 +5,7 @@
> const char *compiled_for = _MIPS_ARCH;
> const char *optimized_for = _MIPS_TUNE;
> 
>-#if __mips_fpr != 32 && __mips_fpr != 64
>+#if __mips_fpr != 32 && __mips_fpr != 64 && __mips_fpr != 0
> #error Bad __mips_fpr
> #endif
> 
>Index: gcc/testsuite/gcc.target/mips/call-clobbered-3.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-clobbered-3.c   (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-clobbered-3.c   (revision 0)
>@@ -0,0 +1,23 @@
>+/* Check that we handle call-clobbered FPRs correctly.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
>+/* Refer to call-clobbered-4.c to see the expected output from -Os builds.  */
>+/* { dg-skip-if "uses callee-saved GPR" { *-*-* } { "-Os" } { "" } } */
>+/* { dg-options "-mabi=32 -modd-spreg -mfpxx -ffixed-f0 -ffixed-f1 -ffixed-f2 
>-ffixed-f3 -ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 
>-ffixed-f10 -ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 
>-ffixed-f16 -ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 
>-ffixed-f24 -ffixed-f26 -ffixed-f28 -ffixed-f30" } */
>+
>+void bar (void);
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  bar();
>+  return b;
>+}
>+/* { dg-final { scan-assembler-times "lwc1" 5 } } */
>+/* { dg-final { scan-assembler-times "swc1" 3 } } */
>+/* { dg-final { scan-assembler-not "mtc" } } */
>+/* { dg-final { scan-assembler-not "mfc" } } */
>+/* { dg-final { scan-assembler-not "mthc" } } */
>+/* { dg-final { scan-assembler-not "mfhc" } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>+/* { dg-final { scan-assembler-not "sdc1" } } */
>Index: gcc/testsuite/gcc.target/mips/call-clobbered-4.c
>===================================================================
>--- gcc/testsuite/gcc.target/mips/call-clobbered-4.c   (revision 0)
>+++ gcc/testsuite/gcc.target/mips/call-clobbered-4.c   (revision 0)
>@@ -0,0 +1,23 @@
>+/* Check that we handle call-clobbered FPRs correctly.
>+   This test differs from call-clobbered-3.c because when optimising for size
>+   a callee-saved GPR is used for 'b' to cross the call.  */
>+/* { dg-skip-if "code quality test" { *-*-* } { "*" } { "-Os" } } */
>+/* { dg-options "-mabi=32 -modd-spreg -mfpxx -ffixed-f0 -ffixed-f1 -ffixed-f2 
>-ffixed-f3 -ffixed-f4 -ffixed-f5 -ffixed-f6 -ffixed-f7 -ffixed-f8 -ffixed-f9 
>-ffixed-f10 -ffixed-f11 -ffixed-f12 -ffixed-f13 -ffixed-f14 -ffixed-f15 
>-ffixed-f16 -ffixed-f17 -ffixed-f18 -ffixed-f19 -ffixed-f20 -ffixed-f22 
>-ffixed-f24 -ffixed-f26 -ffixed-f28 -ffixed-f30" } */
>+
>+void bar (void);
>+float a;
>+float
>+foo ()
>+{
>+  float b = a + 1.0f;
>+  bar();
>+  return b;
>+}
>+/* { dg-final { scan-assembler-times "lwc1" 4 } } */
>+/* { dg-final { scan-assembler-times "swc1" 2 } } */
>+/* { dg-final { scan-assembler-times "mtc" 1 } } */
>+/* { dg-final { scan-assembler-times "mfc" 1 } } */
>+/* { dg-final { scan-assembler-not "mthc" } } */
>+/* { dg-final { scan-assembler-not "mfhc" } } */
>+/* { dg-final { scan-assembler-not "ldc1" } } */
>+/* { dg-final { scan-assembler-not "sdc1" } } */
>Index: gcc/config.in
>===================================================================
>--- gcc/config.in      (revision 216257)
>+++ gcc/config.in      (working copy)
>@@ -472,6 +472,12 @@
> #endif
> 
> 
>+/* Define if the assembler understands .module. */
>+#ifndef USED_FOR_TARGET
>+#undef HAVE_AS_MODULE
>+#endif
>+
>+

Use HAVE_AS_DOT_MODULE, please.

> /* 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/common/config/mips/mips-common.c
>===================================================================
>--- gcc/common/config/mips/mips-common.c       (revision 216257)
>+++ gcc/common/config/mips/mips-common.c       (working copy)
>@@ -42,6 +42,15 @@ mips_handle_option (struct gcc_options *opts,
>       opts->x_mips_cache_flush_func = NULL;
>       return true;
> 
>+    case OPT_mfp32:
>+    case OPT_mfp64:
>+      opts->x_target_flags &= ~MASK_FLOATXX;
>+      return true;
>+
>+    case OPT_mfpxx:
>+      opts->x_target_flags &= ~MASK_FLOAT64;
>+      return true;
>+
>     default:
>       return true;
>     }
>Index: gcc/configure.ac
>===================================================================
>--- gcc/configure.ac   (revision 216257)
>+++ gcc/configure.ac   (working copy)
>@@ -4236,6 +4236,17 @@ LCF0:
>       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
>         [Define if your assembler supports .gnu_attribute.])])
> 
>+    gcc_GAS_CHECK_FEATURE([.module support],
>+      gcc_cv_as_mips_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_MSG_ERROR(
>+      [Requesting --with-fp= requires assembler support for .module.])
>+    fi
>+
>     gcc_GAS_CHECK_FEATURE([.micromips support],
>       gcc_cv_as_micromips_support,,[--fatal-warnings],
>       [.set micromips],,
>Index: gcc/config.gcc
>===================================================================
>--- gcc/config.gcc     (revision 216257)
>+++ gcc/config.gcc     (working copy)
>@@ -3738,7 +3760,7 @@ case "${target}" in
>               ;;
> 
>       mips*-*-*)
>-              supported_defaults="abi arch arch_32 arch_64 float fpu nan tune 
>tune_32 tune_64 divide llsc mips-plt synci"
>+              supported_defaults="abi arch arch_32 arch_64 float fpu nan 
>fp_32 odd_spreg_32 tune tune_32 tune_64 divide llsc mips-plt synci"
> 
>               case ${with_float} in
>               "" | soft | hard)
>@@ -3770,6 +3792,32 @@ case "${target}" in
>                       ;;
>               esac
> 
>+              case ${with_fp_32} in
>+              "" | 32 | xx | 64)
>+                      # OK
>+                      ;;
>+              *)
>+                      echo "Unknown FP mode used in --with-fp-32=$with_fp_32" 
>1>&2
>+                      exit 1
>+                      ;;
>+              esac
>+
>+              case ${with_odd_spreg_32} in
>+              yes)
>+                      with_odd_spreg_32="odd-spreg"
>+                      ;;
>+              no)
>+                      with_odd_spreg_32="no-odd-spreg"
>+                      ;;
>+              "")
>+                      # OK
>+                      ;;
>+              *)
>+                      echo "Unknown odd-spreg-32 type used in 
>--with-odd-spreg-32=$with_odd_spreg_32" 1>&2
>+                      exit 1
>+                      ;;
>+              esac
>+
>               case ${with_abi} in
>               "" | 32 | o64 | n32 | 64 | eabi)
>                       # OK
>@@ -4174,7 +4222,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 nan 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 mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls"
> for option in $all_defaults
> do
>       eval "val=\$with_"`echo $option | sed s/-/_/g`
>Index: gcc/config/mips/mti-linux.h
>===================================================================
>--- gcc/config/mips/mti-linux.h        (revision 216257)
>+++ gcc/config/mips/mti-linux.h        (working copy)
>@@ -39,6 +39,9 @@ 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}}}",               
>\
>+                                                                      \
>   /* Base SPECs.  */                                                  \
>   BASE_DRIVER_SELF_SPECS                                              \
>                                                                       \
>Index: gcc/config/mips/mips.md
>===================================================================
>--- gcc/config/mips/mips.md    (revision 216257)
>+++ gcc/config/mips/mips.md    (working copy)
>@@ -432,12 +432,22 @@
>   (const_string "none"))
> 
> (define_attr "enabled" "no,yes"
>-  (if_then_else (ior (eq_attr "compression" "all,none")
>-                   (and (eq_attr "compression" "micromips")
>-                        (match_test "TARGET_MICROMIPS")))
>-              (const_string "yes")
>-              (const_string "no")))
>+  (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)")
>+            (eq_attr "dword_mode" "yes"))
>+       (const_string "no")
> 

        Use TARGET_O32_FP64A_ABI

>+       ;; The micromips compressed instruction alternatives should only be
>+       ;; considered when targetting micromips.
        
                s/targetting/targeting or get rid of the comment altogether.

>+       (and (eq_attr "compression" "micromips")
>+            (match_test "!TARGET_MICROMIPS"))
>+       (const_string "no")]
>+      (const_string "yes")))
>+
> ;; The number of individual instructions that a non-branch pattern generates,
> ;; using units of BASE_INSN_LENGTH.
> (define_attr "insn_count" ""
>@@ -4996,7 +5006,7 @@
>       rtx low = mips_subword (operands[1], 0);
>       rtx high = mips_subword (operands[1], 1);
>       emit_insn (gen_load_low<mode> (operands[0], low));
>-      if (TARGET_FLOAT64 && !TARGET_64BIT)
>+      if (ISA_HAS_MXHC1 && !TARGET_64BIT)
>               emit_insn (gen_mthc1<mode> (operands[0], high, operands[0]));
>       else
>       emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
>@@ -5006,7 +5016,7 @@
>       rtx low = mips_subword (operands[0], 0);
>       rtx high = mips_subword (operands[0], 1);
>       emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
>-      if (TARGET_FLOAT64 && !TARGET_64BIT)
>+      if (ISA_HAS_MXHC1 && !TARGET_64BIT)
>       emit_insn (gen_mfhc1<mode> (high, operands[1]));
>       else
>       emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
>Index: gcc/config/mips/mips.opt
>===================================================================
>--- gcc/config/mips/mips.opt   (revision 216257)
>+++ gcc/config/mips/mips.opt   (working copy)
>@@ -197,6 +197,10 @@ mfp32
> Target Report RejectNegative InverseMask(FLOAT64)
> Use 32-bit floating-point registers
> 
>+mfpxx
>+Target Report RejectNegative Mask(FLOATXX)
>+Follow the O32 FPXX ABI

  Conform to the O32 FPXX ABI.

  Should it be o32 or O32?  Usage is inconsistent throughout the patch.
>+
> mfp64
> Target Report RejectNegative Mask(FLOAT64)
> Use 64-bit floating-point registers
>@@ -408,5 +412,9 @@ mxgot
> Target Report Var(TARGET_XGOT)
> Lift restrictions on GOT size
> 
>+modd-spreg
>+Target Report Mask(ODD_SPREG)
>+Enable use of odd-numbered single-precision registers
>+
> noasmopt
> Driver
>Index: gcc/config/mips/mips-protos.h
>===================================================================
>--- gcc/config/mips/mips-protos.h      (revision 216257)
>+++ gcc/config/mips/mips-protos.h      (working copy)
>@@ -278,6 +278,8 @@ extern void mips_expand_before_return (void);
> extern void mips_expand_epilogue (bool);
> extern bool mips_can_use_return_insn (void);
> 
>+extern bool mips_secondary_memory_needed (enum reg_class, enum reg_class,
>+                                        enum machine_mode);
> extern bool mips_cannot_change_mode_class (enum machine_mode,
>                                          enum machine_mode, enum reg_class);
> extern bool mips_dangerous_for_la25_p (rtx);
>@@ -286,6 +288,9 @@ extern enum reg_class mips_secondary_reload_class
>                                                  enum machine_mode,
>                                                  rtx, bool);
> extern int mips_class_max_nregs (enum reg_class, enum machine_mode);
>+extern enum machine_mode mips_hard_regno_caller_save_mode (unsigned int,
>+                                                           unsigned int,
>+                                                           enum machine_mode);
> 
> extern int mips_adjust_insn_length (rtx_insn *, int);
> extern void mips_output_load_label (rtx);
>Index: gcc/config/mips/mti-elf.h
>===================================================================
>--- gcc/config/mips/mti-elf.h  (revision 216257)
>+++ gcc/config/mips/mti-elf.h  (working copy)
>@@ -34,6 +34,9 @@ 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}}}",               
>\
>+                                                                      \
>   /* Make sure that an endian option is always present.  This makes   \
>      things like LINK_SPEC easier to write.  */                               
> \
>   "%{!EB:%{!EL:%(endian_spec)}}",                                     \
>Index: gcc/config/mips/mips.c
>===================================================================
>--- gcc/config/mips/mips.c     (revision 216257)
>+++ gcc/config/mips/mips.c     (working copy)
>@@ -1201,6 +1201,7 @@ static rtx mips_find_pic_call_symbol (rtx_insn *,
> static int mips_register_move_cost (enum machine_mode, reg_class_t,
>                                   reg_class_t);
> static unsigned int mips_function_arg_boundary (enum machine_mode, 
> const_tree);
>+static enum machine_mode mips_get_reg_raw_mode (int regno);
> 
> struct mips16_flip_traits : default_hashmap_traits
> {
>@@ -5125,6 +5126,7 @@ mips_get_arg_info (struct mips_arg_info *info, con
>       /* Only leading floating-point scalars are passed in
>        floating-point registers.  We also handle vector floats the same
>        say, which is OK because they are not covered by the standard ABI.  */
>+      gcc_assert (TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode);
>       info->fpr_p = (!cum->gp_reg_found
>                    && cum->arg_number < 2
>                    && (type == 0
>@@ -5140,6 +5142,7 @@ mips_get_arg_info (struct mips_arg_info *info, con
>       /* Scalar, complex and vector floating-point types are passed in
>        floating-point registers, as long as this is a named rather
>        than a variable argument.  */
>+      gcc_assert (TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode);
>       info->fpr_p = (named
>                    && (type == 0 || FLOAT_TYPE_P (type))
>                    && (GET_MODE_CLASS (mode) == MODE_FLOAT
>@@ -5423,6 +5426,16 @@ mips_function_arg_boundary (enum machine_mode mode
>   return alignment;
> }
> 
>+/* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE.  */
>+
>+static enum machine_mode
>+mips_get_reg_raw_mode (int regno)
>+{
>+  if (mips_abi == ABI_32 && !TARGET_FLOAT32 && FP_REG_P (regno))
>+    return DFmode;
>+  return default_get_reg_raw_mode (regno);
>+}
>+
> /* Return true if FUNCTION_ARG_PADDING (MODE, TYPE) should return
>    upward rather than downward.  In other words, return true if the
>    first byte of the stack slot has useful data, false if the last
>@@ -5580,6 +5593,7 @@ mips_return_in_msb (const_tree valtype)
> static bool
> mips_return_mode_in_fpr_p (enum machine_mode mode)
> {
>+  gcc_assert (TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode);
>   return ((GET_MODE_CLASS (mode) == MODE_FLOAT
>          || mode == V2SFmode
>          || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
>@@ -5626,7 +5640,7 @@ mips_return_fpr_pair (enum machine_mode mode,
> {
>   int inc;
> 
>-  inc = (TARGET_NEWABI ? 2 : MAX_FPRS_PER_FMT);
>+  inc = (TARGET_NEWABI || mips_abi == ABI_32 ? 2 : MAX_FPRS_PER_FMT);
>   return gen_rtx_PARALLEL
>     (mode,
>      gen_rtvec (2,
>@@ -5742,19 +5756,26 @@ mips_libcall_value (enum machine_mode mode, const_
> 
> /* Implement TARGET_FUNCTION_VALUE_REGNO_P.
> 
>-   On the MIPS, R2 R3 and F0 F2 are the only register thus used.
>-   Currently, R2 and F0 are only implemented here (C has no complex type).  */
>+   On the MIPS, R2 R3 and F0 F2 are the only register thus used.  */
> 
> static bool
> mips_function_value_regno_p (const unsigned int regno)
> {
>   if (regno == GP_RETURN
>       || regno == FP_RETURN
>+      || regno == FP_RETURN + 2
>       || (LONG_DOUBLE_TYPE_SIZE == 128
>         && FP_RETURN != GP_RETURN
>         && regno == FP_RETURN + 2))
>     return true;
> 
  Is this right? I'm  not following the intent of this modification.  

>+  if ((regno == FP_RETURN + 1
>+      || regno == FP_RETURN + 3)
>+      && FP_RETURN != GP_RETURN
>+      && (mips_abi == ABI_32 && TARGET_FLOAT32)
>+      && FP_REG_P (regno))
>+    return true;
>+
>   return false;
> }
> 
>@@ -6462,7 +6483,10 @@ mips16_call_stub_mode_suffix (enum machine_mode mo
>   else if (mode == DCmode)
>     return "dc";
>   else if (mode == V2SFmode)
>-    return "df";
>+    {
>+      gcc_assert (TARGET_PAIRED_SINGLE_FLOAT);
>+      return "df";
>+    }
>   else
>     gcc_unreachable ();
> }
>@@ -6486,13 +6510,27 @@ mips_output_64bit_xfer (char direction, unsigned i
>   if (TARGET_64BIT)
>     fprintf (asm_out_file, "\tdm%cc1\t%s,%s\n", direction,
>            reg_names[gpreg], reg_names[fpreg]);
>-  else if (TARGET_FLOAT64)
>+  else if (ISA_HAS_MXHC1)
>     {
>       fprintf (asm_out_file, "\tm%cc1\t%s,%s\n", direction,
>              reg_names[gpreg + TARGET_BIG_ENDIAN], reg_names[fpreg]);
>       fprintf (asm_out_file, "\tm%chc1\t%s,%s\n", direction,
>              reg_names[gpreg + TARGET_LITTLE_ENDIAN], reg_names[fpreg]);
>     }
>+  else if (TARGET_FLOATXX && direction == 't')
>+    {
>+      /* Use the argument save area to move via memory.  */
>+      fprintf (asm_out_file, "\tsw\t%s,0($sp)\n", reg_names[gpreg]);
>+      fprintf (asm_out_file, "\tsw\t%s,4($sp)\n", reg_names[gpreg + 1]);
>+      fprintf (asm_out_file, "\tldc1\t%s,0($sp)\n", reg_names[fpreg]);
>+    }
>+  else if (TARGET_FLOATXX && direction == 'f')
>+    {
>+      /* Use the argument save area to move via memory.  */
>+      fprintf (asm_out_file, "\tsdc1\t%s,0($sp)\n", reg_names[fpreg]);
>+      fprintf (asm_out_file, "\tlw\t%s,0($sp)\n", reg_names[gpreg]);
>+      fprintf (asm_out_file, "\tlw\t%s,4($sp)\n", reg_names[gpreg + 1]);
>+    }
>   else
>     {
>       /* Move the least-significant word.  */
>@@ -6900,11 +6938,11 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, r
>           case SCmode:
>             mips_output_32bit_xfer ('f', GP_RETURN + TARGET_BIG_ENDIAN,
>                                     TARGET_BIG_ENDIAN
>-                                    ? FP_REG_FIRST + MAX_FPRS_PER_FMT
>+                                    ? FP_REG_FIRST + 2
>                                     : FP_REG_FIRST);
>             mips_output_32bit_xfer ('f', GP_RETURN + TARGET_LITTLE_ENDIAN,
>                                     TARGET_LITTLE_ENDIAN
>-                                    ? FP_REG_FIRST + MAX_FPRS_PER_FMT
>+                                    ? FP_REG_FIRST + 2
>                                     : FP_REG_FIRST);
>             if (GET_MODE (retval) == SCmode && TARGET_64BIT)
>               {
>@@ -6933,10 +6971,12 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, r
> 
>           case DCmode:
>             mips_output_64bit_xfer ('f', GP_RETURN + (8 / UNITS_PER_WORD),
>-                                    FP_REG_FIRST + MAX_FPRS_PER_FMT);
>+                                    FP_REG_FIRST + 2);
>             /* Fall though.  */
>           case DFmode:
>           case V2SFmode:
>+            gcc_assert (TARGET_PAIRED_SINGLE_FLOAT
>+                        || GET_MODE (retval) != V2SFmode);
>             mips_output_64bit_xfer ('f', GP_RETURN, FP_REG_FIRST);
>             break;
> 
>@@ -8643,15 +8683,30 @@ mips_dwarf_register_span (rtx reg)
>   rtx high, low;
>   enum machine_mode mode;
> 
>-  /* By default, GCC maps increasing register numbers to increasing
>-     memory locations, but paired FPRs are always little-endian,
>-     regardless of the prevailing endianness.  */
>+  /* TARGET_FLOATXX is implemented as 32-bit floating-point registers but
>+     ensures that double precision registers are treated as if they were

                double-precision

>+     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

                s/precisely correct/precise/

>+     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_BIG_ENDIAN
>-      && MAX_FPRS_PER_FMT > 1
>+      && TARGET_FLOATXX
>       && GET_MODE_SIZE (mode) > UNITS_PER_FPREG)
>     {
>+      return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, reg));
>+    }
>+  /* By default, GCC maps increasing register numbers to increasing
>+     memory locations, but paired FPRs are always little-endian,
>+     regardless of the prevailing endianness.  */
>+  else if (FP_REG_P (REGNO (reg))
>+         && TARGET_BIG_ENDIAN
>+         && MAX_FPRS_PER_FMT > 1
>+         && GET_MODE_SIZE (mode) > UNITS_PER_FPREG)
>+    {
>       gcc_assert (GET_MODE_SIZE (mode) == UNITS_PER_HWFPVALUE);
>       high = mips_subword (reg, true);
>       low = mips_subword (reg, false);
>@@ -8661,6 +8716,19 @@ mips_dwarf_register_span (rtx reg)
>   return NULL_RTX;
> }
> 
>+/* Implement TARGET_DWARF_FRAME_REG_MODE.  */
>+
>+static enum machine_mode
>+mips_dwarf_frame_reg_mode (int regno)
>+{
>+  enum machine_mode mode = default_dwarf_frame_reg_mode (regno);
>+
>+  if (FP_REG_P (regno) && mips_abi == ABI_32 && TARGET_FLOAT64)
>+    mode = SImode;
>+
>+  return mode;
>+}
>+
> /* DSP ALU can bypass data with no delays for the following pairs. */
> enum insn_code dspalu_bypass_table[][2] =
> {
>@@ -8940,7 +9008,32 @@ 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
>+  /* Record the FP ABI.  See below for comments.  */
>+  if (TARGET_NO_FLOAT)
> #ifdef HAVE_AS_GNU_ATTRIBUTE
>+    fputs ("\t.gnu_attribute 4, 0\n", asm_out_file);
>+#else
>+    ;
>+#endif
>+  else if (!TARGET_HARD_FLOAT_ABI)
>+    fputs ("\t.module\tsoftfloat\n", asm_out_file);
>+  else if (!TARGET_DOUBLE_FLOAT)
>+    fputs ("\t.module\tsinglefloat\n", asm_out_file);
>+  else if (TARGET_FLOATXX)
>+    fputs ("\t.module\tfp=xx\n", asm_out_file);
>+  else if (TARGET_FLOAT64)
>+    fputs ("\t.module\tfp=64\n", asm_out_file);
>+  else
>+    fputs ("\t.module\tfp=32\n", asm_out_file);
>+
>+  if (TARGET_ODD_SPREG)
>+    fputs ("\t.module\toddspreg\n", asm_out_file);
>+  else
>+    fputs ("\t.module\tnooddspreg\n", asm_out_file);
>+
>+#else
>+#ifdef HAVE_AS_GNU_ATTRIBUTE
>   {
>     int attr;
> 
>@@ -8953,9 +9046,19 @@ mips_file_start (void)
>     /* Single-float code, -msingle-float.  */
>     else if (!TARGET_DOUBLE_FLOAT)
>       attr = 2;
>-    /* 64-bit FP registers on a 32-bit target, -mips32r2 -mfp64.  */
>-    else if (!TARGET_64BIT && TARGET_FLOAT64)
>-      attr = 4;
>+    /* 64-bit FP registers on a 32-bit target, -mips32r2 -mfp64.
>+       Reserved attr=4.
>+       This case used 12 callee save double precision registers

                s/callee save/callee-saved

>+       and is deprecated.  */
>+    /* 64-bit or 32-bit FP registers on a 32-bit target, -mfpxx.  */
>+    else if (TARGET_FLOATXX)
>+      attr = 5;
>+    /* 64-bit FP registers on a 32-bit target, -mfp64 -modd-spreg.  */
>+    else if (mips_abi == ABI_32 && TARGET_FLOAT64 && TARGET_ODD_SPREG)
>+      attr = 6;
>+    /* 64-bit FP registers on a 32-bit target, -mfp64 -mno-odd-spreg.  */
>+    else if (mips_abi == ABI_32 && TARGET_FLOAT64)
>+      attr = 7;
>     /* Regular FP code, FP regs same size as GP regs, -mdouble-float.  */
>     else
>       attr = 1;
>@@ -8963,6 +9066,7 @@ mips_file_start (void)
>     fprintf (asm_out_file, "\t.gnu_attribute 4, %d\n", attr);
>   }
> #endif
>+#endif
> 
>   /* If TARGET_ABICALLS, tell GAS to generate -KPIC code.  */
>   if (TARGET_ABICALLS)
>@@ -10452,7 +10556,9 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
> static void
> mips_save_reg (rtx reg, rtx mem)
> {
>-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
>+  if (GET_MODE (reg) == DFmode
>+      && (!TARGET_FLOAT64
>+        || mips_abi == ABI_32))
>     {
>       rtx x1, x2;
> 
>@@ -10610,7 +10716,16 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
>        regno -= MAX_FPRS_PER_FMT)
>     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
>       {
>-      mips_save_restore_reg (fpr_mode, regno, offset, fn);
>+      if (!TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT
>+          && (fixed_regs[regno] || fixed_regs[regno + 1]))
>+        {
>+          if (fixed_regs[regno])
>+            mips_save_restore_reg (SFmode, regno + 1, offset, fn);
>+          else
>+            mips_save_restore_reg (SFmode, regno, offset, fn);
>+        }
>+      else
>+        mips_save_restore_reg (fpr_mode, regno, offset, fn);
>       offset -= GET_MODE_SIZE (fpr_mode);
>       }
> }
>@@ -11377,7 +11492,9 @@ mips_restore_reg (rtx reg, rtx mem)
>      $7 instead and adjust the return insn appropriately.  */
>   if (TARGET_MIPS16 && REGNO (reg) == RETURN_ADDR_REGNUM)
>     reg = gen_rtx_REG (GET_MODE (reg), GP_REG_FIRST + 7);
>-  else if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
>+  else if (GET_MODE (reg) == DFmode
>+         && (!TARGET_FLOAT64
>+             || mips_abi == ABI_32))
>     {
>       mips_add_cfa_restore (mips_subword (reg, true));
>       mips_add_cfa_restore (mips_subword (reg, false));
>@@ -11727,6 +11844,12 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enu
>       && (((regno - FP_REG_FIRST) % MAX_FPRS_PER_FMT) == 0
>         || (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)
>+      return false;
>+
        Use TARGET_O32_FP64A_ABI

>       /* Allow 64-bit vector modes for Loongson-2E/2F.  */
>       if (TARGET_LOONGSON_VECTORS
>         && (mode == V2SImode
>@@ -12081,6 +12204,25 @@ mips_memory_move_cost (enum machine_mode mode, reg
>         + memory_move_secondary_cost (mode, rclass, in));
> } 
> 
>+/* Implement SECONDARY_MEMORY_NEEDED.  */
>+
>+bool
>+mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
>+                            enum machine_mode mode)
>+{
>+  /* Ignore spilled pseudos.  */
>+  if (lra_in_progress && (class1 == NO_REGS || class2 == NO_REGS))
>+    return false;
>+
>+  if (((class1 == FP_REGS) != (class2 == FP_REGS))
>+      && ((TARGET_FLOATXX && !ISA_HAS_MXHC1)
>+        || (mips_abi == ABI_32 && TARGET_FLOAT64 && !TARGET_ODD_SPREG))
>+      && GET_MODE_SIZE (mode) >= 8)
>+    return true;
>+
>+  return false;
>+}
>+
         Use TARGET_O32_FP64A_ABI

> /* Return the register class required for a secondary register when
>    copying between one of the registers in RCLASS and value X, which
>    has mode MODE.  X is the source of the move if IN_P, otherwise it
>@@ -17012,6 +17154,13 @@ mips_option_override (void)
>       target_flags &= ~MASK_FLOAT64;
>     }
> 
>+  if (mips_abi != ABI_32 && TARGET_FLOATXX)
>+    error ("%<-mfpxx%> can only be used with the o32 ABI");
>+  else if (ISA_MIPS1 && !TARGET_FLOAT32)
>+    error ("%<-march=%s%> requires %<-mfp32%>", mips_arch_info->name);
>+  else if (TARGET_FLOATXX && !mips_lra_flag)
>+    error ("%<-mfpxx%> requires %<-mlra%>");
>+
>   /* End of code shared with GAS.  */
> 
>   /* The R5900 FPU only supports single precision.  */
>@@ -17099,6 +17248,26 @@ mips_option_override (void)
>     warning (0, "the %qs architecture does not support madd or msub"
>            " instructions", mips_arch_info->name);
> 
>+  /* If neither -modd-spreg nor -mno-odd-spreg was given on the command
>+     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.  */
>+      if (!ISA_HAS_ODD_SPREG || TARGET_FLOATXX)
>+      target_flags &= ~MASK_ODD_SPREG;
>+      else
>+      target_flags |= MASK_ODD_SPREG;
>+    }
>+  else if (TARGET_ODD_SPREG && !ISA_HAS_ODD_SPREG)
>+    warning (0, "the %qs architecture does not support odd single-precision"
>+           " registers", mips_arch_info->name);
>+
>+  if (!TARGET_ODD_SPREG && TARGET_64BIT)
>+    {
>+      error ("unsupported combination: %s", "-mgp64 -mno-odd-spreg");
>+      target_flags |= MASK_ODD_SPREG;
>+    }
>+

     Is there any reason to error here and then silently set the combination 
that you are looking for?
     I would either set ODD_SPREG or error, not both.


>   /* The effect of -mabicalls isn't defined for the EABI.  */
>   if (mips_abi == ABI_EABI && TARGET_ABICALLS)
>     {
>@@ -17461,8 +17630,10 @@ mips_conditional_register_usage (void)
>       call_really_used_regs[regno] = call_used_regs[regno] = 1;
>     }
>   /* Odd registers in the range $f21-$f31 (inclusive) are call-clobbered
>-     for n32.  */
>-  if (mips_abi == ABI_N32)
>+     for n32 and o32 FP64.  */
>+  if (mips_abi == ABI_N32
>+      || (mips_abi == ABI_32
>+          && TARGET_FLOAT64))
>     {
>       int regno;
>       for (regno = FP_REG_FIRST + 21; regno <= FP_REG_FIRST + 31; regno+=2)
>@@ -18801,6 +18972,21 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx o
>   emit_insn (gen_rtx_SET (VOIDmode, target, x));
> }
> 
>+/* Implement HARD_REGNO_CALLER_SAVE_MODE.  */
>+
>+enum machine_mode
>+mips_hard_regno_caller_save_mode (unsigned int regno,
>+                                unsigned int nregs,
>+                                enum machine_mode mode)
>+{
>+  /* For performance, to avoid saving/restoring upper parts of a register,
>+     we return MODE as save mode when MODE is not VOIDmode.  */
>+  if (mode == VOIDmode)
>+    return choose_hard_reg_mode (regno, nregs, false);
>+  else
>+    return mode;
>+}
>+
> /* Implement TARGET_CASE_VALUES_THRESHOLD.  */
> 
> unsigned int
>@@ -19020,6 +19206,10 @@ mips_lra_p (void)
> #define TARGET_FUNCTION_ARG_ADVANCE mips_function_arg_advance
> #undef TARGET_FUNCTION_ARG_BOUNDARY
> #define TARGET_FUNCTION_ARG_BOUNDARY mips_function_arg_boundary
>+#undef TARGET_GET_RAW_RESULT_MODE
>+#define TARGET_GET_RAW_RESULT_MODE mips_get_reg_raw_mode
>+#undef TARGET_GET_RAW_ARG_MODE
>+#define TARGET_GET_RAW_ARG_MODE mips_get_reg_raw_mode
> 
> #undef TARGET_MODE_REP_EXTENDED
> #define TARGET_MODE_REP_EXTENDED mips_mode_rep_extended
>@@ -19076,6 +19266,8 @@ mips_lra_p (void)
> #endif
> #undef TARGET_DWARF_REGISTER_SPAN
> #define TARGET_DWARF_REGISTER_SPAN mips_dwarf_register_span
>+#undef TARGET_DWARF_FRAME_REG_MODE
>+#define TARGET_DWARF_FRAME_REG_MODE mips_dwarf_frame_reg_mode
> 
> #undef TARGET_ASM_FINAL_POSTSCAN_INSN
> #define TARGET_ASM_FINAL_POSTSCAN_INSN mips_final_postscan_insn
>Index: gcc/config/mips/mips.h
>===================================================================
>--- gcc/config/mips/mips.h     (revision 216257)
>+++ gcc/config/mips/mips.h     (working copy)
>@@ -320,6 +320,10 @@ struct mips_cpu_info {
> #define TARGET_HARD_FLOAT (TARGET_HARD_FLOAT_ABI && !TARGET_MIPS16)
> #define TARGET_SOFT_FLOAT (TARGET_SOFT_FLOAT_ABI || TARGET_MIPS16)
> 
   Add a macro:

#define TARGET_O32_FP64A_ABI (mips_abi == ABI32         \
                              && TARGET_FLOAT64         \
                              && !TARGET_ODD_SPREG)

>+/* TARGET_FLOAT64 represents -mfp64 and TARGET_FLOATXX represents
>+   -mfpxx, derive TARGET_FLOAT32 to represent -mfp32.  */
>+#define TARGET_FLOAT32 (!TARGET_FLOAT64 && !TARGET_FLOATXX)
>+
> /* 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
>@@ -388,6 +392,8 @@ struct mips_cpu_info {
>                                                                       \
>       if (TARGET_FLOAT64)                                             \
>       builtin_define ("__mips_fpr=64");                               \
>+      else if (TARGET_FLOATXX)                                                
>\
>+      builtin_define ("__mips_fpr=0");                                \
>       else                                                            \
>       builtin_define ("__mips_fpr=32");                               \
>                                                                       \
>@@ -516,6 +522,8 @@ struct mips_cpu_info {
>       builtin_define_with_int_value ("_MIPS_SZPTR", POINTER_SIZE);    \
>       builtin_define_with_int_value ("_MIPS_FPSET",                   \
>                                    32 / MAX_FPRS_PER_FMT);            \
>+      builtin_define_with_int_value ("_MIPS_SPFPSET",                 \
>+                                   TARGET_ODD_SPREG ? 32 : 16);       \
>                                                                       \
>       /* These defines reflect the ABI in use, not whether the        \
>        FPU is directly accessible.  */                                \
>@@ -751,6 +759,12 @@ struct mips_cpu_info {
> #define MIPS_32BIT_OPTION_SPEC \
>   "mips1|mips2|mips32*|mgp32"
> 
>+/* A spec condition that matches architectures should be targetted with

        targetted -> targeted

>+   O32 FPXX for compatibility reasons.  */
>+#define MIPS_FPXX_OPTION_SPEC \
>+  "mips2|mips3|mips4|mips5|mips32|mips32r2|mips32r3|mips32r5| \
>+   mips64|mips64r2|mips64r3|mips64r5"
>+
> /* Infer a -msynci setting from a -mips argument, on the assumption that
>    -msynci is desired where possible.  */
> #define MIPS_ISA_SYNCI_SPEC \
>@@ -776,6 +790,8 @@ struct mips_cpu_info {
>    --with-float is ignored if -mhard-float or -msoft-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-divide is ignored if -mdivide-traps or -mdivide-breaks are
>      specified. */
> #define OPTION_DEFAULT_SPECS \
>@@ -789,6 +805,8 @@ struct mips_cpu_info {
>   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
>   {"fpu", "%{!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)}}}" }, \
>   {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
>   {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }, \
>   {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }, \
>@@ -840,6 +858,12 @@ struct mips_cpu_info {
>    been generated up to this point.  */
> #define ISA_HAS_BRANCHLIKELY  (!ISA_MIPS1)
> 
>+/* ISA has 32 single-precision registers.  */
>+#define ISA_HAS_ODD_SPREG     ((mips_isa_rev >= 1                     \
>+                                && !TARGET_LOONGSON_3A)               \
>+                               || TARGET_FLOAT64                      \
>+                               || TARGET_MIPS5900)
>+
> /* ISA has a three-operand multiplication instruction (usually spelt "mul").  
> */
> #define ISA_HAS_MUL3          ((TARGET_MIPS3900                       \
>                                 || TARGET_MIPS5400                    \
>@@ -1027,7 +1051,8 @@ struct mips_cpu_info {
> #define ISA_HAS_EXT_INS               (mips_isa_rev >= 2 && !TARGET_MIPS16)
> 
> /* ISA has instructions for accessing top part of 64-bit fp regs.  */
>-#define ISA_HAS_MXHC1         (TARGET_FLOAT64 && mips_isa_rev >= 2)
>+#define ISA_HAS_MXHC1         (!TARGET_FLOAT32        \
>+                               && mips_isa_rev >= 2)
> 
> /* ISA has lwxs instruction (load w/scaled index address.  */
> #define ISA_HAS_LWXS          ((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
>@@ -1183,7 +1208,8 @@ struct mips_cpu_info {
> %(subtarget_asm_debugging_spec) \
> %{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
> %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \
>-%{mfp32} %{mfp64} %{mnan=*} \
>+%{mfp32} %{mfpxx} %{mfp64} %{mnan=*} \
>+%{modd-spreg} %{mno-odd-spreg} \
> %{mshared} %{mno-shared} \
> %{msym32} %{mno-sym32} \
> %{mtune=*} \
>@@ -1355,7 +1381,7 @@ struct mips_cpu_info {
> /* The number of consecutive floating-point registers needed to store the
>    smallest format supported by the FPU.  */
> #define MIN_FPRS_PER_FMT \
>-  (mips_isa_rev >= 1 ? 1 : MAX_FPRS_PER_FMT)
>+  (TARGET_ODD_SPREG ? 1 : MAX_FPRS_PER_FMT)
> 
> /* The largest size of value that can be held in floating-point
>    registers and moved with a single instruction.  */
>@@ -1761,6 +1787,16 @@ struct mips_cpu_info {
> #define HARD_REGNO_MODE_OK(REGNO, MODE)                                       
> \
>   mips_hard_regno_mode_ok[ (int)(MODE) ][ (REGNO) ]
> 
>+/* Select a register mode required for caller save of hard regno REGNO.  */
>+#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

        "call saved" -> call-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))
>+
> #define MODES_TIEABLE_P mips_modes_tieable_p
> 
> /* Register to use for pushing function arguments.  */
>@@ -2094,6 +2130,22 @@ 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.

  /* 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))
>+
> /* Return the maximum number of consecutive registers
>    needed to represent mode MODE in a register of class CLASS.  */
> 
>@@ -2215,12 +2267,16 @@ enum reg_class
>   (TARGET_MIPS16 ? GP_ARG_FIRST + 2 : PIC_OFFSET_TABLE_REGNUM)
> 
> /* 1 if N is a possible register number for function argument passing.
>-   We have no FP argument registers when soft-float.  When FP registers
>-   are 32 bits, we can't directly reference the odd numbered ones.  */
>+   We have no FP argument registers when soft-float.  Special handling
>+   is required for O32 where only even numbered registers are used for
>+   O32-FPXX and O32-FP64.  */
> 
> #define FUNCTION_ARG_REGNO_P(N)                                       \
>   ((IN_RANGE((N), GP_ARG_FIRST, GP_ARG_LAST)                  \
>-    || (IN_RANGE((N), FP_ARG_FIRST, FP_ARG_LAST)))            \
>+    || (IN_RANGE((N), FP_ARG_FIRST, FP_ARG_LAST)              \
>+        && (mips_abi != ABI_32                                        \
>+            || TARGET_FLOAT32                                         \
>+            || ((N) % 2 == 0))))                              \
>    && !fixed_regs[N])
> 
> /* This structure has to cope with two different argument allocation

Reply via email to