From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Subject: [rfa] mips argument passing fixes for o32 Date: Fri, 06 Jul 2001 11:26:00 -0000 Message-id: <20010706112635.A5870@nevyn.them.org> X-SW-Source: 2001-07/msg00156.html 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 * 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))