aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/ppc-sysv-tdep.c79
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);
}