PATCH: Extend gdb remote protocol for AVX

H.J. Lu
2008-09-18T17:28:28Z

Hi,

Intel AVX extends 128bit XMM registers to 256bit YMM registers. I
am enclosing a propose to add YMM register support in gdb. Since
there is no AVX hardware, we can only implement the remote debug
with AVX emulator.

This patch extends gdb remote protocol for AVX, based on Daniel's
patch to auto-detect ia32 and x86-64 executables:

http://sources.redhat.com/ml/gdb-patches/2006-11/msg00056.html

I tested it by setting x86_sse_unit to avx in gdbserver/i387-fp.c. OK
to install?

Thanks.

H.J.
----
Goals:

1. Only display YMM registers, no XMM registers if the execution
environment supports AVX, independent of executables.
2. Native:
a. Check native AVX support at run-time.
b. Use AVX registers only if native environment supports AVX.
Otherwise use XMM registers.
3. Remote:
a. Check remote AVX support when setting up connection.
b. Use AVX registers only if remote environment supports AVX.
Otherwise use XMM registers.

Implementation:

1. Add sse_unit to gdbarch_tdep:
a. sse_unit can be either sse or avx.
b. Use xmm registers if sse_unit is sse.
c. Use ymm registers if sse_unit is avx.
2. Native. Set sse_unit based on native environment.
3. Remote. Update remote protocol:
a. If remote target supports SSE, no change.
b. If remote target supports AVX:
i. Don't send xmlarch.
ii. Replace 128bit xmm registers with 256bit ymm registers in
the g/G packet.
iii. Gdb will auto-detect SSE unit on remote target, based on the
the g/G packet size.

---
gdb/

2008-09-18 H.J. Lu <hongjiu.lu@intel.com>

* amd64-linux-tdep.c (amd64_linux_init_abi): Call
i386_register_g_packet_guesses.
* i386-linux-tdep.c (i386_linux_init_abi): Likewise.

* amd64-tdep.c (amd64_register_names): Renamed to ...
(amd64_sse_register_names): This.
(amd64_avx_register_names): New.
(AMD64_NUM_REGS): Updated.
(amd64_register_name): Handle sse_unit.
(amd64_init_abi): Call i386_gdbarch_sse_unit_init.

* amd64-tdep.h (AMD64_G_PACKET_SIZE_SSE): New.
(AMD64_G_PACKET_SIZE_AVX): Likewise.

* i386-tdep.c: Include "remote.h" and "target-descriptions.h".
(I386_PROPERTY_SSE): New.
(I386_PROPERTY_AVX): Likewise.
(i386_tdesc_sse): Likewise.
(i386_tdesc_avx): Likewise.
(i386_avx_register_names): Likewise.
(i386_vec128_type): Likewise.
(i386_vec256_type): Likewise.
(i386_init_tdesc): Likewise.
(i386_register_g_packet_guesses): Likewise.
(i386_gdbarch_sse_unit_init): Likewise.
(i386_register_names): Renamed to ...
(i386_sse_register_names): This.
(i386_num_register_names): Updated.
(i386_register_name): Handle sse_unit.
(i386_sse_type): Likewise.
(i386_gdbarch_init): Call i386_gdbarch_sse_unit_init and
i386_register_g_packet_guesses.
(_initialize_i386_tdep): Call i386_init_tdesc.

* i386-tdep.h (x86_sse_unit): New.
(I386_G_PACKET_SIZE_SSE): Likewise.
(I386_G_PACKET_SIZE_AVX): Likewise.
(i386_register_g_packet_guesses): Likewise.
(i386_gdbarch_sse_unit_init): Likewise.
(gdbarch_tdep): Add sse_unit.
(I386_MAX_REGISTER_SIZE): Increase to 32.

* i387-tdep.c (i387_supply_fxsave): Assert sse_unit on SSE
registers.

* defs.h (MAX_REGISTER_SIZE): Increase to 32.

* regformats/reg-i386-avx.dat: New.
* regformats/reg-i386-avx-linux.dat: Likewise.
* regformats/reg-x86-64-avx.dat: Likewise.
* regformats/reg-x86-64-avx-linux.dat: Likewise.

* regformats/reg-x86-64.dat: Add xmlarch.

gdb/gdbserver/

2008-09-18 H.J. Lu <hongjiu.lu@intel.com>

* configure.srv (srv_regobj): Add reg-i386-avx-linux.o for
i[34567]86-*-linux*. Add reg-x86-64-avx-linux.o for
x86_64-*-linux*.

