diff options
Diffstat (limited to 'gcc/config/mips/mips.c')
-rw-r--r-- | gcc/config/mips/mips.c | 68 |
1 files changed, 51 insertions, 17 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 2dcf69d3f43..d73e52b4cf8 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -4321,9 +4321,11 @@ mips_arg_info (cum, mode, type, named, info) is a double, but $f14 if it is a single. Otherwise, on a 32-bit double-float machine, each FP argument must start in a new register pair. */ - even_reg_p = ((mips_abi == ABI_O64 && mode == SFmode) || FP_INC > 1); + even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_HWFPVALUE + || (mips_abi == ABI_O64 && mode == SFmode) + || FP_INC > 1); } - else if (!TARGET_64BIT) + else if (!TARGET_64BIT || LONG_DOUBLE_TYPE_SIZE == 128) { if (GET_MODE_CLASS (mode) == MODE_INT || GET_MODE_CLASS (mode) == MODE_FLOAT) @@ -4635,7 +4637,7 @@ mips_setup_incoming_varargs (cum, mode, type, no_rtl) rtx ptr = plus_constant (virtual_incoming_args_rtx, off); emit_move_insn (gen_rtx_MEM (mode, ptr), gen_rtx_REG (mode, FP_ARG_FIRST + i)); - off += UNITS_PER_FPVALUE; + off += UNITS_PER_HWFPVALUE; } } } @@ -4712,6 +4714,15 @@ mips_va_start (valist, nextarg) { const CUMULATIVE_ARGS *cum = ¤t_function_args_info; + /* ARG_POINTER_REGNUM is initialized to STACK_POINTER_BOUNDARY, but + since the stack is aligned for a pair of argument-passing slots, + and the beginning of a variable argument list may be an odd slot, + we have to decrease its alignment. */ + if (cfun && cfun->emit->regno_pointer_align) + while (((current_function_pretend_args_size * BITS_PER_UNIT) + & (REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) - 1)) != 0) + REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) /= 2; + if (mips_abi == ABI_EABI) { int gpr_save_area_size; @@ -4909,9 +4920,9 @@ mips_va_arg (valist, type) off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff); /* When floating-point registers are saved to the stack, - each one will take up UNITS_PER_FPVALUE bytes, regardless + each one will take up UNITS_PER_HWFPVALUE bytes, regardless of the float's precision. */ - rsize = UNITS_PER_FPVALUE; + rsize = UNITS_PER_HWFPVALUE; } else { @@ -4930,7 +4941,7 @@ mips_va_arg (valist, type) bytes (= PARM_BOUNDARY bits). RSIZE can sometimes be smaller than that, such as in the combination -mgp64 -msingle-float -fshort-double. Doubles passed in registers will then take - up UNITS_PER_FPVALUE bytes, but those passed on the stack + up UNITS_PER_HWFPVALUE bytes, but those passed on the stack take up UNITS_PER_WORD bytes. */ osize = MAX (rsize, UNITS_PER_WORD); @@ -5007,7 +5018,10 @@ mips_va_arg (valist, type) that alignments <= UNITS_PER_WORD are preserved by the va_arg increment mechanism. */ - if (TARGET_64BIT) + if ((mips_abi == ABI_N32 || mips_abi == ABI_64) + && TYPE_ALIGN (type) > 64) + align = 16; + else if (TARGET_64BIT) align = 8; else if (TYPE_ALIGN (type) > 32) align = 8; @@ -5365,6 +5379,10 @@ override_options () else mips16 = 0; +#ifdef MIPS_TFMODE_FORMAT + real_format_for_mode[TFmode - QFmode] = &MIPS_TFMODE_FORMAT; +#endif + mips_print_operand_punct['?'] = 1; mips_print_operand_punct['#'] = 1; mips_print_operand_punct['&'] = 1; @@ -7085,7 +7103,7 @@ save_restore_insns (store_p, large_reg, large_offset) /* Pick which pointer to use as a base register. */ fp_offset = cfun->machine->frame.fp_sp_offset; end_offset = fp_offset - (cfun->machine->frame.fp_reg_size - - UNITS_PER_FPVALUE); + - UNITS_PER_HWFPVALUE); if (fp_offset < 0 || end_offset < 0) internal_error @@ -7140,7 +7158,7 @@ save_restore_insns (store_p, large_reg, large_offset) else emit_move_insn (reg_rtx, mem_rtx); - fp_offset -= UNITS_PER_FPVALUE; + fp_offset -= UNITS_PER_HWFPVALUE; } } } @@ -8271,11 +8289,26 @@ mips_function_value (valtype, func, mode) } mclass = GET_MODE_CLASS (mode); - if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE) + if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) reg = FP_RETURN; + else if (mclass == MODE_FLOAT && mode == TFmode) + /* long doubles are really split between f0 and f2, not f1. Eek. + Use DImode for each component, since GCC wants integer modes + for subregs. */ + return gen_rtx_PARALLEL + (VOIDmode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (DImode, FP_RETURN), + GEN_INT (0)), + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (DImode, FP_RETURN + 2), + GEN_INT (GET_MODE_SIZE (mode) / 2)))); + + else if (mclass == MODE_COMPLEX_FLOAT - && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE * 2) + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2) { enum machine_mode cmode = GET_MODE_INNER (mode); @@ -8416,19 +8449,20 @@ function_arg_pass_by_reference (cum, mode, type, named) We can't allow 64-bit float registers to change from a 32-bit mode to a 64-bit mode. */ -enum reg_class -mips_cannot_change_mode_class (from, to) +bool +mips_cannot_change_mode_class (from, to, class) enum machine_mode from, to; + enum reg_class class; { if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) { if (TARGET_BIG_ENDIAN) - return FP_REGS; + return reg_classes_intersect_p (FP_REGS, class); if (TARGET_FLOAT64) - return HI_AND_FP_REGS; - return HI_REG; + return reg_classes_intersect_p (HI_AND_FP_REGS, class); + return reg_classes_intersect_p (HI_REG, class); } - return NO_REGS; + return false; } /* This function returns the register class required for a secondary |