Implement MIPS o32 FPXX, FP64, FP64A ABI extensions.
authorMatthew Fortune <matthew.fortune@imgtec.com>
Wed, 12 Nov 2014 21:39:46 +0000 (21:39 +0000)
committerMatthew Fortune <mpf@gcc.gnu.org>
Wed, 12 Nov 2014 21:39:46 +0000 (21:39 +0000)
2014-11-12  Matthew Fortune  <matthew.fortune@imgtec.com>

gcc/
* common/config/mips/mips-common.c (mips_handle_option): Ensure
that -mfp32, -mfp64 disable -mfpxx and -mfpxx disables -mfp64.
* config.gcc (--with-fp-32): New option.
(--with-odd-spreg-32): Likewise.
* config.in (HAVE_AS_DOT_MODULE): New config define.
* config/mips/mips-protos.h
(mips_secondary_memory_needed): New prototype.
(mips_hard_regno_caller_save_mode): Likewise.
* config/mips/mips.c (mips_get_reg_raw_mode): New static prototype.
(mips_get_arg_info): Assert that V2SFmode is only handled specially
with TARGET_PAIRED_SINGLE_FLOAT.
(mips_return_mode_in_fpr_p): Likewise.
(mips16_call_stub_mode_suffix): Likewise.
(mips_get_reg_raw_mode): New static function.
(mips_return_fpr_pair): O32 return values span two registers.
(mips16_build_call_stub): Likewise.
(mips_function_value_regno_p): Support both FP return registers.
(mips_output_64bit_xfer): Use mthc1 whenever TARGET_HAS_MXHC1.  Add
specific cases for TARGET_FPXX to move via memory.
(mips_dwarf_register_span): For TARGET_FPXX pretend that modes larger
than UNITS_PER_FPREG 'span' one register.
(mips_dwarf_frame_reg_mode): New static function.
(mips_file_start): Switch to using .module instead of .gnu_attribute.
No longer support FP ABI 4 (-mips32r2 -mfp64), replace with FP ABI 6.
Add FP ABI 5 (-mfpxx) and FP ABI 7 (-mfp64 -mno-odd-spreg).
(mips_save_reg, mips_restore_reg): Always represent DFmode frame
slots with two CFI directives even for O32 FP64.
(mips_for_each_saved_gpr_and_fpr): Account for fixed_regs when
saving/restoring callee-saved registers.
(mips_hard_regno_mode_ok_p): Implement O32 FP64A extension.
(mips_secondary_memory_needed): New function.
(mips_option_override): ABI check for TARGET_FLOATXX.  Disable
odd-numbered single-precision registers when using TARGET_FLOATXX.
Implement -modd-spreg and defaults.
(mips_conditional_register_usage): Redefine O32 FP64 to match O32 FP32
callee-saved behaviour.
(mips_hard_regno_caller_save_mode): Implement.
(TARGET_GET_RAW_RESULT_MODE): Define target hook.
(TARGET_GET_RAW_ARG_MODE): Define target hook.
(TARGET_DWARF_FRAME_REG_MODE): Define target hook.
* config/mips/mips.h (TARGET_FLOAT32): New macro.
(TARGET_O32_FP64A_ABI): Likewise.
(TARGET_CPU_CPP_BUILTINS): TARGET_FPXX is __mips_fpr==0. Add
_MIPS_SPFPSET builtin define.
(MIPS_FPXX_OPTION_SPEC): New macro.
(OPTION_DEFAULT_SPECS): Pass through --with-fp-32=* to -mfp and
--with-odd-spreg-32=* to -m[no-]odd-spreg.
(ISA_HAS_ODD_SPREG): New macro.
(ISA_HAS_MXHC1): True for anything other than -mfp32.
(ASM_SPEC): Pass through mfpxx, mfp64, -mno-odd-spreg and -modd-spreg.
(MIN_FPRS_PER_FMT): Redefine in terms of TARGET_ODD_SPREG.
(HARD_REGNO_CALLER_SAVE_MODE): Define.  Implement O32 FPXX extension
(HARD_REGNO_CALL_PART_CLOBBERED): Likewise.
(SECONDARY_MEMORY_NEEDED): Likewise.
(FUNCTION_ARG_REGNO_P): Update for O32 FPXX and FP64 extensions.
* config/mips/mips.md (define_attr enabled): Implement O32 FPXX and
FP64A ABI extensions.
(move_doubleword_fpr<mode>): Use ISA_HAS_MXHC1 instead of
TARGET_FLOAT64.
* config/mips/mips.opt (mfpxx): New target option.
(modd-spreg): Likewise.
* config/mips/mti-elf.h (DRIVER_SELF_SPECS): Infer FP ABI from arch.
* config/mips/mti-linux.h (DRIVER_SELF_SPECS): Likewise and remove
fp64 sysroot.
* config/mips/t-mti-elf: Remove fp64 multilib.
* config/mips/t-mti-linux: Likewise.
* configure.ac: Detect .module support.
* configure: Regenerate.
* doc/invoke.texi: Document -mfpxx, -modd-spreg, -mno-odd-spreg option.
* doc/install.texi (--with-fp-32, --with-odd-spreg-32): Document new
options.

