diff options
author | Matthew Fortune <matthew.fortune@imgtec.com> | 2014-11-12 21:39:46 +0000 |
---|---|---|
committer | Matthew Fortune <mpf@gcc.gnu.org> | 2014-11-12 21:39:46 +0000 |
commit | 050af1445b878d2a8a070f4c2ad602cbe80f8d73 (patch) | |
tree | ae5a1e2880c64a6507d463ca40e21b1f5abaf535 | |
parent | 21c767169b833b6c22f8b1e8550e95ef792b6fd1 (diff) | |
download | gcc-050af1445b878d2a8a070f4c2ad602cbe80f8d73.zip gcc-050af1445b878d2a8a070f4c2ad602cbe80f8d73.tar.gz gcc-050af1445b878d2a8a070f4c2ad602cbe80f8d73.tar.bz2 |
Implement MIPS o32 FPXX, FP64, FP64A ABI extensions.
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, 955 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1fc374b..a15bfd2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/common/config/mips/mips-common.c b/gcc/common/config/mips/mips-common.c index 7dd8d2d..a140d55 100644 --- a/gcc/common/config/mips/mips-common.c +++ b/gcc/common/config/mips/mips-common.c @@ -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; } diff --git a/gcc/config.gcc b/gcc/config.gcc index 0b223a4..0af4a1a 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -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` diff --git a/gcc/config.in b/gcc/config.in index 8b8c556..520b5f7 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -472,6 +472,12 @@ #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 diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index db93913..adeda598 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -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 *, diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index a09883b..02268f3 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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); 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 diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index dd67f11..8a38829 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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]) /* This structure has to cope with two different argument allocation diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 4b72546..647bf85 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -433,11 +433,17 @@ (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. @@ -4997,7 +5003,7 @@ rtx low = mips_subword (operands[1], 0); rtx high = mips_subword (operands[1], 1); emit_insn (gen_load_low<mode> (operands[0], low)); - if (TARGET_FLOAT64 && !TARGET_64BIT) + if (ISA_HAS_MXHC1 && !TARGET_64BIT) emit_insn (gen_mthc1<mode> (operands[0], high, operands[0])); else emit_insn (gen_load_high<mode> (operands[0], high, operands[0])); @@ -5007,7 +5013,7 @@ rtx low = mips_subword (operands[0], 0); rtx high = mips_subword (operands[0], 1); emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx)); - if (TARGET_FLOAT64 && !TARGET_64BIT) + if (ISA_HAS_MXHC1 && !TARGET_64BIT) emit_insn (gen_mfhc1<mode> (high, operands[1])); else emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx)); diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt index dca4f80..146961e 100644 --- a/gcc/config/mips/mips.opt +++ b/gcc/config/mips/mips.opt @@ -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 diff --git a/gcc/config/mips/mti-elf.h b/gcc/config/mips/mti-elf.h index 76d289e..d6dc1bb 100644 --- a/gcc/config/mips/mti-elf.h +++ b/gcc/config/mips/mti-elf.h @@ -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)}}", \ diff --git a/gcc/config/mips/mti-linux.h b/gcc/config/mips/mti-linux.h index 34b64d6..98d6582 100644 --- a/gcc/config/mips/mti-linux.h +++ b/gcc/config/mips/mti-linux.h @@ -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 \ \ diff --git a/gcc/configure b/gcc/configure index 6459a8a..064b438 100755 --- a/gcc/configure +++ b/gcc/configure @@ -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 : diff --git a/gcc/configure.ac b/gcc/configure.ac index ba2b387..8be5479 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -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],, diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 9fbf853..f314cf2 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 13270bc..294e17d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 93889d4d..c2cbfe8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/gcc.target/mips/args-1.c b/gcc/testsuite/gcc.target/mips/args-1.c index 3a132de..643df24 100644 --- a/gcc/testsuite/gcc.target/mips/args-1.c +++ b/gcc/testsuite/gcc.target/mips/args-1.c @@ -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 index 0000000..ecb994f --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-1.c @@ -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 index 0000000..5f9a472 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-2.c @@ -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 index 0000000..fce4d99 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-3.c @@ -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 index 0000000..51498b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-4.c @@ -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 index 0000000..c7cd7ca --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-clobbered-5.c @@ -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 index 0000000..e126175 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-saved-4.c @@ -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 index 0000000..2937b31 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-saved-5.c @@ -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 index 0000000..0d1a4c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-saved-6.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index e2b137e..a9beb27 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -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 index 0000000..f0267d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/movdf-1.c @@ -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 index 0000000..175b61c --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/movdf-2.c @@ -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 index 0000000..5db52c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/movdf-3.c @@ -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 index 0000000..a9c6957 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-1.c @@ -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 index 0000000..e2e0a26 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-2.c @@ -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 index 0000000..f287eb6 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-3.c @@ -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 index 0000000..723424a --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-4.c @@ -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 index 0000000..8d7d884 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-5.c @@ -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 index 0000000..955dea901 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/oddspreg-6.c @@ -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)); +} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 17c8bb1..fd7ba11 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -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-*-*. diff --git a/libgcc/config/mips/mips16.S b/libgcc/config/mips/mips16.S index dde8939..c0c73ff 100644 --- a/libgcc/config/mips/mips16.S +++ b/libgcc/config/mips/mips16.S @@ -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 |