summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <jsm@polyomino.org.uk>2008-06-03 10:53:34 +0000
committerJoseph Myers <jsm@polyomino.org.uk>2008-06-03 10:53:34 +0000
commite29d49b994869cd03ddea2a01ec89f23c8c81f87 (patch)
tree97cdc6d4be511873d5b73b92b4697a7a6e9079b6
parent073103f85cb8645e8412ac7f0bab6577d77496a2 (diff)
downloadgdb-e29d49b994869cd03ddea2a01ec89f23c8c81f87.tar.gz
2008-06-03 Michael Snyder <msnyder@redhat.com>
Joseph Myers <joseph@codesourcery.com> * mips-tdep.c (mips_eabi_return_value): Replace stub that always returned RETURN_VALUE_STRUCT_CONVENTION with a real function.
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/mips-tdep.c53
2 files changed, 57 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 08a01c742e5..5f4fbba5f9b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2008-06-03 Michael Snyder <msnyder@redhat.com>
+ Joseph Myers <joseph@codesourcery.com>
+
+ * mips-tdep.c (mips_eabi_return_value): Replace stub that always
+ returned RETURN_VALUE_STRUCT_CONVENTION with a real function.
+
2008-06-02 Roman Zippel <zippel@linux-m68k.org>
* m68klinux-tdep.c (m68k_linux_pc_in_sigtramp): Fix incorrect test.
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 6277407695d..976bcf7f0e6 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -2956,10 +2956,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type,
struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int fp_return_type = 0;
+ int offset, regnum, xfer;
+
if (TYPE_LENGTH (type) > 2 * mips_abi_regsize (gdbarch))
return RETURN_VALUE_STRUCT_CONVENTION;
- if (readbuf)
- memset (readbuf, 0, TYPE_LENGTH (type));
+
+ /* Floating point type? */
+ if (tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ fp_return_type = 1;
+ /* Structs with a single field of float type
+ are returned in a floating point register. */
+ if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ && TYPE_NFIELDS (type) == 1)
+ {
+ struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
+
+ if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
+ fp_return_type = 1;
+ }
+ }
+
+ if (fp_return_type)
+ {
+ /* A floating-point value belongs in the least significant part
+ of FP0/FP1. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+ regnum = mips_regnum (gdbarch)->fp0;
+ }
+ else
+ {
+ /* An integer value goes in V0/V1. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return scalar in $v0\n");
+ regnum = MIPS_V0_REGNUM;
+ }
+ for (offset = 0;
+ offset < TYPE_LENGTH (type);
+ offset += mips_abi_regsize (gdbarch), regnum++)
+ {
+ xfer = mips_abi_regsize (gdbarch);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ mips_xfer_register (gdbarch, regcache,
+ gdbarch_num_regs (gdbarch) + regnum, xfer,
+ gdbarch_byte_order (gdbarch), readbuf, writebuf,
+ offset);
+ }
+
return RETURN_VALUE_REGISTER_CONVENTION;
}