* i387-fp.c (x86_sse_unit): New.
(x86_get_sse_unit): Likewise.
(i387_cache_to_fsave): Handle x86_sse_unit.
(i387_fxsave_to_cache): Likewise.

* i387-fp.h (x86_sse_unit): New.
(x86_get_sse_unit): Likewise.

* linux-i386-low.c (init_registers_i386_avx_linux): Declared.
(i386_arch_setup): New.
(the_low_target): Replace init_registers_i386_linux with
i386_arch_setup.

* linux-x86-64-low.c (init_registers_x86_64_avx_linux): New.
(x86_64_arch_setup): New.
(the_low_target): Replace init_registers_x86_64_linux with
x86_64_arch_setup.

* Makefile.in (clean): Also remove reg-i386-avx.c,
reg-i386-linux-avx.c, reg-x86-64-avx.c and
reg-x86-64-avx-linux.c.
(reg-i386-avx.o): New target.
(reg-i386-avx.c): Likewise.
(reg-i386-avx-linux.o): Likewise.
(reg-i386-avx-linux.c): Likewise.
(reg-x86-64-avx.o): Likewise.
(reg-x86-64-avx.c): Likewise.
(reg-x86-64-avx-linux.o): Likewise.
(reg-x86-64-avx-linux.c): Likewise.

Index: i387-tdep.c
===================================================================
--- i387-tdep.c (.../fsf/trunk/gdb) (revision 3974)
+++ i387-tdep.c (.../branches/avx/gdb) (revision 3974)
@@ -593,7 +593,10 @@ i387_supply_fxsave (struct regcache *reg
regcache_raw_supply (regcache, i, val);
}
else
- regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ {
+ gdb_assert (tdep->sse_unit == sse);
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ }
}

if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
Index: amd64-tdep.c
===================================================================
--- amd64-tdep.c (.../fsf/trunk/gdb) (revision 3974)
+++ amd64-tdep.c (.../branches/avx/gdb) (revision 3974)
@@ -49,7 +49,7 @@

/* Register information. */

-static const char *amd64_register_names[] =
+static const char *amd64_sse_register_names[] =
{
"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp",

@@ -64,11 +64,31 @@ static const char *amd64_register_names[
/* %xmm0 is register number 40. */
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+
+ "mxcsr",
+};
+
+static const char *amd64_avx_register_names[] =
+{
+ "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp",
+
+ /* %r8 is indeed register number 8. */
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "rip", "eflags", "cs", "ss", "ds", "es", "fs", "gs",
+
+ /* %st0 is register number 24. */
+ "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7",
+ "fctrl", "fstat", "ftag", "fiseg", "fioff", "foseg", "fooff", "fop",
+
+ /* %ymm0 is register number 40. */
+ "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
+ "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15",
+
"mxcsr",
};

/* Total number of registers. */
-#define AMD64_NUM_REGS ARRAY_SIZE (amd64_register_names)
+#define AMD64_NUM_REGS ARRAY_SIZE (amd64_sse_register_names)

/* Return the name of register REGNUM. */

@@ -76,7 +96,19 @@ const char *
amd64_register_name (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= 0 && regnum < AMD64_NUM_REGS)
- return amd64_register_names[regnum];
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ switch (tdep->sse_unit)
+ {
+ case sse:
+ return amd64_sse_register_names[regnum];
+ case avx:
+ return amd64_avx_register_names[regnum];
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Unsupported vector unit."));
+ }
+ }

return NULL;
}
@@ -1307,6 +1339,7 @@ amd64_init_abi (struct gdbarch_info info
/* AMD64 has an FPU and 16 SSE registers. */
tdep->st0_regnum = AMD64_ST0_REGNUM;
tdep->num_xmm_regs = 16;
+ i386_gdbarch_sse_unit_init (&info, tdep);

/* This is what all the fuss is about. */
set_gdbarch_long_bit (gdbarch, 64);
Index: amd64-tdep.h
===================================================================
--- amd64-tdep.h (.../fsf/trunk/gdb) (revision 3974)
+++ amd64-tdep.h (.../branches/avx/gdb) (revision 3974)
@@ -66,6 +66,14 @@ enum amd64_regnum
/* Number of general purpose registers. */
#define AMD64_NUM_GREGS 24

+/* The g/G packet size for SSE target. */
+#define AMD64_G_PACKET_SIZE_SSE \
+ (17 * 8 + 7 * 4 + 8 * 10 + 8 * 4 + 16 * 16 + 4)
+
+/* The g/G packet size for SSE target. */
+#define AMD64_G_PACKET_SIZE_AVX \
+ (17 * 8 + 7 * 4 + 8 * 10 + 8 * 4 + 16 * 32 + 4)
+
extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);

