>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
> . */
>
>+#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
> # | |
> # -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 (operands[0], low));
>- if (TARGET_FLOAT64 && !TARGET_64BIT)
>+ if (ISA_HAS_MXHC1 && !TARGET_64BIT)
> emit_insn (gen_mthc1 (operands[0], high, operands[0]));
> else
> emit_insn (gen_load_high (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 (low, operands[1], const0_rtx));
>- if (TARGET_FLOAT64 && !TARGET_64BIT)
>+ if (ISA_HAS_MXHC1 && !TARGET_64BIT)
> emit_insn (gen_mfhc1 (high, operands[1]));
> else
> emit_insn (gen_store_word (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