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
This commit is contained in:
Richard Sandiford 2004-08-19 18:44:32 +00:00 committed by Richard Sandiford
parent e3f92d3b7d
commit ae04300302
2 changed files with 114 additions and 47 deletions

View File

@ -1,3 +1,11 @@
2004-08-19 Richard Sandiford <rsandifo@redhat.com>
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 <rth@redhat.com>
* config/arm/arm.c (arm_gen_load_multiple): Use

View File

@ -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;
case ABI_N32:
case ABI_64:
info->fpr_p = (named && (type == 0 || FLOAT_TYPE_P (type)));
break;
}
/* Now decide whether the argument must go in an even-numbered register. */
even_reg_p = false;
if (info->fpr_p)
The checks against UNITS_PER_FPVALUE handle the soft-float and
single-float cases. */
switch (mips_abi)
{
/* 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);
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_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;
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;
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