diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/ppc-sysv-tdep.c | 79 |
2 files changed, 68 insertions, 19 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 518bd17..9ef0469 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,6 +1,14 @@ 2007-11-07 Joseph Myers <joseph@codesourcery.com> Daniel Jacobowitz <dan@codesourcery.com> + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Right-align + struct values smaller than one doubleword; left-align those + larger. Pass structs containing a single floating-point value in + registers. + +2007-11-07 Joseph Myers <joseph@codesourcery.com> + Daniel Jacobowitz <dan@codesourcery.com> + * gdbtypes.c (floatformats_ibm_long_double): New. * gdbtypes.h (floatformats_ibm_long_double): Declare. * ia64-tdep.c (floatformat_ia64_ext): Update for addition of diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c index 21947aa..9d54227 100644 --- a/gdb/ppc-sysv-tdep.c +++ b/gdb/ppc-sysv-tdep.c @@ -977,22 +977,17 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, if (len > tdep->wordsize) len = tdep->wordsize; memset (regval, 0, sizeof regval); - /* WARNING: cagney/2003-09-21: As best I can - tell, the ABI specifies that the value should - be left aligned. Unfortunately, GCC doesn't - do this - it instead right aligns even sized - values and puts odd sized values on the - stack. Work around that by putting both a - left and right aligned value into the - register (hopefully no one notices :-^). - Arrrgh! */ - /* Left aligned (8 byte values such as pointers - fill the buffer). */ - memcpy (regval, val + byte, len); - /* Right aligned (but only if even). */ - if (len == 1 || len == 2 || len == 4) + /* The ABI (version 1.9) specifies that values + smaller than one doubleword are right-aligned + and those larger are left-aligned. GCC + versions before 3.4 implemented this + incorrectly; see + <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>. */ + if (byte == 0) memcpy (regval + tdep->wordsize - len, val + byte, len); + else + memcpy (regval, val + byte, len); regcache_cooked_write (regcache, greg, regval); } greg++; @@ -1006,11 +1001,57 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, value to memory. Fortunately, doing this simplifies the code. */ write_memory (gparam, val, TYPE_LENGTH (type)); - if (write_pass) - /* WARNING: cagney/2004-06-20: It appears that GCC - likes to put structures containing a single - floating-point member in an FP register instead of - general general purpose. */ + if (freg <= 13 + && TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1 + && TYPE_LENGTH (type) <= 16) + { + /* The ABI (version 1.9) specifies that structs + containing a single floating-point value, at any + level of nesting of single-member structs, are + passed in floating-point registers. */ + while (TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1) + type = check_typedef (TYPE_FIELD_TYPE (type, 0)); + if (TYPE_CODE (type) == TYPE_CODE_FLT) + { + if (TYPE_LENGTH (type) <= 8) + { + if (write_pass) + { + gdb_byte regval[MAX_REGISTER_SIZE]; + struct type *regtype + = register_type (gdbarch, + tdep->ppc_fp0_regnum); + convert_typed_floating (val, type, regval, + regtype); + regcache_cooked_write (regcache, + (tdep->ppc_fp0_regnum + + freg), + regval); + } + freg++; + } + else if (TYPE_LENGTH (type) == 16 + && (gdbarch_long_double_format (current_gdbarch) + == floatformats_ibm_long_double)) + { + if (write_pass) + { + regcache_cooked_write (regcache, + (tdep->ppc_fp0_regnum + + freg), + val); + if (freg <= 12) + regcache_cooked_write (regcache, + (tdep->ppc_fp0_regnum + + freg + 1), + val + 8); + } + freg += 2; + } + } + } /* Always consume parameter stack space. */ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); } |