diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 84ceb1b4fc9..9d5ff317abc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2003-01-28 Alexandre Oliva + + * config/mips/mips.h (UNITS_PER_HWFPVALUE): Renamed from... + (UNITS_PER_FPVALUE): Defined as the width of a long double, or + zero if no hardware floating point. + (LONG_DUBLE_TYPE_SIZE): Set to 128 on N32 and N64. + (MAX_FIXED_MODE_SIZE): Define to LONG_DOUBLE_TYPE_SIZE. + (LIBGCC2_LONG_DOUBLE_TYPE_SIZE): Define. + (BIGGEST_ALIGNMENT): Same as LONG_DOUBLE_TYPE_SIZE. + (FUNCTION_VALUE_REGNO_P): Set for FP_RETURN+2 on N32 and N64. + * config/mips/mips.c (mips_arg_info): Pass TFmode values in + even FP registers on N32 and N64. + (mips_setup_incoming_varargs): Use UNITS_PER_HWFPVALUE. + (mips_va_start): Adjust alignment of ARG_POINTER_REGNUM. + (mips_va_arg): Use UNITS_PER_HWFPVALUE. Impose additional + even-register-like alignment to 128-bit arguments. + (save_restore_insns): Use UNITS_PER_HWFPVALUE. + (mips_function_value): Likewise. Return TFmode in $f0 and $f2 + on N32 or N64. + * config/mips/_tilib.c (__negti2, __ashlti3, __lshrti3): New. + * config/mips/t-iris6 (LIB2FUNCS_EXTRA): Add _tilib.c. + (TPBIT): Set to tp-bit.c. + (tp-bit.c): Create out of fp-bit.c. + 2003-01-28 Gabriel Dos Reis * c-parse.in: Remove '%expect 32' directive in objc mode. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index c0133fafdb2..b1408f19024 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -4315,9 +4315,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) @@ -4629,7 +4631,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; } } } @@ -4706,6 +4708,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; @@ -4903,9 +4914,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 { @@ -4924,7 +4935,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); @@ -4998,7 +5009,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; @@ -7080,7 +7094,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 @@ -7133,7 +7147,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; } } } @@ -8264,11 +8278,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); diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 09d46632fe3..61a6b0db735 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1517,8 +1517,14 @@ do { \ the next available register. */ #define FP_INC (TARGET_FLOAT64 || TARGET_SINGLE_FLOAT ? 1 : 2) -/* The largest size of value that can be held in floating-point registers. */ -#define UNITS_PER_FPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG) +/* The largest size of value that can be held in floating-point + registers and moved with a single instruction. */ +#define UNITS_PER_HWFPVALUE (TARGET_SOFT_FLOAT ? 0 : FP_INC * UNITS_PER_FPREG) + +/* The largest size of value that can be held in floating-point + registers. */ +#define UNITS_PER_FPVALUE \ + (TARGET_SOFT_FLOAT ? 0 : (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)) /* The number of bytes in a double. */ #define UNITS_PER_DOUBLE (TYPE_PRECISION (double_type_node) / BITS_PER_UNIT) @@ -1565,7 +1571,21 @@ do { \ /* A C expression for the size in bits of the type `long double' on the target machine. If you don't define this, the default is two words. */ -#define LONG_DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE \ + (mips_abi == ABI_N32 || mips_abi == ABI_64 ? 128 : 64) + +/* long double is not a fixed mode, but the idea is that, if we + support long double, we also want a 128-bit integer type. */ +#define MAX_FIXED_MODE_SIZE LONG_DOUBLE_TYPE_SIZE + +#ifdef IN_LIBGCC2 +#if (defined _ABIN32 && _MIPS_SIM == _ABIN32) \ + || (defined _ABI64 && _MIPS_SIM == _ABI64) +# define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128 +# else +# define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 +# endif +#endif /* Width in bits of a pointer. See also the macro `Pmode' defined below. */ @@ -1592,7 +1612,7 @@ do { \ #define STRUCTURE_SIZE_BOUNDARY 8 /* There is no point aligning anything to a rounder boundary than this. */ -#define BIGGEST_ALIGNMENT 64 +#define BIGGEST_ALIGNMENT LONG_DOUBLE_TYPE_SIZE /* Set this nonzero if move instructions will actually fail to work when given unaligned data. */ @@ -2654,7 +2674,9 @@ extern enum reg_class mips_char_to_class[256]; 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) */ -#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN) +#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN \ + || (LONG_DOUBLE_TYPE_SIZE == 128 && FP_RETURN != GP_RETURN \ + && (N) == FP_RETURN + 2)) /* 1 if N is a possible register number for function argument passing. We have no FP argument registers when soft-float. When FP registers diff --git a/gcc/config/mips/t-iris6 b/gcc/config/mips/t-iris6 index 1d61c244bf1..a1be0b9c9ed 100644 --- a/gcc/config/mips/t-iris6 +++ b/gcc/config/mips/t-iris6 @@ -18,3 +18,16 @@ CRTSTUFF_T_CFLAGS=-g1 # This is only needed in the static libgcc as a band-aid until gcc correctly # implements the N32/N64 ABI structure passing conventions LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/mips/irix6-libc-compat.c + +LIB2FUNCS_EXTRA = $(srcdir)/config/mips/_tilib.c + +TPBIT = tp-bit.c + +tp-bit.c: $(srcdir)/config/fp-bit.c + echo '#ifdef __MIPSEL__' > tp-bit.c + echo '# define FLOAT_BIT_ORDER_MISMATCH' >> tp-bit.c + echo '#endif' >> tp-bit.c + echo '#if __LDBL_MANT_DIG__ == 106' >> tp-bit.c + echo '# define TFLOAT' >> tp-bit.c + cat $(srcdir)/config/fp-bit.c >> tp-bit.c + echo '#endif' >> tp-bit.c