[rfa] mips argument passing fixes for o32

Daniel Jacobowitz
2001-07-06T11:26:00Z

These are based on testsuite failures (call-*-st, if I remember correctly)
and reading the argument passing code in GCC. The struct alignment fix
definitely agrees with the ABI, though it's not always clear on this point -
it becomes necessary for us when the return value is a struct and thus there
is a hidden pointer as the first argument. The shift fix matches this
comment in GCC and is not really specified by the ABI document:

/* The following is a hack in order to pass 1 byte structures
the same way that the MIPS compiler does (namely by passing
the structure in the high byte or half word of the register).
This also makes varargs work. If we have such a structure,
we save the adjustment RTL, and the call define expands will
emit them. For the VOIDmode argument (argument after the
last real argument), pass back a parallel vector holding each
of the adjustments. */

/* ??? function_arg can be called more than once for each argument.
As a result, we compute more adjustments than we need here.
See the CUMULATIVE_ARGS definition in mips.h. */

/* ??? This scheme requires everything smaller than the word size to
shifted to the left, but when TARGET_64BIT and ! TARGET_INT64,
that would mean every int needs to be shifted left, which is very
inefficient. Let's not carry this compatibility to the 64 bit
calling convention for now. */

if (struct_p && int_size_in_bytes (type) < UNITS_PER_WORD
&& ! TARGET_64BIT && mips_abi != ABI_EABI)
{
rtx amount = GEN_INT (BITS_PER_WORD
- int_size_in_bytes (type) * BITS_PER_UNIT);
rtx reg = gen_rtx_REG (word_mode, regbase + *arg_words + bias);

if (TARGET_64BIT)
cum->adjust[cum->num_adjusts++] = gen_ashldi3 (reg, reg, amount);
else
cum->adjust[cum->num_adjusts++] = gen_ashlsi3 (reg, reg, amount);
}

OK?

--
Daniel Jacobowitz Carnegie Mellon University
MontaVista Software Debian GNU/Linux Developer

2001-07-06 Daniel Jacobowitz <drow@mvista.com>

* mips-tdep.c (mips_type_needs_double_align): New function.
(mips_push_arguments): Align o32 structs to even argument
registers if necessary. Shift small structures to the left
in registers even if the target is little endian.

Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.56
diff -u -r1.56 mips-tdep.c
--- mips-tdep.c 2001/07/06 05:35:17 1.56
+++ mips-tdep.c 2001/07/06 18:03:57
@@ -2126,6 +2133,36 @@
&& MIPS_FPU_TYPE != MIPS_FPU_NONE);
}

+/* On o32, argument passing in GPRs depends on the alignment of the type being
+ passed. Return 1 if this type must be aligned to a doubleword boundary. */
+
+static int
+mips_type_needs_double_align (struct type *type)
+{
+ enum type_code typecode = TYPE_CODE (type);
+
+ if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
+ return 1;
+ else if (typecode == TYPE_CODE_STRUCT)
+ {
+ if (TYPE_NFIELDS (type) < 1)
+ return 0;
+ return mips_type_needs_double_align (TYPE_FIELD_TYPE (type, 0));
+ }
+ else if (typecode == TYPE_CODE_UNION)
+ {
+ int i, n;
+
+ n = TYPE_NFIELDS (type);
+ for (i = 0; i < n; i++)
+ if (mips_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+
CORE_ADDR
mips_push_arguments (int nargs,
value_ptr *args,
@@ -2312,6 +2349,13 @@
compatibility, we will put them in both places. */
int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
(len % MIPS_SAVED_REGSIZE != 0));
+ /* Structures should be aligned to eight bytes (even arg registers)
+ on MIPS_ABI_O32 if their first member has double precision. */
+ if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+ && mips_type_needs_double_align (arg_type))
+ {
+ argreg += argreg & 1;
+ }
/* Note: Floating-point values that didn't fit into an FP
register are only written to memory. */
while (len > 0)
@@ -2393,7 +2437,8 @@

if (!MIPS_EABI
&& MIPS_SAVED_REGSIZE < 8
- && TARGET_BYTE_ORDER == BIG_ENDIAN
+ && (TARGET_BYTE_ORDER == BIG_ENDIAN
+ || TYPE_LENGTH (arg_type) < MIPS_SAVED_REGSIZE)
&& partial_len < MIPS_SAVED_REGSIZE
&& (typecode == TYPE_CODE_STRUCT ||
typecode == TYPE_CODE_UNION))