/* Functions from amd64-tdep.c which may be needed on architectures
Index: amd64-linux-tdep.c
===================================================================
--- amd64-linux-tdep.c (.../fsf/trunk/gdb) (revision 3974)
+++ amd64-linux-tdep.c (.../branches/avx/gdb) (revision 3974)
@@ -286,6 +286,10 @@ amd64_linux_init_abi (struct gdbarch_inf
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
+
+ i386_register_g_packet_guesses (gdbarch,
+ AMD64_G_PACKET_SIZE_SSE + 8,
+ AMD64_G_PACKET_SIZE_AVX + 8);
}
\f

Index: i386-linux-tdep.c
===================================================================
--- i386-linux-tdep.c (.../fsf/trunk/gdb) (revision 3974)
+++ i386-linux-tdep.c (.../branches/avx/gdb) (revision 3974)
@@ -469,6 +469,10 @@ i386_linux_init_abi (struct gdbarch_info
simple_displaced_step_free_closure);
set_gdbarch_displaced_step_location (gdbarch,
displaced_step_at_entry_point);
+
+ i386_register_g_packet_guesses (gdbarch,
+ I386_G_PACKET_SIZE_SSE + 4,
+ I386_G_PACKET_SIZE_AVX + 4);
}

/* Provide a prototype to silence -Wmissing-prototypes. */
Index: regformats/reg-x86-64-avx-linux.dat
===================================================================
--- regformats/reg-x86-64-avx-linux.dat (.../fsf/trunk/gdb) (revision 0)
+++ regformats/reg-x86-64-avx-linux.dat (.../branches/avx/gdb) (revision 3974)
@@ -0,0 +1,60 @@
+name:x86_64_avx_linux
+expedite:rbp,rsp,rip
+64:rax
+64:rbx
+64:rcx
+64:rdx
+64:rsi
+64:rdi
+64:rbp
+64:rsp
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:rip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+256:ymm0
+256:ymm1
+256:ymm2
+256:ymm3
+256:ymm4
+256:ymm5
+256:ymm6
+256:ymm7
+256:ymm8
+256:ymm9
+256:ymm10
+256:ymm11
+256:ymm12
+256:ymm13
+256:ymm14
+256:ymm15
+32:mxcsr
+64:orig_rax
Index: regformats/reg-x86-64-avx.dat
===================================================================
--- regformats/reg-x86-64-avx.dat (.../fsf/trunk/gdb) (revision 0)
+++ regformats/reg-x86-64-avx.dat (.../branches/avx/gdb) (revision 3974)
@@ -0,0 +1,59 @@
+name:x86_64_avx
+expedite:rbp,rsp,rip
+64:rax
+64:rbx
+64:rcx
+64:rdx
+64:rsi
+64:rdi
+64:rbp
+64:rsp
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:rip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+256:ymm0
+256:ymm1
+256:ymm2
+256:ymm3
+256:ymm4
+256:ymm5
+256:ymm6
+256:ymm7
+256:ymm8
+256:ymm9
+256:ymm10
+256:ymm11
+256:ymm12
+256:ymm13
+256:ymm14
+256:ymm15
+32:mxcsr
Index: regformats/reg-x86-64.dat
===================================================================
--- regformats/reg-x86-64.dat (.../fsf/trunk/gdb) (revision 3974)
+++ regformats/reg-x86-64.dat (.../branches/avx/gdb) (revision 3974)
@@ -1,4 +1,5 @@
name:x86_64
+xmlarch:i386:x86-64
expedite:rbp,rsp,rip
64:rax
64:rbx
Index: regformats/reg-i386-avx-linux.dat
===================================================================
--- regformats/reg-i386-avx-linux.dat (.../fsf/trunk/gdb) (revision 0)
+++ regformats/reg-i386-avx-linux.dat (.../branches/avx/gdb) (revision 3974)
@@ -0,0 +1,44 @@
+name:i386_avx_linux
+expedite:ebp,esp,eip
+32:eax
+32:ecx
+32:edx
+32:ebx
+32:esp
+32:ebp
+32:esi
+32:edi
+32:eip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+256:ymm0
+256:ymm1
+256:ymm2
+256:ymm3
+256:ymm4
+256:ymm5
+256:ymm6
+256:ymm7
+32:mxcsr
+32:orig_eax
Index: regformats/reg-i386-avx.dat
===================================================================
--- regformats/reg-i386-avx.dat (.../fsf/trunk/gdb) (revision 0)
+++ regformats/reg-i386-avx.dat (.../branches/avx/gdb) (revision 3974)
@@ -0,0 +1,43 @@
+name:i386_avx
+expedite:ebp,esp,eip
+32:eax
+32:ecx
+32:edx
+32:ebx
+32:esp
+32:ebp
+32:esi
+32:edi
+32:eip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+256:ymm0
+256:ymm1
+256:ymm2
+256:ymm3
+256:ymm4
+256:ymm5
+256:ymm6
+256:ymm7
+32:mxcsr
Index: gdbserver/Makefile.in
===================================================================
--- gdbserver/Makefile.in (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/Makefile.in (.../branches/avx/gdb) (revision 3974)
@@ -226,6 +226,8 @@ clean:
rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c
rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c
rm -f powerpc-vsx64l.c xml-builtin.c stamp-xml
+ rm -f reg-i386-avx.c reg-i386-linux-avx.c
+ rm -f reg-x86-64-avx.c reg-x86-64-avx-linux.c

maintainer-clean realclean distclean: clean
rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@@ -348,6 +350,12 @@ reg-i386.c : $(srcdir)/../regformats/reg
reg-i386-linux.o : reg-i386-linux.c $(regdef_h)
reg-i386-linux.c : $(srcdir)/../regformats/reg-i386-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-i386-linux.dat reg-i386-linux.c
+reg-i386-avx.o : reg-i386-avx.c $(regdef_h)
+reg-i386-avx.c : $(srcdir)/../regformats/reg-i386-avx.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-i386-avx.dat reg-i386-avx.c
+reg-i386-avx-linux.o : reg-i386-avx-linux.c $(regdef_h)
+reg-i386-avx-linux.c : $(srcdir)/../regformats/reg-i386-avx-linux.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-i386-avx-linux.dat reg-i386-avx-linux.c
reg-ia64.o : reg-ia64.c $(regdef_h)
reg-ia64.c : $(srcdir)/../regformats/reg-ia64.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-ia64.dat reg-ia64.c
@@ -402,6 +410,12 @@ reg-x86-64.c : $(srcdir)/../regformats/r
reg-x86-64-linux.o : reg-x86-64-linux.c $(regdef_h)
reg-x86-64-linux.c : $(srcdir)/../regformats/reg-x86-64-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-x86-64-linux.dat reg-x86-64-linux.c
+reg-x86-64-avx.o : reg-x86-64-avx.c $(regdef_h)
+reg-x86-64-avx.c : $(srcdir)/../regformats/reg-x86-64-avx.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-x86-64.dat reg-x86-64-avx.c
+reg-x86-64-avx-linux.o : reg-x86-64-avx-linux.c $(regdef_h)
+reg-x86-64-avx-linux.c : $(srcdir)/../regformats/reg-x86-64-linux.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-x86-64-avx-linux.dat reg-x86-64-avx-linux.c
reg-xtensa.o : reg-xtensa.c $(regdef_h)
reg-xtensa.c : $(srcdir)/../regformats/reg-xtensa.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-xtensa.dat reg-xtensa.c
Index: gdbserver/configure.srv
===================================================================
--- gdbserver/configure.srv (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/configure.srv (.../branches/avx/gdb) (revision 3974)
@@ -55,7 +55,7 @@ case "${target}" in
i[34567]86-*-cygwin*) srv_regobj=reg-i386.o
srv_tgtobj="win32-low.o win32-i386-low.o"
;;
- i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
+ i[34567]86-*-linux*) srv_regobj="reg-i386-linux.o reg-i386-avx-linux.o"
srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
@@ -142,7 +142,7 @@ case "${target}" in
spu*-*-*) srv_regobj=reg-spu.o
srv_tgtobj="spu-low.o"
;;
- x86_64-*-linux*) srv_regobj=reg-x86-64-linux.o
+ x86_64-*-linux*) srv_regobj="reg-x86-64-linux.o reg-x86-64-avx-linux.o"
srv_tgtobj="linux-low.o linux-x86-64-low.o i387-fp.o"
srv_linux_regsets=yes
srv_linux_thread_db=yes
Index: gdbserver/linux-i386-low.c
===================================================================
--- gdbserver/linux-i386-low.c (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/linux-i386-low.c (.../branches/avx/gdb) (revision 3974)
@@ -36,6 +36,8 @@
/* Defined in auto-generated file reg-i386-linux.c. */
void init_registers_i386_linux (void);

+/* Defined in auto-generated file reg-i386-avx-linux.c. */
+void init_registers_i386_avx_linux (void);

/* This module only supports access to the general purpose registers. */

@@ -188,8 +190,17 @@ i386_breakpoint_at (CORE_ADDR pc)
return 0;
}