gcc/testsuite/
* gcc.target/mips/args-1.c: Handle __mips_fpr == 0.
* gcc.target/mips/call-clobbered-1.c: New.
* gcc.target/mips/call-clobbered-2.c: New.
* gcc.target/mips/call-clobbered-3.c: New.
* gcc.target/mips/call-clobbered-4.c: New.
* gcc.target/mips/call-clobbered-5.c: New.
* gcc.target/mips/call-saved-4.c: New.
* gcc.target/mips/call-saved-5.c: New.
* gcc.target/mips/call-saved-6.c: New.
* gcc.target/mips/mips.exp: Support -mfpxx, -ffixed-f*,
and -m[no-]odd-spreg.  Use _MIPS_SPFPSET to determine default
odd-spreg option.  Account for -modd-spreg in minimum arch code.
* gcc.target/mips/movdf-1.c: New.
* gcc.target/mips/movdf-2.c: New.
* gcc.target/mips/movdf-3.c: New.
* gcc.target/mips/oddspreg-1.c: New.
* gcc.target/mips/oddspreg-2.c: New.
* gcc.target/mips/oddspreg-3.c: New.
* gcc.target/mips/oddspreg-4.c: New.
* gcc.target/mips/oddspreg-5.c: New.
* gcc.target/mips/oddspreg-6.c: New.

libgcc/
* config/mips/mips16.S: Set .module when supported.  Update O32
FP64 calling convention and use for FPXX when possible.  Add FPXX
calling convention fallback case.

From-SVN: r217446

37 files changed:
gcc/ChangeLog
gcc/common/config/mips/mips-common.c
gcc/config.gcc
gcc/config.in
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/mips.opt
gcc/config/mips/mti-elf.h
gcc/config/mips/mti-linux.h
gcc/configure
gcc/configure.ac
gcc/doc/install.texi
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/args-1.c
gcc/testsuite/gcc.target/mips/call-clobbered-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-clobbered-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-clobbered-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-clobbered-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-clobbered-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-saved-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-saved-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/call-saved-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/mips.exp
gcc/testsuite/gcc.target/mips/movdf-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/movdf-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/movdf-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/oddspreg-6.c [new file with mode: 0644]
libgcc/ChangeLog
libgcc/config/mips/mips16.S

index 1fc374b..a15bfd2 100644 (file)
@@ -1,3 +1,77 @@
+2014-11-12  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * common/config/mips/mips-common.c (mips_handle_option): Ensure
+       that -mfp32, -mfp64 disable -mfpxx and -mfpxx disables -mfp64.
+       * config.gcc (--with-fp-32): New option.
+       (--with-odd-spreg-32): Likewise.
+       * config.in (HAVE_AS_DOT_MODULE): New config define.
+       * config/mips/mips-protos.h
+       (mips_secondary_memory_needed): New prototype.
+       (mips_hard_regno_caller_save_mode): Likewise.
+       * config/mips/mips.c (mips_get_reg_raw_mode): New static prototype.
+       (mips_get_arg_info): Assert that V2SFmode is only handled specially
+       with TARGET_PAIRED_SINGLE_FLOAT.
+       (mips_return_mode_in_fpr_p): Likewise.
+       (mips16_call_stub_mode_suffix): Likewise.
+       (mips_get_reg_raw_mode): New static function.
+       (mips_return_fpr_pair): O32 return values span two registers.
+       (mips16_build_call_stub): Likewise.
+       (mips_function_value_regno_p): Support both FP return registers.
+       (mips_output_64bit_xfer): Use mthc1 whenever TARGET_HAS_MXHC1.  Add
+       specific cases for TARGET_FPXX to move via memory.
+       (mips_dwarf_register_span): For TARGET_FPXX pretend that modes larger
+       than UNITS_PER_FPREG 'span' one register.
+       (mips_dwarf_frame_reg_mode): New static function.
+       (mips_file_start): Switch to using .module instead of .gnu_attribute.
+       No longer support FP ABI 4 (-mips32r2 -mfp64), replace with FP ABI 6.
+       Add FP ABI 5 (-mfpxx) and FP ABI 7 (-mfp64 -mno-odd-spreg).
+       (mips_save_reg, mips_restore_reg): Always represent DFmode frame
+       slots with two CFI directives even for O32 FP64.
+       (mips_for_each_saved_gpr_and_fpr): Account for fixed_regs when
+       saving/restoring callee-saved registers.
+       (mips_hard_regno_mode_ok_p): Implement O32 FP64A extension.
+       (mips_secondary_memory_needed): New function.
+       (mips_option_override): ABI check for TARGET_FLOATXX.  Disable
+       odd-numbered single-precision registers when using TARGET_FLOATXX.
+       Implement -modd-spreg and defaults.
+       (mips_conditional_register_usage): Redefine O32 FP64 to match O32 FP32
+       callee-saved behaviour.
+       (mips_hard_regno_caller_save_mode): Implement.
+       (TARGET_GET_RAW_RESULT_MODE): Define target hook.
+       (TARGET_GET_RAW_ARG_MODE): Define target hook.
+       (TARGET_DWARF_FRAME_REG_MODE): Define target hook.
+       * config/mips/mips.h (TARGET_FLOAT32): New macro.
+       (TARGET_O32_FP64A_ABI): Likewise.
+       (TARGET_CPU_CPP_BUILTINS): TARGET_FPXX is __mips_fpr==0. Add
+       _MIPS_SPFPSET builtin define.
+       (MIPS_FPXX_OPTION_SPEC): New macro.
+       (OPTION_DEFAULT_SPECS): Pass through --with-fp-32=* to -mfp and
+       --with-odd-spreg-32=* to -m[no-]odd-spreg.
+       (ISA_HAS_ODD_SPREG): New macro.
+       (ISA_HAS_MXHC1): True for anything other than -mfp32.
+       (ASM_SPEC): Pass through mfpxx, mfp64, -mno-odd-spreg and -modd-spreg.
+       (MIN_FPRS_PER_FMT): Redefine in terms of TARGET_ODD_SPREG.
+       (HARD_REGNO_CALLER_SAVE_MODE): Define.  Implement O32 FPXX extension
+       (HARD_REGNO_CALL_PART_CLOBBERED): Likewise.
+       (SECONDARY_MEMORY_NEEDED): Likewise.
+       (FUNCTION_ARG_REGNO_P): Update for O32 FPXX and FP64 extensions.
+       * config/mips/mips.md (define_attr enabled): Implement O32 FPXX and
+       FP64A ABI extensions.
+       (move_doubleword_fpr<mode>): Use ISA_HAS_MXHC1 instead of
+       TARGET_FLOAT64.
+       * config/mips/mips.opt (mfpxx): New target option.
+       (modd-spreg): Likewise.
+       * config/mips/mti-elf.h (DRIVER_SELF_SPECS): Infer FP ABI from arch.
+       * config/mips/mti-linux.h (DRIVER_SELF_SPECS): Likewise and remove
+       fp64 sysroot.
+       * config/mips/t-mti-elf: Remove fp64 multilib.
+       * config/mips/t-mti-linux: Likewise.
+       * configure.ac: Detect .module support.
+       * configure: Regenerate.
+       * doc/invoke.texi: Document -mfpxx, -modd-spreg, -mno-odd-spreg option.
+       * doc/install.texi (--with-fp-32, --with-odd-spreg-32): Document new
+       options.
+
 2014-11-12  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/63815
