#include "i386-tdep.h"
#include "i387-tdep.h"
+#include "i386-xstate.h"
#include "record.h"
#include <stdint.h>
#include "features/i386/i386.c"
+#include "features/i386/i386-avx.c"
+#include "features/i386/i386-mmx.c"
/* Register names. */
"mxcsr"
};
+static const char *i386_ymm_names[] =
+{
+ "ymm0", "ymm1", "ymm2", "ymm3",
+ "ymm4", "ymm5", "ymm6", "ymm7",
+};
+
+static const char *i386_ymmh_names[] =
+{
+ "ymm0h", "ymm1h", "ymm2h", "ymm3h",
+ "ymm4h", "ymm5h", "ymm6h", "ymm7h",
+};
+
/* Register names for MMX pseudo-registers. */
static const char *i386_mmx_names[] =
return regnum >= 0 && regnum < tdep->num_dword_regs;
}
+int
+i386_ymmh_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ymm0h_regnum = tdep->ymm0h_regnum;
+
+ if (ymm0h_regnum < 0)
+ return 0;
+
+ regnum -= ymm0h_regnum;
+ return regnum >= 0 && regnum < tdep->num_ymm_regs;
+}
+
+/* AVX register? */
+
+int
+i386_ymm_regnum_p (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ymm0_regnum = tdep->ymm0_regnum;
+
+ if (ymm0_regnum < 0)
+ return 0;
+
+ regnum -= ymm0_regnum;
+ return regnum >= 0 && regnum < tdep->num_ymm_regs;
+}
+
/* SSE register? */
-static int
-i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
+int
+i386_xmm_regnum_p (struct gdbarch *gdbarch, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int num_xmm_regs = I387_NUM_XMM_REGS (tdep);
- if (I387_NUM_XMM_REGS (tdep) == 0)
+ if (num_xmm_regs == 0)
return 0;
- return (I387_XMM0_REGNUM (tdep) <= regnum
- && regnum < I387_MXCSR_REGNUM (tdep));
+ regnum -= I387_XMM0_REGNUM (tdep);
+ return regnum >= 0 && regnum < num_xmm_regs;
}
static int
&& regnum < I387_XMM0_REGNUM (tdep));
}
+/* Return the name of register REGNUM, or the empty string if it is
+ an anonymous register. */
+
+static const char *
+i386_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ /* Hide the upper YMM registers. */
+ if (i386_ymmh_regnum_p (gdbarch, regnum))
+ return "";
+
+ return tdesc_register_name (gdbarch, regnum);
+}
+
/* Return the name of register REGNUM. */
const char *
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (i386_mmx_regnum_p (gdbarch, regnum))
return i386_mmx_names[regnum - I387_MM0_REGNUM (tdep)];
+ else if (i386_ymm_regnum_p (gdbarch, regnum))
+ return i386_ymm_names[regnum - tdep->ymm0_regnum];
else if (i386_byte_regnum_p (gdbarch, regnum))
return i386_byte_names[regnum - tdep->al_regnum];
else if (i386_word_regnum_p (gdbarch, regnum))
else if (reg >= 21 && reg <= 28)
{
/* SSE registers. */
- return reg - 21 + I387_XMM0_REGNUM (tdep);
+ int ymm0_regnum = tdep->ymm0_regnum;
+
+ if (ymm0_regnum >= 0
+ && i386_xmm_regnum_p (gdbarch, reg))
+ return reg - 21 + ymm0_regnum;
+ else
+ return reg - 21 + I387_XMM0_REGNUM (tdep);
}
else if (reg >= 29 && reg <= 36)
{
return tdep->i387_ext_type;
}
+/* Construct vector type for pseudo YMM registers. We can't use
+ tdesc_find_type since YMM isn't described in target description. */
+
+static struct type *
+i386_ymm_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->i386_ymm_type)
+ {
+ const struct builtin_type *bt = builtin_type (gdbarch);
+
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec256i
+ {
+ int128_t uint128[2];
+ int64_t v2_int64[4];
+ int32_t v4_int32[8];
+ int16_t v8_int16[16];
+ int8_t v16_int8[32];
+ double v2_double[4];
+ float v4_float[8];
+ };
+#endif
+
+ struct type *t;
+
+ t = arch_composite_type (gdbarch,
+ "__gdb_builtin_type_vec256i", TYPE_CODE_UNION);
+ append_composite_type_field (t, "v8_float",
+ init_vector_type (bt->builtin_float, 8));
+ append_composite_type_field (t, "v4_double",
+ init_vector_type (bt->builtin_double, 4));
+ append_composite_type_field (t, "v32_int8",
+ init_vector_type (bt->builtin_int8, 32));
+ append_composite_type_field (t, "v16_int16",
+ init_vector_type (bt->builtin_int16, 16));
+ append_composite_type_field (t, "v8_int32",
+ init_vector_type (bt->builtin_int32, 8));
+ append_composite_type_field (t, "v4_int64",
+ init_vector_type (bt->builtin_int64, 4));
+ append_composite_type_field (t, "v2_int128",
+ init_vector_type (bt->builtin_int128, 2));
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "builtin_type_vec128i";
+ tdep->i386_ymm_type = t;
+ }
+
+ return tdep->i386_ymm_type;
+}
+
/* Construct vector type for MMX registers. */
static struct type *
i386_mmx_type (struct gdbarch *gdbarch)
{
if (i386_mmx_regnum_p (gdbarch, regnum))
return i386_mmx_type (gdbarch);
+ else if (i386_ymm_regnum_p (gdbarch, regnum))
+ return i386_ymm_type (gdbarch);
else
{
const struct builtin_type *bt = builtin_type (gdbarch);
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (i386_word_regnum_p (gdbarch, regnum))
+ if (i386_ymm_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->ymm0_regnum;
+
+ /* Extract (always little endian). Read lower 128bits. */
+ regcache_raw_read (regcache,
+ I387_XMM0_REGNUM (tdep) + regnum,
+ raw_buf);
+ memcpy (buf, raw_buf, 16);
+ /* Read upper 128bits. */
+ regcache_raw_read (regcache,
+ tdep->ymm0h_regnum + regnum,
+ raw_buf);
+ memcpy (buf + 16, raw_buf, 16);
+ }
+ else if (i386_word_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->ax_regnum;
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (i386_word_regnum_p (gdbarch, regnum))
+ if (i386_ymm_regnum_p (gdbarch, regnum))
+ {
+ regnum -= tdep->ymm0_regnum;
+
+ /* ... Write lower 128bits. */
+ regcache_raw_write (regcache,
+ I387_XMM0_REGNUM (tdep) + regnum,
+ buf);
+ /* ... Write upper 128bits. */
+ regcache_raw_write (regcache,
+ tdep->ymm0h_regnum + regnum,
+ buf + 16);
+ }
+ else if (i386_word_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->ax_regnum;
i387_collect_fsave (regcache, regnum, fpregs);
}
+/* Similar to i386_supply_fpregset, but use XSAVE extended state. */
+
+static void
+i386_supply_xstateregset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *xstateregs, size_t len)
+{
+ i387_supply_xsave (regcache, regnum, xstateregs);
+}
+
+/* Similar to i386_collect_fpregset , but use XSAVE extended state. */
+
+static void
+i386_collect_xstateregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *xstateregs, size_t len)
+{
+ i387_collect_xsave (regcache, regnum, xstateregs, 1);
+}
+
/* Return the appropriate register set for the core section identified
by SECT_NAME and SECT_SIZE. */
return tdep->fpregset;
}
+ if (strcmp (sect_name, ".reg-xstate") == 0)
+ {
+ if (tdep->xstateregset == NULL)
+ tdep->xstateregset = regset_alloc (gdbarch,
+ i386_supply_xstateregset,
+ i386_collect_xstateregset);
+
+ return tdep->xstateregset;
+ }
+
return NULL;
}
\f
tdep->jb_pc_offset = 36;
/* DJGPP does not support the SSE registers. */
- tdep->num_xmm_regs = 0;
- set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I387_NUM_REGS);
+ if (! tdesc_has_registers (info.target_desc))
+ tdep->tdesc = tdesc_i386_mmx;
/* Native compiler is GCC, which uses the SVR4 register numbering
even in COFF and STABS. See the comment in i386_gdbarch_init,
set_gdbarch_sdb_reg_to_regnum. */
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+ set_gdbarch_has_dos_based_file_system (gdbarch, 1);
}
\f
i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
- int sse_regnum_p, fp_regnum_p, mmx_regnum_p, byte_regnum_p,
- word_regnum_p, dword_regnum_p;
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int fp_regnum_p, mmx_regnum_p, xmm_regnum_p, mxcsr_regnum_p,
+ ymm_regnum_p, ymmh_regnum_p;
/* Don't include pseudo registers, except for MMX, in any register
groups. */
- byte_regnum_p = i386_byte_regnum_p (gdbarch, regnum);
- if (byte_regnum_p)
+ if (i386_byte_regnum_p (gdbarch, regnum))
return 0;
- word_regnum_p = i386_word_regnum_p (gdbarch, regnum);
- if (word_regnum_p)
+ if (i386_word_regnum_p (gdbarch, regnum))
return 0;
- dword_regnum_p = i386_dword_regnum_p (gdbarch, regnum);
- if (dword_regnum_p)
+ if (i386_dword_regnum_p (gdbarch, regnum))
return 0;
mmx_regnum_p = i386_mmx_regnum_p (gdbarch, regnum);
if (group == i386_mmx_reggroup)
return mmx_regnum_p;
- sse_regnum_p = (i386_sse_regnum_p (gdbarch, regnum)
- || i386_mxcsr_regnum_p (gdbarch, regnum));
+ xmm_regnum_p = i386_xmm_regnum_p (gdbarch, regnum);
+ mxcsr_regnum_p = i386_mxcsr_regnum_p (gdbarch, regnum);
if (group == i386_sse_reggroup)
- return sse_regnum_p;
+ return xmm_regnum_p || mxcsr_regnum_p;
+
+ ymm_regnum_p = i386_ymm_regnum_p (gdbarch, regnum);
if (group == vector_reggroup)
- return mmx_regnum_p || sse_regnum_p;
+ return (mmx_regnum_p
+ || ymm_regnum_p
+ || mxcsr_regnum_p
+ || (xmm_regnum_p
+ && ((tdep->xcr0 & I386_XSTATE_AVX_MASK)
+ == I386_XSTATE_SSE_MASK)));
fp_regnum_p = (i386_fp_regnum_p (gdbarch, regnum)
|| i386_fpc_regnum_p (gdbarch, regnum));
if (group == float_reggroup)
return fp_regnum_p;
+ /* For "info reg all", don't include upper YMM registers nor XMM
+ registers when AVX is supported. */
+ ymmh_regnum_p = i386_ymmh_regnum_p (gdbarch, regnum);
+ if (group == all_reggroup
+ && ((xmm_regnum_p
+ && (tdep->xcr0 & I386_XSTATE_AVX))
+ || ymmh_regnum_p))
+ return 0;
+
if (group == general_reggroup)
return (!fp_regnum_p
&& !mmx_regnum_p
- && !sse_regnum_p
- && !byte_regnum_p
- && !word_regnum_p
- && !dword_regnum_p);
+ && !mxcsr_regnum_p
+ && !xmm_regnum_p
+ && !ymm_regnum_p
+ && !ymmh_regnum_p);
return default_register_reggroup_p (gdbarch, regnum, group);
}
break;
case 0x0f31: /* rdtsc */
- printf_unfiltered (_("Process record does not support "
- "instruction rdtsc.\n"));
- ir.addr -= 2;
- goto no_support;
+ I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
break;
case 0x0f34: /* sysenter */
record_arch_list_add_reg (ir.regcache, i);
for (i = I387_XMM0_REGNUM (tdep);
- i386_sse_regnum_p (gdbarch, i); i++)
+ i386_xmm_regnum_p (gdbarch, i); i++)
record_arch_list_add_reg (ir.regcache, i);
if (i386_mxcsr_regnum_p (gdbarch, I387_MXCSR_REGNUM(tdep)))
if (i386_record_modrm (&ir))
return -1;
ir.reg |= rex_r;
- if (!i386_sse_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.reg))
+ if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.reg))
goto no_support;
record_arch_list_add_reg (ir.regcache,
I387_XMM0_REGNUM (tdep) + ir.reg);
|| opcode == 0x0f17 || opcode == 0x660f17)
goto no_support;
ir.rm |= ir.rex_b;
- if (!i386_sse_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
+ if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
record_arch_list_add_reg (ir.regcache,
I387_XMM0_REGNUM (tdep) + ir.rm);
if (i386_record_modrm (&ir))
return -1;
ir.rm |= ir.rex_b;
- if (!i386_sse_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
+ if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
record_arch_list_add_reg (ir.regcache,
I387_XMM0_REGNUM (tdep) + ir.rm);
if (ir.mod == 3)
{
ir.rm |= ir.rex_b;
- if (!i386_sse_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
+ if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
record_arch_list_add_reg (ir.regcache,
I387_XMM0_REGNUM (tdep) + ir.rm);
struct tdesc_arch_data *tdesc_data)
{
const struct target_desc *tdesc = tdep->tdesc;
- const struct tdesc_feature *feature_core, *feature_vector;
+ const struct tdesc_feature *feature_core;
+ const struct tdesc_feature *feature_sse, *feature_avx;
int i, num_regs, valid_p;
if (! tdesc_has_registers (tdesc))
/* Get core registers. */
feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.core");
+ if (feature_core == NULL)
+ return 0;
/* Get SSE registers. */
- feature_vector = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse");
+ feature_sse = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse");
- if (feature_core == NULL || feature_vector == NULL)
- return 0;
+ /* Try AVX registers. */
+ feature_avx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx");
valid_p = 1;
+ /* The XCR0 bits. */
+ if (feature_avx)
+ {
+ /* AVX register description requires SSE register description. */
+ if (!feature_sse)
+ return 0;
+
+ tdep->xcr0 = I386_XSTATE_AVX_MASK;
+
+ /* It may have been set by OSABI initialization function. */
+ if (tdep->num_ymm_regs == 0)
+ {
+ tdep->ymmh_register_names = i386_ymmh_names;
+ tdep->num_ymm_regs = 8;
+ tdep->ymm0h_regnum = I386_YMM0H_REGNUM;
+ }
+
+ for (i = 0; i < tdep->num_ymm_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_avx, tdesc_data,
+ tdep->ymm0h_regnum + i,
+ tdep->ymmh_register_names[i]);
+ }
+ else if (feature_sse)
+ tdep->xcr0 = I386_XSTATE_SSE_MASK;
+ else
+ {
+ tdep->xcr0 = I386_XSTATE_X87_MASK;
+ tdep->num_xmm_regs = 0;
+ }
+
num_regs = tdep->num_core_regs;
for (i = 0; i < num_regs; i++)
valid_p &= tdesc_numbered_register (feature_core, tdesc_data, i,
tdep->register_names[i]);
- /* Need to include %mxcsr, so add one. */
- num_regs += tdep->num_xmm_regs + 1;
- for (; i < num_regs; i++)
- valid_p &= tdesc_numbered_register (feature_vector, tdesc_data, i,
- tdep->register_names[i]);
+ if (feature_sse)
+ {
+ /* Need to include %mxcsr, so add one. */
+ num_regs += tdep->num_xmm_regs + 1;
+ for (; i < num_regs; i++)
+ valid_p &= tdesc_numbered_register (feature_sse, tdesc_data, i,
+ tdep->register_names[i]);
+ }
return valid_p;
}
struct tdesc_arch_data *tdesc_data;
const struct target_desc *tdesc;
int mm0_regnum;
+ int ymm0_regnum;
/* If there is already a candidate, use it. */
arches = gdbarch_list_lookup_by_info (arches, &info);
tdep->fpregset = NULL;
tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+ tdep->xstateregset = NULL;
+
/* The default settings include the FPU registers, the MMX registers
and the SSE registers. This can be overridden for a specific ABI
by adjusting the members `st0_regnum', `mm0_regnum' and
`num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
- will show up in the output of "info all-registers". Ideally we
- should try to autodetect whether they are available, such that we
- can prevent "info all-registers" from displaying registers that
- aren't available.
-
- NOTE: kevinb/2003-07-13: ... if it's a choice between printing
- [the SSE registers] always (even when they don't exist) or never
- showing them to the user (even when they do exist), I prefer the
- former over the latter. */
+ will show up in the output of "info all-registers". */
tdep->st0_regnum = I386_ST0_REGNUM;
tdep->sc_pc_offset = -1;
tdep->sc_sp_offset = -1;
+ tdep->xsave_xcr0_offset = -1;
+
tdep->record_regmap = i386_record_regmap;
/* The format used for `long double' on almost all i386 targets is
set_tdesc_pseudo_register_type (gdbarch, i386_pseudo_register_type);
set_tdesc_pseudo_register_name (gdbarch, i386_pseudo_register_name);
- /* The default ABI includes general-purpose registers,
- floating-point registers, and the SSE registers. */
- set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
+ /* Override the normal target description method to make the AVX
+ upper halves anonymous. */
+ set_gdbarch_register_name (gdbarch, i386_register_name);
+
+ /* Even though the default ABI only includes general-purpose registers,
+ floating-point registers and the SSE registers, we have to leave a
+ gap for the upper AVX registers. */
+ set_gdbarch_num_regs (gdbarch, I386_AVX_NUM_REGS);
/* Get the x86 target description from INFO. */
tdesc = info.target_desc;
tdep->num_core_regs = I386_NUM_GREGS + I387_NUM_REGS;
tdep->register_names = i386_register_names;
+ /* No upper YMM registers. */
+ tdep->ymmh_register_names = NULL;
+ tdep->ymm0h_regnum = -1;
+
tdep->num_byte_regs = 8;
tdep->num_word_regs = 8;
tdep->num_dword_regs = 0;
tdep->num_mmx_regs = 8;
+ tdep->num_ymm_regs = 0;
tdesc_data = tdesc_data_alloc ();
info.tdep_info = (void *) tdesc_data;
gdbarch_init_osabi (info, gdbarch);
+ if (!i386_validate_tdesc_p (tdep, tdesc_data))
+ {
+ tdesc_data_cleanup (tdesc_data);
+ xfree (tdep);
+ gdbarch_free (gdbarch);
+ return NULL;
+ }
+
/* Wire in pseudo registers. Number of pseudo registers may be
changed. */
set_gdbarch_num_pseudo_regs (gdbarch, (tdep->num_byte_regs
+ tdep->num_word_regs
+ tdep->num_dword_regs
- + tdep->num_mmx_regs));
+ + tdep->num_mmx_regs
+ + tdep->num_ymm_regs));
/* Target description may be changed. */
tdesc = tdep->tdesc;
- if (!i386_validate_tdesc_p (tdep, tdesc_data))
- {
- tdesc_data_cleanup (tdesc_data);
- xfree (tdep);
- gdbarch_free (gdbarch);
- return NULL;
- }
-
tdesc_use_registers (gdbarch, tdesc, tdesc_data);
/* Override gdbarch_register_reggroup_p set in tdesc_use_registers. */
tdep->al_regnum = gdbarch_num_regs (gdbarch);
tdep->ax_regnum = tdep->al_regnum + tdep->num_byte_regs;
- mm0_regnum = tdep->ax_regnum + tdep->num_word_regs;
+ ymm0_regnum = tdep->ax_regnum + tdep->num_word_regs;
if (tdep->num_dword_regs)
{
/* Support dword pseudo-registesr if it hasn't been disabled, */
- tdep->eax_regnum = mm0_regnum;
- mm0_regnum = tdep->eax_regnum + tdep->num_dword_regs;
+ tdep->eax_regnum = ymm0_regnum;
+ ymm0_regnum += tdep->num_dword_regs;
}
else
tdep->eax_regnum = -1;
+ mm0_regnum = ymm0_regnum;
+ if (tdep->num_ymm_regs)
+ {
+ /* Support YMM pseudo-registesr if it is available, */
+ tdep->ymm0_regnum = ymm0_regnum;
+ mm0_regnum += tdep->num_ymm_regs;
+ }
+ else
+ tdep->ymm0_regnum = -1;
+
if (tdep->num_mmx_regs != 0)
{
/* Support MMX pseudo-registesr if MMX hasn't been disabled, */
/* Initialize the standard target descriptions. */
initialize_tdesc_i386 ();
+ initialize_tdesc_i386_mmx ();
+ initialize_tdesc_i386_avx ();
/* Tell remote stub that we support XML target description. */
register_remote_support_xml ("i386");