>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