index 7dd8d2d..a140d55 100644 (file)
@@ -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 0b223a4..0af4a1a 100644 (file)
@@ -3754,7 +3754,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)
@@ -3786,6 +3786,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
@@ -4213,7 +4239,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 8b8c556..520b5f7 100644 (file)
 #endif
 
 
+/* Define if the assembler understands .module. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_DOT_MODULE
+#endif
+
+
 /* Define if your assembler supports the -no-mul-bug-abort option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_NO_MUL_BUG_ABORT_OPTION
index db93913..adeda59 100644 (file)
@@ -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,
+                                         machine_mode);
 extern bool mips_cannot_change_mode_class (machine_mode,
                                           machine_mode, enum reg_class);
 extern bool mips_dangerous_for_la25_p (rtx);
@@ -287,6 +289,9 @@ extern enum reg_class mips_secondary_reload_class (enum reg_class,
                                                   rtx, bool);
 extern int mips_class_max_nregs (enum reg_class, machine_mode);
 
+extern machine_mode mips_hard_regno_caller_save_mode (unsigned int,
+                                                     unsigned int,
+                                                     machine_mode);
 extern int mips_adjust_insn_length (rtx_insn *, int);
 extern void mips_output_load_label (rtx);
 extern const char *mips_output_conditional_branch (rtx_insn *, rtx *,
index a09883b..02268f3 100644 (file)
@@ -1232,6 +1232,7 @@ static rtx mips_find_pic_call_symbol (rtx_insn *, rtx, bool);
 static int mips_register_move_cost (machine_mode, reg_class_t,
                                    reg_class_t);
 static unsigned int mips_function_arg_boundary (machine_mode, const_tree);
+static machine_mode mips_get_reg_raw_mode (int regno);
 \f
 struct mips16_flip_traits : default_hashmap_traits
 {
@@ -5160,6 +5161,7 @@ mips_get_arg_info (struct mips_arg_info *info, const CUMULATIVE_ARGS *cum,
       /* 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
@@ -5175,6 +5177,7 @@ mips_get_arg_info (struct mips_arg_info *info, const CUMULATIVE_ARGS *cum,
       /* 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
@@ -5458,6 +5461,16 @@ mips_function_arg_boundary (machine_mode mode, const_tree type)
   return alignment;
 }
 
+/* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE.  */
+
+static machine_mode
+mips_get_reg_raw_mode (int regno)
+{
+  if (TARGET_FLOATXX && 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
@@ -5615,6 +5628,7 @@ mips_return_in_msb (const_tree valtype)
 static bool
 mips_return_mode_in_fpr_p (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)
@@ -5661,7 +5675,7 @@ mips_return_fpr_pair (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,
@@ -5777,19 +5791,31 @@ mips_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
 
 /* 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)
 {
+  /* Most types only require one GPR or one FPR for return values but for
+     hard-float two FPRs can be used for _Complex types (for all ABIs)
+     and long doubles (for n64).  */
   if (regno == GP_RETURN
       || regno == FP_RETURN
-      || (LONG_DOUBLE_TYPE_SIZE == 128
-         && FP_RETURN != GP_RETURN
+      || (FP_RETURN != GP_RETURN
          && regno == FP_RETURN + 2))
     return true;
 
+  /* For o32 FP32, _Complex double will be returned in four 32-bit registers.
+     This does not apply to o32 FPXX as floating-point function argument and
+     return registers are described as 64-bit even though floating-point
+     registers are primarily described as 32-bit internally.
+     See: mips_get_reg_raw_mode.  */
+  if ((mips_abi == ABI_32 && TARGET_FLOAT32)
+      && FP_RETURN != GP_RETURN
+      && (regno == FP_RETURN + 1
+         || regno == FP_RETURN + 3))
+    return true;
+
   return false;
 }
 
@@ -6497,7 +6523,10 @@ mips16_call_stub_mode_suffix (machine_mode mode)
   else if (mode == DCmode)
     return "dc";
   else if (mode == V2SFmode)
-    return "df";
+    {
+      gcc_assert (TARGET_PAIRED_SINGLE_FLOAT);
+      return "df";
+    }
   else
     gcc_unreachable ();
 }
@@ -6521,13 +6550,27 @@ mips_output_64bit_xfer (char direction, unsigned int gpreg, unsigned int fpreg)
   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.  */
@@ -6935,11 +6978,11 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code)
            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)
                {
@@ -6968,10 +7011,12 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code)
 
            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;
 