+static void
+i386_arch_setup (void)
+{
+ if (x86_get_sse_unit () == avx)
+ init_registers_i386_avx_linux ();
+ else
+ init_registers_i386_linux ();
+}
+
struct linux_target_ops the_low_target = {
- init_registers_i386_linux,
+ i386_arch_setup,
i386_num_regs,
i386_regmap,
i386_cannot_fetch_register,
Index: gdbserver/i387-fp.c
===================================================================
--- gdbserver/i387-fp.c (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/i387-fp.c (.../branches/avx/gdb) (revision 3974)
@@ -72,6 +72,16 @@ struct i387_fxsave {
unsigned char xmm_space[256];
};

+static enum x86_sse_unit x86_sse_unit = unknown;
+
+enum x86_sse_unit
+x86_get_sse_unit (void)
+{
+ if (x86_sse_unit == unknown)
+ x86_sse_unit = sse;
+ return x86_sse_unit;
+}
+
void
i387_cache_to_fsave (void *buf)
{
@@ -152,13 +162,38 @@ i387_cache_to_fxsave (void *buf)
struct i387_fxsave *fp = (struct i387_fxsave *) buf;
int i;
int st0_regnum = find_regno ("st0");
- int xmm0_regnum = find_regno ("xmm0");
unsigned long val, val2;

for (i = 0; i < 8; i++)
collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
- for (i = 0; i < num_xmm_registers; i++)
- collect_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+ switch (x86_sse_unit)
+ {
+ case sse:
+ {
+ int xmm0_regnum = find_regno ("xmm0");
+ for (i = 0; i < num_xmm_registers; i++)
+ collect_register (i + xmm0_regnum,
+ ((char *) &fp->xmm_space[0]) + i * 16);
+ }
+ break;
+ case avx:
+ {
+ int ymm0_regnum = find_regno ("ymm0");
+ int fake_ymm[8];
+
+ /* FIMXE: Since we can't set YMM registers, we just fake it
+ with xmm registers. */
+ for (i = 0; i < num_xmm_registers; i++)
+ {
+ collect_register (i + ymm0_regnum, fake_ymm);
+ memcpy (((char *) &fp->xmm_space[0]) + i * 16, fake_ymm, 16);
+ }
+ }
+ break;
+ default:
+ fatal ("i387_cache_to_fxsave: Unsupported sse unit");
+ }

collect_register_by_name ("fioff", &fp->fioff);
collect_register_by_name ("fooff", &fp->fooff);
@@ -248,13 +283,38 @@ i387_fxsave_to_cache (const void *buf)
struct i387_fxsave *fp = (struct i387_fxsave *) buf;
int i, top;
int st0_regnum = find_regno ("st0");
- int xmm0_regnum = find_regno ("xmm0");
unsigned long val;

for (i = 0; i < 8; i++)
supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
- for (i = 0; i < num_xmm_registers; i++)
- supply_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+ switch (x86_sse_unit)
+ {
+ case sse:
+ {
+ int xmm0_regnum = find_regno ("xmm0");
+ for (i = 0; i < num_xmm_registers; i++)
+ supply_register (i + xmm0_regnum,
+ ((char *) &fp->xmm_space[0]) + i * 16);
+ }
+ break;
+ case avx:
+ {
+ int ymm0_regnum = find_regno ("ymm0");
+ int fake_ymm[8] = { 0, 0, 0, 0, -1, -1, -1, -1 };
+
+ /* FIMXE: Since we can't get YMM registers, we just fake it
+ with xmm registers and set the upper 128bits to all 1s. */
+ for (i = 0; i < num_xmm_registers; i++)
+ {
+ memcpy (fake_ymm, ((char *) &fp->xmm_space[0]) + i * 16, 16);
+ supply_register (i + ymm0_regnum, fake_ymm);
+ }
+ }
+ break;
+ default:
+ fatal ("i387_fxsave_to_cache: Unsupported sse unit");
+ }

supply_register_by_name ("fioff", &fp->fioff);
supply_register_by_name ("fooff", &fp->fooff);
Index: gdbserver/i387-fp.h
===================================================================
--- gdbserver/i387-fp.h (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/i387-fp.h (.../branches/avx/gdb) (revision 3974)
@@ -25,6 +25,15 @@ void i387_fsave_to_cache (const void *bu
void i387_cache_to_fxsave (void *buf);
void i387_fxsave_to_cache (const void *buf);

+enum x86_sse_unit
+{
+ unknown,
+ sse,
+ avx
+};
+
+enum x86_sse_unit x86_get_sse_unit (void);
+
extern int num_xmm_registers;

#endif /* I387_FP_H */
Index: gdbserver/linux-x86-64-low.c
===================================================================
--- gdbserver/linux-x86-64-low.c (.../fsf/trunk/gdb) (revision 3974)
+++ gdbserver/linux-x86-64-low.c (.../branches/avx/gdb) (revision 3974)
@@ -27,6 +27,9 @@
/* Defined in auto-generated file reg-x86-64-linux.c. */
void init_registers_x86_64_linux (void);

+/* Defined in auto-generated file reg-x86-64-avx-linux.c. */
+void init_registers_x86_64_avx_linux (void);
+
#include <sys/reg.h>
#include <sys/procfs.h>
#include <sys/ptrace.h>
@@ -162,8 +165,17 @@ x86_64_breakpoint_at (CORE_ADDR pc)
return 0;
}

+static void
+x86_64_arch_setup (void)
+{
+ if (x86_get_sse_unit () == avx)
+ init_registers_x86_64_avx_linux ();
+ else
+ init_registers_x86_64_linux ();
+}
+
struct linux_target_ops the_low_target = {
- init_registers_x86_64_linux,
+ x86_64_arch_setup,
-1,
NULL,
NULL,
Index: i386-tdep.c
===================================================================
--- i386-tdep.c (.../fsf/trunk/gdb) (revision 3974)
+++ i386-tdep.c (.../branches/avx/gdb) (revision 3974)
@@ -49,9 +49,20 @@
#include "i386-tdep.h"
#include "i387-tdep.h"

+#include "remote.h"
+#include "target-descriptions.h"
+
+/* Properties (for struct target_desc) describing the g/G packet
+ layout. */
+#define I386_PROPERTY_SSE "internal: transfers-sse-registers"
+#define I386_PROPERTY_AVX "internal: transfers-avx-registers"
+
+static struct target_desc *i386_tdesc_sse;
+static struct target_desc *i386_tdesc_avx;
+
/* Register names. */

-static char *i386_register_names[] =
+static char *i386_sse_register_names[] =
{
"eax", "ecx", "edx", "ebx",
"esp", "ebp", "esi", "edi",
@@ -66,7 +77,23 @@ static char *i386_register_names[] =
"mxcsr"
};

-static const int i386_num_register_names = ARRAY_SIZE (i386_register_names);
+static char *i386_avx_register_names[] =
+{
+ "eax", "ecx", "edx", "ebx",
+ "esp", "ebp", "esi", "edi",
+ "eip", "eflags", "cs", "ss",
+ "ds", "es", "fs", "gs",
+ "st0", "st1", "st2", "st3",
+ "st4", "st5", "st6", "st7",
+ "fctrl", "fstat", "ftag", "fiseg",
+ "fioff", "foseg", "fooff", "fop",
+ "ymm0", "ymm1", "ymm2", "ymm3",
+ "ymm4", "ymm5", "ymm6", "ymm7",
+ "mxcsr"
+};
+
+static const int i386_num_register_names
+ = ARRAY_SIZE (i386_sse_register_names);

/* Register names for MMX pseudo-registers. */

@@ -149,7 +176,19 @@ i386_register_name (struct gdbarch *gdba
return i386_mmx_names[regnum - I387_MM0_REGNUM (gdbarch_tdep (gdbarch))];

if (regnum >= 0 && regnum < i386_num_register_names)
- return i386_register_names[regnum];
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ switch (tdep->sse_unit)
+ {
+ case sse:
+ return i386_sse_register_names[regnum];
+ case avx:
+ return i386_avx_register_names[regnum];
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Unsupported vector unit."));
+ }
+ }

return NULL;
}
@@ -2046,49 +2085,110 @@ i386_mmx_type (struct gdbarch *gdbarch)
return tdep->i386_mmx_type;
}

-struct type *
-i386_sse_type (struct gdbarch *gdbarch)
+static struct type *
+i386_vec128_type (struct gdbarch *gdbarch)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec128i
+ {
+ int128_t uint128;
+ int64_t v2_int64[2];
+ int32_t v4_int32[4];
+ int16_t v8_int16[8];
+ int8_t v16_int8[16];
+ double v2_double[2];
+ float v4_float[4];
+ };
+#endif

- if (!tdep->i386_sse_type)
- {
- /* The type we're building is this: */
+ struct type *t;
+
+ t = init_composite_type ("__gdb_builtin_type_vec128i",
+ TYPE_CODE_UNION);
+ append_composite_type_field (t, "v4_float",
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_float, 4));
+ append_composite_type_field (t, "v2_double",
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_double, 2));
+ append_composite_type_field (t, "v16_int8",
+ init_vector_type (builtin_type_int8, 16));
+ append_composite_type_field (t, "v8_int16",
+ init_vector_type (builtin_type_int16, 8));
+ append_composite_type_field (t, "v4_int32",
+ init_vector_type (builtin_type_int32, 4));
+ append_composite_type_field (t, "v2_int64",
+ init_vector_type (builtin_type_int64, 2));
+ append_composite_type_field (t, "uint128", builtin_type_int128);
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_vec128i";
+ return t;
+}
+
+static struct type *
+i386_vec256_type (struct gdbarch *gdbarch)
+{
+ /* The type we're building is this: */
#if 0
- union __gdb_builtin_type_vec128i
- {
- int128_t uint128;
- int64_t v2_int64[2];
- int32_t v4_int32[4];
- int16_t v8_int16[8];
- int8_t v16_int8[16];
- double v2_double[2];
- float v4_float[4];
- };
+ union __gdb_builtin_type_vec256i
+ {
+ int128_t v2_int128[2];
+ int64_t v4_int64[4];
+ int32_t v8_int32[8];
+ int16_t v16_int16[16];
+ int8_t v32_int8[32];
+ double v4_double[4];
+ float v8_float[8];
+ };
#endif

- struct type *t;
+ struct type *t;

- t = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
- append_composite_type_field (t, "v4_float",
- init_vector_type (builtin_type (gdbarch)
- ->builtin_float, 4));
- append_composite_type_field (t, "v2_double",
- init_vector_type (builtin_type (gdbarch)
- ->builtin_double, 2));
- append_composite_type_field (t, "v16_int8",
- init_vector_type (builtin_type_int8, 16));
- append_composite_type_field (t, "v8_int16",
- init_vector_type (builtin_type_int16, 8));
- append_composite_type_field (t, "v4_int32",
- init_vector_type (builtin_type_int32, 4));
- append_composite_type_field (t, "v2_int64",
- init_vector_type (builtin_type_int64, 2));
- append_composite_type_field (t, "uint128", builtin_type_int128);
+ t = init_composite_type ("__gdb_builtin_type_vec256i",
+ TYPE_CODE_UNION);
+ append_composite_type_field (t, "v8_float",
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_float, 8));
+ append_composite_type_field (t, "v4_double",
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_double, 4));
+ append_composite_type_field (t, "v32_int8",
+ init_vector_type (builtin_type_int8, 32));
+ append_composite_type_field (t, "v16_int16",
+ init_vector_type (builtin_type_int16, 16));
+ append_composite_type_field (t, "v8_int32",
+ init_vector_type (builtin_type_int32, 8));
+ append_composite_type_field (t, "v4_int64",
+ init_vector_type (builtin_type_int64, 4));
+ append_composite_type_field (t, "v2_int128",
+ init_vector_type (builtin_type_int128, 2));
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_vec256i";
+ return t;
+}

