summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2006-06-08 07:23:04 +0000
committerNathan Sidwell <nathan@codesourcery.com>2006-06-08 07:23:04 +0000
commit12dccab81d483164e14abcb064bb85f8158ab0d5 (patch)
tree6b0eb5ef07cf1ef617e958ead54dcf625b479f73
parentd1c75ada32762217cc2f8cffb3fdedc53db40e0b (diff)
downloadgdb-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.csl13
-rw-r--r--gdb/m68k-tdep.c149
-rw-r--r--gdb/m68k-tdep.h3
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;