From ae043003021c0c559cea825813c04da153c28c3b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 19 Aug 2004 18:44:32 +0000 Subject: [PATCH] re PR target/16446 (Irix calling conventions for complex numbers) PR target/16446 * config/mips/mips.c (struct mips_arg_info): Delete num_bytes. (mips_arg_info): Update accordingly. Remove common treatment of fpr_p; treat each ABI separately. Deal with n32/n64 complex float arguments. (function_arg): Add associated complex handling here. From-SVN: r86259 --- gcc/ChangeLog | 8 +++ gcc/config/mips/mips.c | 149 ++++++++++++++++++++++++++++------------- 2 files changed, 112 insertions(+), 45 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bca0f90125c..cf8fd9253dd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2004-08-19 Richard Sandiford + + PR target/16446 + * config/mips/mips.c (struct mips_arg_info): Delete num_bytes. + (mips_arg_info): Update accordingly. Remove common treatment of fpr_p; + treat each ABI separately. Deal with n32/n64 complex float arguments. + (function_arg): Add associated complex handling here. + 2004-08-19 Richard Henderson * config/arm/arm.c (arm_gen_load_multiple): Use diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 148bf27e402..29bee9c7bcd 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -330,9 +330,6 @@ struct mips_arg_info would have been if we hadn't run out of registers. */ bool fpr_p; - /* The argument's size, in bytes. */ - unsigned int num_bytes; - /* The number of words passed in registers, rounded up. */ unsigned int reg_words; @@ -2957,50 +2954,96 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named, struct mips_arg_info *info) { bool even_reg_p; - unsigned int num_words, max_regs; + unsigned int num_bytes, num_words, max_regs; - /* Decide whether this argument should go in a floating-point register, - assuming one is free. Later code checks for availability. */ + /* Work out the size of the argument. */ + num_bytes = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + num_words = (num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - info->fpr_p = (GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE); + /* Decide whether it should go in a floating-point register, assuming + one is free. Later code checks for availability. - if (info->fpr_p) - switch (mips_abi) - { - case ABI_32: - case ABI_O64: - info->fpr_p = (!cum->gp_reg_found - && cum->arg_number < 2 - && (type == 0 || FLOAT_TYPE_P (type))); - break; + The checks against UNITS_PER_FPVALUE handle the soft-float and + single-float cases. */ + switch (mips_abi) + { + case ABI_EABI: + /* The EABI conventions have traditionally been defined in terms + of TYPE_MODE, regardless of the actual type. */ + info->fpr_p = (GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE); + break; - case ABI_N32: - case ABI_64: - info->fpr_p = (named && (type == 0 || FLOAT_TYPE_P (type))); - break; - } + case ABI_32: + case ABI_O64: + /* Only leading floating-point scalars are passed in + floating-point registers. */ + info->fpr_p = (!cum->gp_reg_found + && cum->arg_number < 2 + && (type == 0 || SCALAR_FLOAT_TYPE_P (type)) + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE); + break; - /* Now decide whether the argument must go in an even-numbered register. */ + case ABI_N32: + case ABI_64: + /* Scalar and complex floating-point types are passed in + floating-point registers. */ + info->fpr_p = (named + && (type == 0 || FLOAT_TYPE_P (type)) + && (GET_MODE_CLASS (mode) == MODE_FLOAT + || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) + && GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_FPVALUE); + + /* ??? According to the ABI documentation, the real and imaginary + parts of complex floats should be passed in individual registers. + The real and imaginary parts of stack arguments are supposed + to be contiguous and there should be an extra word of padding + at the end. + + This has two problems. First, it makes it impossible to use a + single "void *" va_list type, since register and stack arguments + are passed differently. (At the time of writing, MIPSpro cannot + handle complex float varargs correctly.) Second, it's unclear + hat should happen when there is only one register free. + + For now, we assume that named complex floats should go into FPRs + if there are two FPRs free, otherwise they should be passed in the + same way as a struct containing two floats. */ + if (info->fpr_p + && GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && GET_MODE_UNIT_SIZE (mode) < UNITS_PER_FPVALUE) + { + if (cum->num_gprs >= MAX_ARGS_IN_REGISTERS - 1) + info->fpr_p = false; + else + num_words = 2; + } + break; - even_reg_p = false; - if (info->fpr_p) - { - /* Under the O64 ABI, the second float argument goes in $f13 if it - 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 = (GET_MODE_SIZE (mode) > UNITS_PER_HWFPVALUE - || (mips_abi == ABI_O64 && mode == SFmode) - || FP_INC > 1); + default: + abort (); } - else if (!TARGET_64BIT || LONG_DOUBLE_TYPE_SIZE == 128) - { - if (GET_MODE_CLASS (mode) == MODE_INT - || GET_MODE_CLASS (mode) == MODE_FLOAT) - even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD); - else if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD) + /* Now decide whether the argument must go in an even-numbered register. + Usually this is determined by type alignment, but there are two + exceptions: + + - Under the O64 ABI, the second float argument goes in $f14 if it + is single precision (doubles go in $f13 as expected). + + - Floats passed in FPRs must be in an even-numbered register if + we're using paired FPRs. */ + if (type) + even_reg_p = TYPE_ALIGN (type) > BITS_PER_WORD; + else + even_reg_p = GET_MODE_UNIT_SIZE (mode) > UNITS_PER_WORD; + + if (info->fpr_p) + { + if (mips_abi == ABI_O64 && mode == SFmode) + even_reg_p = true; + if (FP_INC > 1) even_reg_p = true; } @@ -3019,12 +3062,6 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode, if (even_reg_p) info->stack_offset += info->stack_offset & 1; - if (mode == BLKmode) - info->num_bytes = int_size_in_bytes (type); - else - info->num_bytes = GET_MODE_SIZE (mode); - - num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; max_regs = MAX_ARGS_IN_REGISTERS - info->reg_offset; /* Partition the argument between registers and stack. */ @@ -3154,6 +3191,28 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, } } + /* Handle the n32/n64 conventions for passing complex floating-point + arguments in FPR pairs. The real part goes in the lower register + and the imaginary part goes in the upper register. */ + if (TARGET_NEWABI + && info.fpr_p + && GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) + { + rtx real, imag; + enum machine_mode inner; + int reg; + + inner = GET_MODE_INNER (mode); + reg = FP_ARG_FIRST + info.reg_offset; + real = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (inner, reg), + const0_rtx); + imag = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (inner, reg + info.reg_words / 2), + GEN_INT (GET_MODE_SIZE (inner))); + return gen_rtx_PARALLEL (mode, gen_rtvec (2, real, imag)); + } + if (info.fpr_p) return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset); else -- 2.30.2