- TYPE_VECTOR (t) = 1;
- TYPE_NAME (t) = "builtin_type_vec128i";
- tdep->i386_sse_type = t;
+struct type *
+i386_sse_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->i386_sse_type)
+ {
+ switch (tdep->sse_unit)
+ {
+ case sse:
+ tdep->i386_sse_type = i386_vec128_type (gdbarch);
+ break;
+ case avx:
+ tdep->i386_sse_type = i386_vec256_type (gdbarch);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Unsupported vector unit."));
+ }
}

return tdep->i386_sse_type;
@@ -2627,6 +2727,58 @@ i386_fetch_pointer_argument (struct fram
}

static void
+i386_init_tdesc (void)
+{
+ /* Create feature sets with the appropriate properties. The values
+ are not important. */
+ i386_tdesc_sse = allocate_target_description ();
+ set_tdesc_property (i386_tdesc_sse, I386_PROPERTY_SSE, "");
+
+ i386_tdesc_avx = allocate_target_description ();
+ set_tdesc_property (i386_tdesc_avx, I386_PROPERTY_AVX, "");
+}
+
+void
+i386_register_g_packet_guesses (struct gdbarch *gdbarch,
+ int sse_unit_bytes,
+ int avx_unit_bytes)
+{
+ /* If the size matches the set of SSE registers, we are talking to
+ an SSE remote target. */
+ register_remote_g_packet_guess (gdbarch,
+ sse_unit_bytes,
+ i386_tdesc_sse);
+
+ /* If the size matches the set of AVX registers, we are talking to
+ an AVX remote target. */
+ register_remote_g_packet_guess (gdbarch,
+ avx_unit_bytes,
+ i386_tdesc_avx);
+}
+
+void
+i386_gdbarch_sse_unit_init (struct gdbarch_info *info,
+ struct gdbarch_tdep *tdep)
+{
+ if (info->target_desc)
+ {
+ if (tdesc_property (info->target_desc, I386_PROPERTY_AVX))
+ tdep->sse_unit = avx;
+#if 0
+ /* There is no need to check I386_PROPERTY_SSE. We keep it for
+ completeness. */
+ else if (tdesc_property (info->target_desc, I386_PROPERTY_SSE))
+ tdep->sse_unit = sse;
+#endif
+ else
+ tdep->sse_unit = sse;
+ }
+ else if (tdep->sse_unit == unknown)
+ /* FIXME: We need to set it based on native environment. */
+ tdep->sse_unit = sse;
+}
+
+static void
i386_skip_permanent_breakpoint (struct regcache *regcache)
{
CORE_ADDR current_pc = regcache_read_pc (regcache);
@@ -2687,6 +2839,7 @@ i386_gdbarch_init (struct gdbarch_info i

/* I386_NUM_XREGS includes %mxcsr, so substract one. */
tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+ i386_gdbarch_sse_unit_init (&info, tdep);

tdep->jb_pc_offset = -1;
tdep->struct_return = pcc_struct_return;
@@ -2829,6 +2982,10 @@ i386_gdbarch_init (struct gdbarch_info i
set_gdbarch_skip_permanent_breakpoint (gdbarch,
i386_skip_permanent_breakpoint);

+ i386_register_g_packet_guesses (gdbarch,
+ I386_G_PACKET_SIZE_SSE,
+ I386_G_PACKET_SIZE_AVX);
+
return gdbarch;
}

@@ -2884,4 +3041,6 @@ is \"default\"."),
/* Initialize the i386-specific register groups & types. */
i386_init_reggroups ();
i386_init_types();
+
+ i386_init_tdesc ();
}
Index: i386-tdep.h
===================================================================
--- i386-tdep.h (.../fsf/trunk/gdb) (revision 3974)
+++ i386-tdep.h (.../branches/avx/gdb) (revision 3974)
@@ -53,6 +53,13 @@ enum struct_return
reg_struct_return /* Return "short" structures in registers. */
};