@@ -8682,15 +8727,29 @@ mips_dwarf_register_span (rtx reg)
   rtx high, low;
   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
+     64-bit physical registers.  The code will run correctly with 32-bit or
+     64-bit registers which means that dwarf information cannot be precise
+     for all scenarios.  We choose to state that the 64-bit values are stored
+     in a single 64-bit 'piece'.  This slightly unusual construct can then be
+     interpreted as either a pair of registers if the registers are 32-bit or
+     a single 64-bit register depending on hardware.  */
   mode = GET_MODE (reg);
   if (FP_REG_P (REGNO (reg))
-      && TARGET_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);
@@ -8700,6 +8759,19 @@ mips_dwarf_register_span (rtx reg)
   return NULL_RTX;
 }
 
+/* Implement TARGET_DWARF_FRAME_REG_MODE.  */
+
+static machine_mode
+mips_dwarf_frame_reg_mode (int regno)
+{
+  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] =
 {
@@ -8979,6 +9051,31 @@ mips_file_start (void)
     fprintf (asm_out_file, "\t.nan\t%s\n",
             mips_nan == MIPS_IEEE_754_2008 ? "2008" : "legacy");
 
+#ifdef HAVE_AS_DOT_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;
@@ -8992,9 +9089,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-saved double-precision registers
+       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;
@@ -9002,6 +9109,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)
@@ -10491,7 +10599,9 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset, mips_save_restore_fn fn)
 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;
 
@@ -10649,7 +10759,16 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset,
        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);
       }
 }
@@ -11420,7 +11539,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));
@@ -11770,6 +11891,11 @@ mips_hard_regno_mode_ok_p (unsigned int regno, machine_mode mode)
       && (((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 (TARGET_O32_FP64A_ABI && size <= 4 && (regno & 1) != 0)
+       return false;
+
       /* Allow 64-bit vector modes for Loongson-2E/2F.  */
       if (TARGET_LOONGSON_VECTORS
          && (mode == V2SImode
@@ -12124,6 +12250,25 @@ mips_memory_move_cost (machine_mode mode, reg_class_t rclass, bool in)
          + memory_move_secondary_cost (mode, rclass, in));
 } 
 
+/* Implement SECONDARY_MEMORY_NEEDED.  */
+
+bool
+mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
+                             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)
+         || TARGET_O32_FP64A_ABI)
+      && GET_MODE_SIZE (mode) >= 8)
+    return true;
+
+  return false;
+}
+
 /* 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
@@ -17041,6 +17186,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.  */
@@ -17128,6 +17280,28 @@ 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");
+      /* Allow compilation to continue further even though invalid output
+         will be produced.  */
+      target_flags |= MASK_ODD_SPREG;
+    }
+
   /* The effect of -mabicalls isn't defined for the EABI.  */
   if (mips_abi == ABI_EABI && TARGET_ABICALLS)
     {
@@ -17490,8 +17664,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)
@@ -18824,6 +19000,21 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx op1,
   emit_insn (gen_rtx_SET (VOIDmode, target, x));
 }
 
+/* Implement HARD_REGNO_CALLER_SAVE_MODE.  */
+
+machine_mode
+mips_hard_regno_caller_save_mode (unsigned int regno,
+                                 unsigned int nregs,
+                                 machine_mode mode)
+{
+  /* For performance, avoid saving/restoring upper parts of a register
+     by returning MODE as save mode when the mode is known.  */
+  if (mode == VOIDmode)
+    return choose_hard_reg_mode (regno, nregs, false);
+  else
+    return mode;
+}
+
 /* Implement TARGET_CASE_VALUES_THRESHOLD.  */
 
 unsigned int
