diff options
author | mpf <mpf@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-12 21:39:46 +0000 |
---|---|---|
committer | mpf <mpf@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-12 21:39:46 +0000 |
commit | f2b55aeab6c09c3924d3e42e3cfcc5f204a1a7d3 (patch) | |
tree | ae5a1e2880c64a6507d463ca40e21b1f5abaf535 /gcc/config/mips | |
parent | 3fc3fa0f33d5f8c032f29e84df07e3b1aadb0fe6 (diff) | |
download | gcc-f2b55aeab6c09c3924d3e42e3cfcc5f204a1a7d3.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217446 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mips')
-rw-r--r-- | gcc/config/mips/mips-protos.h | 5 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 243 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 77 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 20 | ||||
-rw-r--r-- | gcc/config/mips/mips.opt | 8 | ||||
-rw-r--r-- | gcc/config/mips/mti-elf.h | 5 | ||||
-rw-r--r-- | gcc/config/mips/mti-linux.h | 5 |
7 files changed, 326 insertions, 37 deletions
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index db939132355..adeda598a9d 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 a09883b988f..02268f3247e 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 dd67f11fe03..8a388294219 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 4b725467467..647bf853c22 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 dca4f808945..146961e52ad 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 76d289eaeeb..d6dc1bb84e4 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 34b64d6e5fb..98d6582b198 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 \ \ |