PR gdb/12796
authorMark Kettenis <kettenis@gnu.org>
Tue, 23 Oct 2012 18:16:55 +0000 (18:16 +0000)
committerMark Kettenis <kettenis@gnu.org>
Tue, 23 Oct 2012 18:16:55 +0000 (18:16 +0000)
PR gdb/12798
PR gdb/12800
* amd64-tdep.h (enum amd64_regnum): Add AMD64_ST1_REGNUM and
AMD64_FTAG_REGNUM.
* amd64-tdep.c (amd64_classify): Classify complex types.
(amd64_return_value): Handle the COMPLEX_X87 class.

gdb/ChangeLog
gdb/amd64-tdep.c
gdb/amd64-tdep.h

index d3d534d..2ccc5d7 100644 (file)
@@ -1,3 +1,13 @@
+2012-10-23  Mark Kettenis  <kettenis@gnu.org>
+
+       PR gdb/12796
+       PR gdb/12798
+       PR gdb/12800
+       * amd64-tdep.h (enum amd64_regnum): Add AMD64_ST1_REGNUM and
+       AMD64_FTAG_REGNUM.
+       * amd64-tdep.c (amd64_classify): Classify complex types.
+       (amd64_return_value): Handle the COMPLEX_X87 class.
+
 2012-10-23  Joel Brobecker  <brobecker@adacore.com>
 
        * rs6000-aix-tdep.c (rs6000_aix_auto_wide_charset): New function.
index 9cee464..a4172fc 100644 (file)
@@ -586,6 +586,23 @@ amd64_classify (struct type *type, enum amd64_reg_class class[2])
     /* Class X87 and X87UP.  */
     class[0] = AMD64_X87, class[1] = AMD64_X87UP;
 
+  /* Arguments of complex T where T is one of the types float or
+     double get treated as if they are implemented as:
+
+     struct complexT {
+       T real;
+       T imag;
+     };  */
+  else if (code == TYPE_CODE_COMPLEX && len == 8)
+    class[0] = AMD64_SSE;
+  else if (code == TYPE_CODE_COMPLEX && len == 16)
+    class[0] = class[1] = AMD64_SSE;
+
+  /* A variable of type complex long double is classified as type
+     COMPLEX_X87.  */
+  else if (code == TYPE_CODE_COMPLEX && len == 32)
+    class[0] = AMD64_COMPLEX_X87;
+
   /* Aggregates.  */
   else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT
           || code == TYPE_CODE_UNION)
@@ -636,6 +653,30 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
       return RETURN_VALUE_ABI_RETURNS_ADDRESS;
     }
 
+  /* 8. If the class is COMPLEX_X87, the real part of the value is
+        returned in %st0 and the imaginary part in %st1.  */
+  if (class[0] == AMD64_COMPLEX_X87)
+    {
+      if (readbuf)
+       {
+         regcache_raw_read (regcache, AMD64_ST0_REGNUM, readbuf);
+         regcache_raw_read (regcache, AMD64_ST1_REGNUM, readbuf + 16);
+       }
+
+      if (writebuf)
+       {
+         i387_return_value (gdbarch, regcache);
+         regcache_raw_write (regcache, AMD64_ST0_REGNUM, writebuf);
+         regcache_raw_write (regcache, AMD64_ST1_REGNUM, writebuf + 16);
+
+         /* Fix up the tag word such that both %st(0) and %st(1) are
+            marked as valid.  */
+         regcache_raw_write_unsigned (regcache, AMD64_FTAG_REGNUM, 0xfff);
+       }
+
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+
   gdb_assert (class[1] != AMD64_MEMORY);
   gdb_assert (len <= 16);
 
index cb901cc..eba0d6d 100644 (file)
@@ -57,8 +57,10 @@ enum amd64_regnum
   AMD64_FS_REGNUM,             /* %fs */
   AMD64_GS_REGNUM,             /* %gs */
   AMD64_ST0_REGNUM = 24,       /* %st0 */
+  AMD64_ST1_REGNUM,            /* %st1 */
   AMD64_FCTRL_REGNUM = AMD64_ST0_REGNUM + 8,
   AMD64_FSTAT_REGNUM = AMD64_ST0_REGNUM + 9,
+  AMD64_FTAG_REGNUM = AMD64_ST0_REGNUM + 10,
   AMD64_XMM0_REGNUM = 40,      /* %xmm0 */
   AMD64_XMM1_REGNUM,           /* %xmm1 */
   AMD64_MXCSR_REGNUM = AMD64_XMM0_REGNUM + 16,