Commit ae043003 by Richard Sandiford Committed by Richard Sandiford

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
parent e3f92d3b
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> 2004-08-19 Richard Henderson <rth@redhat.com>
* config/arm/arm.c (arm_gen_load_multiple): Use * config/arm/arm.c (arm_gen_load_multiple): Use
......
...@@ -330,9 +330,6 @@ struct mips_arg_info ...@@ -330,9 +330,6 @@ struct mips_arg_info
would have been if we hadn't run out of registers. */ would have been if we hadn't run out of registers. */
bool fpr_p; bool fpr_p;
/* The argument's size, in bytes. */
unsigned int num_bytes;
/* The number of words passed in registers, rounded up. */ /* The number of words passed in registers, rounded up. */
unsigned int reg_words; unsigned int reg_words;
...@@ -2957,50 +2954,96 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -2957,50 +2954,96 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named, struct mips_arg_info *info) tree type, int named, struct mips_arg_info *info)
{ {
bool even_reg_p; 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, /* Work out the size of the argument. */
assuming one is free. Later code checks for availability. */ 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 /* Decide whether it should go in a floating-point register, assuming
&& GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE); one is free. Later code checks for availability.
if (info->fpr_p) The checks against UNITS_PER_FPVALUE handle the soft-float and
switch (mips_abi) single-float cases. */
{ switch (mips_abi)
case ABI_32: {
case ABI_O64: case ABI_EABI:
info->fpr_p = (!cum->gp_reg_found /* The EABI conventions have traditionally been defined in terms
&& cum->arg_number < 2 of TYPE_MODE, regardless of the actual type. */
&& (type == 0 || FLOAT_TYPE_P (type))); info->fpr_p = (GET_MODE_CLASS (mode) == MODE_FLOAT
break; && GET_MODE_SIZE (mode) <= UNITS_PER_FPVALUE);
break;
case ABI_N32: case ABI_32:
case ABI_64: case ABI_O64:
info->fpr_p = (named && (type == 0 || FLOAT_TYPE_P (type))); /* Only leading floating-point scalars are passed in
break; 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; default:
if (info->fpr_p) abort ();
{
/* 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);
} }
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; even_reg_p = true;
} }
...@@ -3019,12 +3062,6 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -3019,12 +3062,6 @@ mips_arg_info (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
if (even_reg_p) if (even_reg_p)
info->stack_offset += info->stack_offset & 1; 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; max_regs = MAX_ARGS_IN_REGISTERS - info->reg_offset;
/* Partition the argument between registers and stack. */ /* Partition the argument between registers and stack. */
...@@ -3154,6 +3191,28 @@ function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ...@@ -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) if (info.fpr_p)
return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset); return gen_rtx_REG (mode, FP_ARG_FIRST + info.reg_offset);
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment