aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@redhat.com>2004-08-19 18:44:32 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2004-08-19 18:44:32 +0000
commitae043003021c0c559cea825813c04da153c28c3b (patch)
tree591262b9a14f5af77ebd7decb4f4e29345de89f0
parente3f92d3b7d8ef96a9420223eac37c0ece1921e97 (diff)
downloadgcc-ae043003021c0c559cea825813c04da153c28c3b.zip
gcc-ae043003021c0c559cea825813c04da153c28c3b.tar.gz
gcc-ae043003021c0c559cea825813c04da153c28c3b.tar.bz2
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
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/mips/mips.c149
2 files changed, 112 insertions, 45 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bca0f90..cf8fd92 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 148bf27..29bee9c 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