@@ -19043,6 +19234,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
@@ -19099,6 +19294,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 dd67f11..8a38829 100644 (file)
@@ -323,6 +323,15 @@ struct mips_cpu_info {
 #define TARGET_HARD_FLOAT (TARGET_HARD_FLOAT_ABI && !TARGET_MIPS16)
 #define TARGET_SOFT_FLOAT (TARGET_SOFT_FLOAT_ABI || TARGET_MIPS16)
 
+/* TARGET_FLOAT64 represents -mfp64 and TARGET_FLOATXX represents
+   -mfpxx, derive TARGET_FLOAT32 to represent -mfp32.  */
+#define TARGET_FLOAT32 (!TARGET_FLOAT64 && !TARGET_FLOATXX)
+
+/* TARGET_O32_FP64A_ABI represents all the conditions that form the
+   o32 FP64A ABI extension (-mabi=32 -mfp64 -mno-odd-spreg).  */
+#define TARGET_O32_FP64A_ABI (mips_abi == ABI_32 && TARGET_FLOAT64 \
+                             && !TARGET_ODD_SPREG)
+
 /* False if SC acts as a memory barrier with respect to itself,
    otherwise a SYNC will be emitted after SC for atomic operations
    that require ordering between the SC and following loads and
@@ -391,6 +400,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");                               \
                                                                        \
@@ -519,6 +530,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.  */                                \
@@ -754,6 +767,12 @@ struct mips_cpu_info {
 #define MIPS_32BIT_OPTION_SPEC \
   "mips1|mips2|mips32*|mgp32"
 
+/* A spec condition that matches architectures should be targeted with
+   o32 FPXX for compatibility reasons.  */
+#define MIPS_FPXX_OPTION_SPEC \
+  "mips2|mips3|mips4|mips5|mips32|mips32r2|mips32r3|mips32r5| \
+   mips64|mips64r2|mips64r3|mips64r5"
+
 /* Infer a -msynci setting from a -mips argument, on the assumption that
    -msynci is desired where possible.  */
 #define MIPS_ISA_SYNCI_SPEC \
@@ -778,7 +797,12 @@ struct mips_cpu_info {
    --with-abi is ignored if -mabi is specified.
    --with-float is ignored if -mhard-float or -msoft-float are
      specified.
+   --with-fpu is ignored if -msoft-float, -msingle-float or -mdouble-float are
+     specified.
    --with-nan is ignored if -mnan is specified.
+   --with-fp-32 is ignored if -msoft-float, -msingle-float or -mfp are specified.
+   --with-odd-spreg-32 is ignored if -msoft-float, -msingle-float, -modd-spreg
+     or -mno-odd-spreg are specified.
    --with-divide is ignored if -mdivide-traps or -mdivide-breaks are
      specified. */
 #define OPTION_DEFAULT_SPECS \
@@ -790,8 +814,12 @@ struct mips_cpu_info {
   {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \
   {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
   {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
-  {"fpu", "%{!msingle-float:%{!mdouble-float:-m%(VALUE)-float}}" }, \
+  {"fpu", "%{!msoft-float:%{!msingle-float:%{!mdouble-float:-m%(VALUE)-float}}}" }, \
   {"nan", "%{!mnan=*:-mnan=%(VALUE)}" }, \
+  {"fp_32", "%{" OPT_ARCH32 \
+           ":%{!msoft-float:%{!msingle-float:%{!mfp*:-mfp%(VALUE)}}}}" }, \
+  {"odd_spreg_32", "%{" OPT_ARCH32 ":%{!msoft-float:%{!msingle-float:" \
+                  "%{!modd-spreg:%{!mno-odd-spreg:-m%(VALUE)}}}}}" }, \
   {"divide", "%{!mdivide-traps:%{!mdivide-breaks:-mdivide-%(VALUE)}}" }, \
   {"llsc", "%{!mllsc:%{!mno-llsc:-m%(VALUE)}}" }, \
   {"mips-plt", "%{!mplt:%{!mno-plt:-m%(VALUE)}}" }, \
@@ -843,6 +871,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                    \
@@ -1030,7 +1064,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) \
@@ -1186,7 +1221,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=*} \
@@ -1358,7 +1394,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.  */
@@ -1764,6 +1800,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 callee-saved
+   for o32 FPXX as they will be clobbered when run on an FR=1 FPU.  */
+#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE)                    \
+  (TARGET_FLOATXX && hard_regno_nregs[REGNO][MODE] == 1                        \
+   && FP_REG_P (REGNO) && ((REGNO) & 1))
+
 #define MODES_TIEABLE_P mips_modes_tieable_p
 
 /* Register to use for pushing function arguments.  */
@@ -2097,6 +2143,19 @@ enum reg_class
 #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X)                  \
   mips_secondary_reload_class (CLASS, MODE, X, false)
 
+/* 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, 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.  */
 
@@ -2218,12 +2277,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])
 \f
 /* This structure has to cope with two different argument allocation
index 4b72546..647bf85 100644 (file)
   (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)
+                          || TARGET_O32_FP64A_ABI")
+             (eq_attr "dword_mode" "yes"))
+        (const_string "no")
+        (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.
       rtx low = mips_subword (operands[1], 0);
       rtx high = mips_subword (operands[1], 1);
       emit_insn (gen_load_low<mode> (operands[0], low));
-      if (TARGET_FLOAT64 && !TARGET_64BIT)
+      if (ISA_HAS_MXHC1 && !TARGET_64BIT)
        emit_insn (gen_mthc1<mode> (operands[0], high, operands[0]));
       else
        emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
       rtx low = mips_subword (operands[0], 0);
       rtx high = mips_subword (operands[0], 1);
       emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
-      if (TARGET_FLOAT64 && !TARGET_64BIT)
+      if (ISA_HAS_MXHC1 && !TARGET_64BIT)
        emit_insn (gen_mfhc1<mode> (high, operands[1]));
       else
        emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
index dca4f80..146961e 100644 (file)
@@ -197,6 +197,10 @@ mfp32
 Target Report RejectNegative InverseMask(FLOAT64)
 Use 32-bit floating-point registers
 
+mfpxx
+Target Report RejectNegative Mask(FLOATXX)
+Conform to the o32 FPXX ABI
+
 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 76d289e..d6dc1bb 100644 (file)
@@ -34,6 +34,11 @@ 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 ABI option is specified, infer one from the              \
+     ABI/ISA level.  */                                                        \
+  "%{!msoft-float: %{!msingle-float: %{!mfp*: %{mabi=32: %{"           \
+  MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}}}",                               \
+                                                                       \
   /* Make sure that an endian option is always present.  This makes    \
      things like LINK_SPEC easier to write.  */                                \
   "%{!EB:%{!EL:%(endian_spec)}}",                                      \
index 34b64d6..98d6582 100644 (file)
@@ -39,6 +39,11 @@ 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 ABI option is specified, infer one from the              \
+     ABI/ISA level.  */                                                        \
+  "%{!msoft-float: %{!msingle-float: %{!mfp*: %{mabi=32: %{"           \
+  MIPS_FPXX_OPTION_SPEC ": -mfpxx}}}}}",                               \
+                                                                       \
   /* Base SPECs.  */                                                   \
   BASE_DRIVER_SELF_SPECS                                               \
                                                                        \
