commit 46907f38a4f2d3fadf755aad647fb089d32ad6cb Author: Vladimir Prus Date: Tue Apr 26 15:47:50 2011 +0400 Adjust "is register used for struct returns" logic to what GCC does. * m68k-tdep.c (m68k_reg_struct_return_r): New, broken out of ... (m68k_reg_struct_return_p): ... here. Implement gcc's structure mode algorithm. (m68k_svr4_return_value): Adjust to gcc behaviour. diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c index c6ae36d..736bf5b 100644 --- a/gdb/m68k-tdep.c +++ b/gdb/m68k-tdep.c @@ -378,6 +378,70 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache, /* Return non-zero if TYPE, which is assumed to be a structure or union type, should be returned in registers for architecture + GDBARCH. + + Unfortunately GCC incorrectly implements this optimization. Rather + than simply return all small structs, or even just those of size + 2^N, it uses the mode of the structure to determine this. BLKmode + structs will be returned by memory and QI,HI,SI,DI,SF&DF mode + structs will be returned by register. For m68k a struct is BLKmode + unless it's size is 2^N and the mode for that size does not need a + greater alignment than the structure itself. This is horrible. */ + + +static int +m68k_reg_struct_return_r (struct type *type, int *align_p) +{ + enum type_code code = TYPE_CODE (type); + int len = TYPE_LENGTH (type); + int field_align = 1; + int my_align = len > 2 ? 2 : len; + int ix; + + if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION) + { + if (align_p && my_align > *align_p) + *align_p = my_align; + return 1; + } + + if ((len & -len) != len) + /* Length is not 2^n. */ + return 0; + + for (ix = 0; ix != TYPE_NFIELDS (type); ix++) + { + struct type *field_type; + int field_len; + + if (field_is_static (&TYPE_FIELD (type, ix))) + /* Skip static fields. */ + continue; + + field_type = TYPE_FIELD_TYPE (type, ix); + field_type = check_typedef (field_type); + field_len = TYPE_LENGTH (field_type); + + /* Look through arrays. */ + while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY) + { + field_type = TYPE_TARGET_TYPE (field_type); + field_type = check_typedef (field_type); + field_len = TYPE_LENGTH (field_type); + } + + if (!m68k_reg_struct_return_r (field_type, &field_align)) + return 0; + } + + if (align_p && field_align > *align_p) + *align_p = field_align; + + return align_p || my_align <= field_align; +} + +/* Return non-zero if TYPE, which is assumed to be a structure or + union type, should be returned in registers for architecture GDBARCH. */ static int @@ -392,7 +456,11 @@ m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) if (tdep->struct_return == pcc_struct_return) return 0; - return (len == 1 || len == 2 || len == 4 || len == 8); + if (len > 8) + /* Length is too big. */ + return 0; + + return m68k_reg_struct_return_r (type, NULL); } /* Determine, for architecture GDBARCH, how a return value of TYPE @@ -446,25 +514,11 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type, if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) && !m68k_reg_struct_return_p (gdbarch, type)) { - /* The System V ABI says that: - - "A function returning a structure or union also sets %a0 to - the value it finds in %a0. Thus when the caller receives - control again, the address of the returned object resides in - register %a0." - - So the ABI guarantees that we can always find the return - value just after the function has returned. */ - - if (readbuf) - { - ULONGEST addr; - - regcache_raw_read_unsigned (regcache, M68K_A0_REGNUM, &addr); - read_memory (addr, readbuf, TYPE_LENGTH (type)); - } - - return RETURN_VALUE_ABI_RETURNS_ADDRESS; + /* Although they SYSV ABI specifies that a function returning a + structure this way should preserve %a0, GCC doesn't do that. + Furthermore there's no point changeing GCC to make it do it, + as that would just be bloat. */ + return RETURN_VALUE_STRUCT_CONVENTION; } /* This special case is for structures consisting of a single