+enum x86_sse_unit
+{
+ unknown,
+ sse,
+ avx
+};
+
/* i386 architecture specific information. */
struct gdbarch_tdep
{
@@ -78,6 +85,9 @@ struct gdbarch_tdep
/* Number of SSE registers. */
int num_xmm_regs;

+ /* SSE unit. */
+ enum x86_sse_unit sse_unit;
+
/* Offset of saved PC in jmp_buf. */
int jb_pc_offset;

@@ -150,7 +160,15 @@ enum i386_regnum
+ I386_NUM_XREGS)

/* Size of the largest register. */
-#define I386_MAX_REGISTER_SIZE 16
+#define I386_MAX_REGISTER_SIZE 32
+
+/* The g/G packet size for SSE target. */
+#define I386_G_PACKET_SIZE_SSE \
+ (9 * 4 + 7 * 4 + 8 * 10 + 8 * 4 + 8 * 16 + 4)
+
+/* The g/G packet size for SSE target. */
+#define I386_G_PACKET_SIZE_AVX \
+ (9 * 4 + 7 * 4 + 8 * 10 + 8 * 4 + 8 * 32 + 4)

/* Types for i386-specific registers. */
extern struct type *i386_eflags_type;
@@ -159,6 +177,10 @@ extern struct type *i386_mxcsr_type;
extern struct type *i386_mmx_type (struct gdbarch *gdbarch);
extern struct type *i386_sse_type (struct gdbarch *gdbarch);

+extern void i386_register_g_packet_guesses (struct gdbarch *, int, int);
+extern void i386_gdbarch_sse_unit_init (struct gdbarch_info *info,
+ struct gdbarch_tdep *tdep);
+
/* Segment selectors. */
#define I386_SEL_RPL 0x0003 /* Requester's Privilege Level mask. */
#define I386_SEL_UPL 0x0003 /* User Privilige Level. */
Index: defs.h
===================================================================
--- defs.h (.../fsf/trunk/gdb) (revision 3974)
+++ defs.h (.../branches/avx/gdb) (revision 3974)
@@ -982,7 +982,7 @@ extern void *alloca ();
/* Maximum size of a register. Something small, but large enough for
all known ISAs. If it turns out to be too small, make it bigger. */

-enum { MAX_REGISTER_SIZE = 16 };
+enum { MAX_REGISTER_SIZE = 32 };

/* Static target-system-dependent parameters for GDB. */