index 6459a8a..064b438 100755 (executable)
@@ -26152,6 +26152,41 @@ $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confdefs.h
 
 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_dot_module+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_mips_dot_module=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.module fp=32' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { 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_dot_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_dot_module" >&5
+$as_echo "$gcc_cv_as_mips_dot_module" >&6; }
+if test $gcc_cv_as_mips_dot_module = yes; then
+
+$as_echo "#define HAVE_AS_DOT_MODULE 1" >>confdefs.h
+
+fi
+    if test x$gcc_cv_as_mips_dot_module = xno \
+       && test x$with_fp_32 != x; then
+      as_fn_error "Requesting --with-fp-32= requires assembler support for .module." "$LINENO" 5
+    fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
 $as_echo_n "checking assembler for .micromips support... " >&6; }
 if test "${gcc_cv_as_micromips_support+set}" = set; then :
index ba2b387..8be5479 100644 (file)
@@ -4241,6 +4241,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_dot_module,,,
+      [.module fp=32],,
+      [AC_DEFINE(HAVE_AS_DOT_MODULE, 1,
+         [Define if your assembler supports .module.])])
+    if test x$gcc_cv_as_mips_dot_module = xno \
+       && test x$with_fp_32 != x; then
+      AC_MSG_ERROR(
+       [Requesting --with-fp-32= requires assembler support for .module.])
+    fi
+
     gcc_GAS_CHECK_FEATURE([.micromips support],
       gcc_cv_as_micromips_support,,[--fatal-warnings],
       [.set micromips],,
index 9fbf853..f314cf2 100644 (file)
@@ -1261,6 +1261,32 @@ ISA for floating-point arithmetics.  You can select either @samp{sse} which
 enables @option{-msse2} or @samp{avx} which enables @option{-mavx} by default.
 This option is only supported on i386 and x86-64 targets.
 
+@item --with-fp-32=@var{mode}
+On MIPS targets, set the default value for the @option{-mfp} option when using
+the o32 ABI.  The possibilities for @var{mode} are:
+@table @code
+@item 32
+Use the o32 FP32 ABI extension, as with the @option{-mfp32} command-line
+option.
+@item xx
+Use the o32 FPXX ABI extension, as with the @option{-mfpxx} command-line
+option.
+@item 64
+Use the o32 FP64 ABI extension, as with the @option{-mfp64} command-line
+option.
+@end table
+In the absence of this configuration option the default is to use the o32
+FP32 ABI extension.
+
+@item --with-odd-spreg-32
+On MIPS targets, set the @option{-modd-spreg} option by default when using
+the o32 ABI.
+
+@item --without-odd-spreg-32
+On MIPS targets, set the @option{-mno-odd-spreg} option by default when using
+the o32 ABI.  This is normally used in conjunction with
+@option{--with-fp-32=64} in order to target the o32 FP64A ABI extension.
+
 @item --with-nan=@var{encoding}
 On MIPS targets, set the default encoding convention to use for the
 special not-a-number (NaN) IEEE 754 floating-point data.  The
index 13270bc..294e17d 100644 (file)
@@ -788,8 +788,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
 -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
@@ -17745,7 +17746,20 @@ same, but each scalar value is passed in a single 64-bit register
 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.
+
+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
+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
@@ -17834,6 +17848,10 @@ Assume that floating-point registers are 32 bits wide.
 @opindex mfp64
 Assume that floating-point registers are 64 bits wide.
 
+@item -mfpxx
+@opindex mfpxx
+Do not assume the width of floating-point registers.
+
 @item -mhard-float
 @opindex mhard-float
 Use floating-point coprocessor instructions.
@@ -17865,6 +17883,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 processors that are 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 93889d4..c2cbfe8 100644 (file)
@@ -1,3 +1,27 @@
+2014-11-12  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * gcc.target/mips/args-1.c: Handle __mips_fpr == 0.
+       * gcc.target/mips/call-clobbered-1.c: New.
+       * gcc.target/mips/call-clobbered-2.c: New.
+       * gcc.target/mips/call-clobbered-3.c: New.
+       * gcc.target/mips/call-clobbered-4.c: New.
+       * gcc.target/mips/call-clobbered-5.c: New.
+       * gcc.target/mips/call-saved-4.c: New.
+       * gcc.target/mips/call-saved-5.c: New.
+       * gcc.target/mips/call-saved-6.c: New.
+       * gcc.target/mips/mips.exp: Support -mfpxx, -ffixed-f*,
+       and -m[no-]odd-spreg.  Use _MIPS_SPFPSET to determine default
+       odd-spreg option.  Account for -modd-spreg in minimum arch code.
+       * gcc.target/mips/movdf-1.c: New.
+       * gcc.target/mips/movdf-2.c: New.
+       * gcc.target/mips/movdf-3.c: New.
+       * gcc.target/mips/oddspreg-1.c: New.
+       * gcc.target/mips/oddspreg-2.c: New.
+       * gcc.target/mips/oddspreg-3.c: New.
+       * gcc.target/mips/oddspreg-4.c: New.
+       * gcc.target/mips/oddspreg-5.c: New.
+       * gcc.target/mips/oddspreg-6.c: New.
+
 2014-11-12  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/63815
index 3a132de..643df24 100644 (file)
@@ -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
 
diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-1.c b/gcc/testsuite/gcc.target/mips/call-clobbered-1.c
new file mode 100644 (file)
index 0000000..ecb994f
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-2.c b/gcc/testsuite/gcc.target/mips/call-clobbered-2.c
new file mode 100644 (file)
index 0000000..5f9a472
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-3.c b/gcc/testsuite/gcc.target/mips/call-clobbered-3.c
new file mode 100644 (file)
index 0000000..fce4d99
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-4.c b/gcc/testsuite/gcc.target/mips/call-clobbered-4.c
new file mode 100644 (file)
index 0000000..51498b8
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-clobbered-5.c b/gcc/testsuite/gcc.target/mips/call-clobbered-5.c
new file mode 100644 (file)
index 0000000..c7cd7ca
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-saved-4.c b/gcc/testsuite/gcc.target/mips/call-saved-4.c
new file mode 100644 (file)
index 0000000..e126175
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-saved-5.c b/gcc/testsuite/gcc.target/mips/call-saved-5.c
new file mode 100644 (file)
index 0000000..2937b31
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/call-saved-6.c b/gcc/testsuite/gcc.target/mips/call-saved-6.c
new file mode 100644 (file)
index 0000000..0d1a4c8
--- /dev/null
@@ -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 e2b137e..a9beb27 100644 (file)
@@ -235,7 +235,7 @@ set mips_option_groups {
     endianness "-E(L|B)|-me(l|b)"
     float "-m(hard|soft)-float"
     forbid_cpu "forbid_cpu=.*"
-    fp "-mfp(32|64)"
+    fp "-mfp(32|xx|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
     micromips "-mmicromips|-mno-micromips"
@@ -248,6 +248,10 @@ set mips_option_groups {
     dump "-fdump-.*"
 }
 
+for { set option 0 } { $option < 32 } { incr option } {
+    lappend mips_option_groups "fixed-f$option" "-ffixed-f$option"
+}
+
 # Add -mfoo/-mno-foo options to mips_option_groups.
 foreach option {
     abicalls
@@ -270,6 +274,7 @@ foreach option {
     synci
     relax-pic-calls
     mcount-ra-address
+    odd-spreg
 } {
     lappend mips_option_groups $option "-m(no-|)$option"
 }
@@ -723,8 +728,12 @@ proc mips-dg-init {} {
            #if __mips_fpr == 64
            "-mfp64",
            #else
+           #if __mips_fpr == 0
+           "-mfpxx",
+           #else
            "-mfp32",
            #endif
+           #endif
 
            #ifdef __mips64
            "-mgp64",
@@ -756,6 +765,12 @@ proc mips-dg-init {} {
            "-mno-paired-single",
            #endif
 
+           #if _MIPS_SPFPSET == 32
+           "-modd-spreg",
+           #else
+           "-mno-odd-spreg",
+           #endif
+
            #if __mips_abicalls
            "-mabicalls",
            #else
@@ -841,6 +856,8 @@ proc mips-dg-finish {} {
 #            |                           |
 #         -mfp64                      -mfp32
 #            |                           |
+#         -modd-spreg                 -mno-odd-spreg
+#            |                           |
 #         -mabs=2008/-mabs=legacy     <no option>
 #            |                           |
 #         -mhard-float                -msoft-float
@@ -930,6 +947,7 @@ proc mips-dg-options { args } {
     mips_option_dependency options "-mips3d" "-mpaired-single"
     mips_option_dependency options "-mpaired-single" "-mfp64"
     mips_option_dependency options "-mfp64" "-mhard-float"
+    mips_option_dependency options "-mfp64" "-modd-spreg"
     mips_option_dependency options "-mabs=2008" "-mhard-float"
     mips_option_dependency options "-mabs=legacy" "-mhard-float"
     mips_option_dependency options "-mrelax-pic-calls" "-mno-plt"
@@ -1046,10 +1064,13 @@ proc mips-dg-options { args } {
         # We need a MIPS32 or MIPS64 ISA for:
        #
         #   - paired-single instructions(*)
+        #   - odd numbered single precision registers
         #
        # (*) Note that we don't support MIPS V at the moment.
        } elseif { $isa_rev < 1
-                  && [mips_have_test_option_p options "-mpaired-single"] } {
+                  && ([mips_have_test_option_p options "-mpaired-single"]
+                      || ([mips_have_test_option_p options "-modd-spreg"]
+                          && ![mips_have_test_option_p options "-mfp64"]))} {
            if { $gp_size == 32 } {
                mips_make_test_option options "-mips32"
            } else {
@@ -1071,7 +1092,9 @@ proc mips-dg-options { args } {
        # (*) needed by both -mbranch-likely and -mfix-r10000
        } elseif { $isa < 2
                   && ([mips_have_test_option_p options "-mbranch-likely"]
-                      || [mips_have_test_option_p options "-mfix-r10000"]) } {
+                      || [mips_have_test_option_p options "-mfix-r10000"]
+                      || ($gp_size == 32
+                          && [mips_have_test_option_p options "-mfpxx"])) } {
            mips_make_test_option options "-mips2"
        # Check whether we need to switch from a 32-bit processor to the
        # "nearest" 64-bit processor.
@@ -1122,6 +1145,9 @@ proc mips-dg-options { args } {
        } elseif { [mips_have_test_option_p options "-mlong64"]
                   && [mips_long32_abi_p $abi] } {
            set force_abi 1
+       } elseif { [mips_have_test_option_p options "-mfpxx"]
+                  && ![mips_same_option_p $abi "-mabi=32"] } {
+           set force_abi 1
        } else {
            set force_abi 0
        }
@@ -1193,6 +1219,9 @@ proc mips-dg-options { args } {
        }
        if { $isa_rev < 1 } {
            mips_make_test_option options "-mno-paired-single"
+           if { ![mips_have_test_option_p options "-mgp64"] } {
+               mips_make_test_option options "-mno-odd-spreg"
+           }
        }
        if { $isa_rev < 2 } {
            if { $gp_size == 32 } {
@@ -1223,6 +1252,7 @@ proc mips-dg-options { args } {
     mips_option_dependency options "-mplt" "-mno-shared"
     mips_option_dependency options "-mno-shared" "-fno-pic"
     mips_option_dependency options "-mfp32" "-mno-paired-single"
+    mips_option_dependency options "-mfpxx" "-mno-paired-single"
     mips_option_dependency options "-msoft-float" "-mno-paired-single"
     mips_option_dependency options "-mno-paired-single" "-mno-mips3d"
 
@@ -1244,7 +1274,9 @@ proc mips-dg-options { args } {
     foreach group $mips_abi_groups {
        set old_option [mips_original_option $group]
        set new_option [mips_option options $group]
-       if { ![mips_same_option_p $old_option $new_option] } {
+       if { ![mips_same_option_p $old_option $new_option]
+            && ![mips_same_option_p $old_option "-mfpxx"]
+            && ![mips_same_option_p $new_option "-mfpxx"] } {
            switch -- [lindex $do_what 0] {
                link -
                run {
diff --git a/gcc/testsuite/gcc.target/mips/movdf-1.c b/gcc/testsuite/gcc.target/mips/movdf-1.c
new file mode 100644 (file)
index 0000000..f0267d0
--- /dev/null
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/mips/movdf-2.c b/gcc/testsuite/gcc.target/mips/movdf-2.c
new file mode 100644 (file)
index 0000000..175b61c
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/movdf-3.c b/gcc/testsuite/gcc.target/mips/movdf-3.c
new file mode 100644 (file)
index 0000000..5db52c9
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-1.c b/gcc/testsuite/gcc.target/mips/oddspreg-1.c
new file mode 100644 (file)
index 0000000..a9c6957
--- /dev/null
@@ -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));
+}
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-2.c b/gcc/testsuite/gcc.target/mips/oddspreg-2.c
new file mode 100644 (file)
index 0000000..e2e0a26
--- /dev/null
@@ -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));
+}
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-3.c b/gcc/testsuite/gcc.target/mips/oddspreg-3.c
new file mode 100644 (file)
index 0000000..f287eb6
--- /dev/null
@@ -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 -mfp32 -march=loongson3a -mhard-float" } */
+
+void
+foo ()
+{
+  register float foo asm ("$f1"); /* { dg-error "isn't suitable for" } */
+  asm volatile ("" : "=f" (foo));
+}
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-4.c b/gcc/testsuite/gcc.target/mips/oddspreg-4.c
new file mode 100644 (file)
index 0000000..723424a
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-5.c b/gcc/testsuite/gcc.target/mips/oddspreg-5.c
new file mode 100644 (file)
index 0000000..8d7d884
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/mips/oddspreg-6.c b/gcc/testsuite/gcc.target/mips/oddspreg-6.c
new file mode 100644 (file)
index 0000000..955dea9
--- /dev/null
@@ -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 17c8bb1..fd7ba11 100644 (file)
@@ -1,3 +1,9 @@
+2014-11-12  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * config/mips/mips16.S: Set .module when supported.  Update O32
+       FP64 calling convention and use for FPXX when possible.  Add FPXX
+       calling convention fallback case.
+
 2014-11-06  Bernd Schmidt  <bernds@codesourcery.com>
 
        * config.host: Handle nvptx-*-*.
index dde8939..c0c73ff 100644 (file)
@@ -21,6 +21,8 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#include "auto-host.h"
+
 #if defined(__mips_micromips) || defined(__mips_soft_float)
   /* Do nothing because this code is only needed when linking
      against mips16 hard-float objects.  Neither micromips code
@@ -29,6 +31,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      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 respectively.  If not, see
 /* 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 respectively.  If not, see
 #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