diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2006-06-08 07:23:04 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@codesourcery.com> | 2006-06-08 07:23:04 +0000 |
commit | 12dccab81d483164e14abcb064bb85f8158ab0d5 (patch) | |
tree | 6b0eb5ef07cf1ef617e958ead54dcf625b479f73 | |
parent | d1c75ada32762217cc2f8cffb3fdedc53db40e0b (diff) | |
download | gdb-12dccab81d483164e14abcb064bb85f8158ab0d5.tar.gz |
* gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Use
tdep->ptr_value_regnum for pointer returns.
(m68k_svr4_store_return_value): Likewise.
(m68k_reg_struct_return_r): New, broken out of ...
(m68k_reg_struct_return_p): ... here. Implement gcc's structure
mode algorithm.
(m68k_svr4_init_abi, m68k_aout_init_abi): Set ptr_value_regnum.
(m68k_gdbarch_init): Likewise.
* gdb/m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum
field.
-rw-r--r-- | ChangeLog.csl | 13 | ||||
-rw-r--r-- | gdb/m68k-tdep.c | 149 | ||||
-rw-r--r-- | gdb/m68k-tdep.h | 3 |
3 files changed, 86 insertions, 79 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl index c7dfa9c557b..4c6cab05128 100644 --- a/ChangeLog.csl +++ b/ChangeLog.csl @@ -1,3 +1,16 @@ +2006-06-08 Nathan Sidwell <nathan@codesourcery.com> + + * gdb/m68k-tdep.c (m68k_svr4_extract_return_value): Use + tdep->ptr_value_regnum for pointer returns. + (m68k_svr4_store_return_value): Likewise. + (m68k_reg_struct_return_r): New, broken out of ... + (m68k_reg_struct_return_p): ... here. Implement gcc's structure + mode algorithm. + (m68k_svr4_init_abi, m68k_aout_init_abi): Set ptr_value_regnum. + (m68k_gdbarch_init): Likewise. + * gdb/m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum + field. + 2006-06-05 Nathan Sidwell <nathan@codesourcery.com> * gdb/remote.c (remote_insert_watchpoint): Return -1, rather than diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c index 73dfae801ee..1a4493f9bf9 100644 --- a/gdb/m68k-tdep.c +++ b/gdb/m68k-tdep.c @@ -265,11 +265,10 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache, regcache_raw_read (regcache, M68K_FP0_REGNUM, buf); convert_typed_floating (buf, *tdep->fpreg_type, valbuf, type); } -#if 0 - /* GCC never differentiates pointer return types this way. */ else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4) - regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf); -#endif + regcache_raw_read (regcache, + gdbarch_tdep (current_gdbarch)->ptr_value_regnum, + valbuf); else m68k_extract_return_value (type, regcache, valbuf); } @@ -309,48 +308,46 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache, regcache_raw_write (regcache, M68K_FP0_REGNUM, buf); } else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4) - { - regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf); - regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf); - } + regcache_raw_write (regcache, + gdbarch_tdep (current_gdbarch)->ptr_value_regnum, + valbuf); else m68k_store_return_value (type, regcache, valbuf); } /* Return non-zero if TYPE, which is assumed to be a structure or union type, should be returned in registers for architecture - GDBARCH. */ + 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_p (struct gdbarch *gdbarch, struct type *type) +m68k_reg_struct_return_r (struct type *type, int *align_p) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum type_code code = TYPE_CODE (type); int len = TYPE_LENGTH (type); - int align; + int field_align = 1; + int my_align = len > 2 ? 2 : len; int ix; - struct type *union_field_type = NULL; - - gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION); - - if (tdep->struct_return == pcc_struct_return) - return 0; - - /* 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. Unions - will get the mode of last member whose size matches that of the - union itself. This is horrible. */ - if (len > 8 || (len & -len) != len) - /* Length is not 2^n or is too big. */ + 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; - align = len > 4 ? 4 : len; for (ix = 0; ix != TYPE_NFIELDS (type); ix++) { struct type *field_type; @@ -364,60 +361,48 @@ m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) field_type = check_typedef (field_type); field_len = TYPE_LENGTH (field_type); - if (code == TYPE_CODE_STRUCT) - { - /* 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 the field's alignment is finer than the structs, we - won't be in registers. */ - if (field_len < align) - return 0; - - /* If the field itself is a struct or union, then check it - can be passed in registers. */ - if ((TYPE_CODE (field_type) == TYPE_CODE_STRUCT - || TYPE_CODE (field_type) == TYPE_CODE_UNION) - && !m68k_reg_struct_return_p (gdbarch, field_type)) - return 0; - } - else + /* Look through arrays. */ + while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY) { - /* If this field accounts for the whole union, remember it. - Note that we remember the last such field to match GCC's - algorithm. */ - if (field_len == len) - union_field_type = field_type; + field_type = TYPE_TARGET_TYPE (field_type); + field_type = check_typedef (field_type); + field_len = TYPE_LENGTH (field_type); } - } - if (code == TYPE_CODE_UNION) - { - if (!union_field_type) + if (!m68k_reg_struct_return_r (field_type, &field_align)) return 0; - /* Look through arrays. */ - while (TYPE_CODE (union_field_type) == TYPE_CODE_ARRAY) - { - union_field_type = TYPE_TARGET_TYPE (union_field_type); - union_field_type = check_typedef (union_field_type); - } - /* If this field's alignment is too small, then we won't be in - registers. */ - if (TYPE_LENGTH (union_field_type) < align) - return 0; - - if (TYPE_CODE (union_field_type) == TYPE_CODE_STRUCT - || TYPE_CODE (union_field_type) == TYPE_CODE_UNION) - return m68k_reg_struct_return_p (gdbarch, union_field_type); } + + if (align_p && field_align > *align_p) + *align_p = field_align; - /* It will be returned in registers */ - return 1; + 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 +m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum type_code code = TYPE_CODE (type); + int len = TYPE_LENGTH (type); + int align; + int ix; + struct type *union_field_type = NULL; + + gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION); + + if (tdep->struct_return == pcc_struct_return) + return 0; + + 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 @@ -1217,6 +1202,8 @@ m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* SVR4 uses %a0. */ tdep->struct_value_regnum = M68K_A0_REGNUM; tdep->struct_return = reg_struct_return; + /* Pointers are returned in %a0 */ + tdep->ptr_value_regnum = M68K_A0_REGNUM; } /* a.out */ @@ -1228,8 +1215,11 @@ m68k_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_return_value (gdbarch, m68k_return_value); + /* aout uses %a1 */ tdep->struct_value_regnum = M68K_A1_REGNUM; tdep->struct_return = reg_struct_return; + /* Pointers are returned in %a0 */ + tdep->ptr_value_regnum = M68K_A0_REGNUM; } @@ -1286,6 +1276,7 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_return_value (gdbarch, m68k_svr4_return_value); tdep->struct_value_regnum = M68K_A0_REGNUM; tdep->struct_return = reg_struct_return; + tdep->ptr_value_regnum = M68K_D0_REGNUM; tdep->float_return = M68K_RETURN_FP0; tdep->fpreg_type = &M68K_FPREG_TYPE; diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h index f68a9035a79..15f48029cde 100644 --- a/gdb/m68k-tdep.h +++ b/gdb/m68k-tdep.h @@ -77,6 +77,9 @@ struct gdbarch_tdep /* Convention for returning structures. */ enum struct_return struct_return; + /* Register in which pointers are returned. */ + int ptr_value_regnum; + /* Convention for returning floats. zero in int regs, non-zero in float. */ int float_return; |