/* Intel 387 floating point stuff.
- Copyright (C) 1988-2017 Free Software Foundation, Inc.
+ Copyright (C) 1988-2019 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include "doublest.h"
-#include "floatformat.h"
#include "frame.h"
#include "gdbcore.h"
#include "inferior.h"
#include "language.h"
#include "regcache.h"
+#include "target-float.h"
#include "value.h"
#include "i386-tdep.h"
#include "i387-tdep.h"
-#include "x86-xstate.h"
+#include "gdbsupport/x86-xstate.h"
/* Print the floating point number specified by RAW. */
print_i387_value (struct gdbarch *gdbarch,
const gdb_byte *raw, struct ui_file *file)
{
- DOUBLEST value;
-
- /* Using extract_typed_floating here might affect the representation
- of certain numbers such as NaNs, even if GDB is running natively.
- This is fine since our caller already detects such special
- numbers and we print the hexadecimal representation anyway. */
- value = extract_typed_floating (raw, i387_ext_type (gdbarch));
-
/* We try to print 19 digits. The last digit may or may not contain
garbage, but we'd better print one too many. We need enough room
to print the value, 1 position for the sign, 1 for the decimal
point, 19 for the digits and 6 for the exponent adds up to 27. */
-#ifdef PRINTF_HAS_LONG_DOUBLE
- fprintf_filtered (file, " %-+27.19Lg", (long double) value);
-#else
- fprintf_filtered (file, " %-+27.19g", (double) value);
-#endif
+ const struct type *type = i387_ext_type (gdbarch);
+ std::string str = target_float_to_string (raw, type, " %-+27.19g");
+ fprintf_filtered (file, "%s", str.c_str ());
}
/* Print the classification for the register contents RAW. */
if (i386_fp_regnum_p (gdbarch, regnum))
{
/* Floating point registers must be converted unless we are
- accessing them in their hardware type. */
- if (type == i387_ext_type (gdbarch))
+ accessing them in their hardware type or TYPE is not float. */
+ if (type == i387_ext_type (gdbarch)
+ || TYPE_CODE (type) != TYPE_CODE_FLT)
return 0;
else
return 1;
}
/* Convert to TYPE. */
- if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (type),
+ if (!get_frame_register_bytes (frame, regnum, 0,
+ register_size (gdbarch, regnum),
from, optimizedp, unavailablep))
return 0;
- convert_typed_floating (from, i387_ext_type (gdbarch), to, type);
+ target_float_convert (from, i387_ext_type (gdbarch), to, type);
*optimizedp = *unavailablep = 0;
return 1;
}
}
/* Convert from TYPE. */
- convert_typed_floating (from, type, to, i387_ext_type (gdbarch));
+ target_float_convert (from, type, to, i387_ext_type (gdbarch));
put_frame_register (frame, regnum, to);
}
\f
void
i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
const gdb_byte *regs = (const gdb_byte *) fsave;
{
if (fsave == NULL)
{
- regcache_raw_supply (regcache, i, NULL);
+ regcache->raw_supply (i, NULL);
continue;
}
val[2] = val[3] = 0;
if (i == I387_FOP_REGNUM (tdep))
val[1] &= ((1 << 3) - 1);
- regcache_raw_supply (regcache, i, val);
+ regcache->raw_supply (i, val);
}
else
- regcache_raw_supply (regcache, i, FSAVE_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, FSAVE_ADDR (tdep, regs, i));
}
/* Provide dummy values for the SSE registers. */
for (i = I387_XMM0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++)
if (regnum == -1 || regnum == i)
- regcache_raw_supply (regcache, i, NULL);
+ regcache->raw_supply (i, NULL);
if (regnum == -1 || regnum == I387_MXCSR_REGNUM (tdep))
{
gdb_byte buf[4];
- store_unsigned_integer (buf, 4, byte_order, 0x1f80);
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), buf);
+ store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL);
+ regcache->raw_supply (I387_MXCSR_REGNUM (tdep), buf);
}
}
void
i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
gdb_byte *regs = (gdb_byte *) fsave;
int i;
{
gdb_byte buf[4];
- regcache_raw_collect (regcache, i, buf);
+ regcache->raw_collect (i, buf);
if (i == I387_FOP_REGNUM (tdep))
{
memcpy (FSAVE_ADDR (tdep, regs, i), buf, 2);
}
else
- regcache_raw_collect (regcache, i, FSAVE_ADDR (tdep, regs, i));
+ regcache->raw_collect (i, FSAVE_ADDR (tdep, regs, i));
}
}
\f
void
i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
const gdb_byte *regs = (const gdb_byte *) fxsave;
int i;
{
if (regs == NULL)
{
- regcache_raw_supply (regcache, i, NULL);
+ regcache->raw_supply (i, NULL);
continue;
}
val[0] = ftag & 0xff;
val[1] = (ftag >> 8) & 0xff;
}
- regcache_raw_supply (regcache, i, val);
+ regcache->raw_supply (i, val);
}
else
- regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i));
}
if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
{
if (regs == NULL)
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), NULL);
+ regcache->raw_supply (I387_MXCSR_REGNUM (tdep), NULL);
else
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
+ regcache->raw_supply (I387_MXCSR_REGNUM (tdep),
FXSAVE_MXCSR_ADDR (regs));
}
}
void
i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
gdb_byte *regs = (gdb_byte *) fxsave;
int i;
{
gdb_byte buf[4];
- regcache_raw_collect (regcache, i, buf);
+ regcache->raw_collect (i, buf);
if (i == I387_FOP_REGNUM (tdep))
{
memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2);
}
else
- regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ regcache->raw_collect (i, FXSAVE_ADDR (tdep, regs, i));
}
if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep),
+ regcache->raw_collect (I387_MXCSR_REGNUM (tdep),
FXSAVE_MXCSR_ADDR (regs));
}
#define XSAVE_AVX512_ZMM_H_ADDR(tdep, xsave, regnum) \
(xsave + xsave_avx512_zmm_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
+/* At xsave_pkeys_offset[REGNUM] you find the offset to the location
+ of the PKRU register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_pkeys_offset[] =
+{
+2688 + 0 * 8 /* %pkru (64 bits in XSTATE, 32-bit actually used by
+ instructions and applications). */
+};
+
+#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+
+
+/* Extract from XSAVE a bitset of the features that are available on the
+ target, but which have not yet been enabled. */
+
+ULONGEST
+i387_xsave_get_clear_bv (struct gdbarch *gdbarch, const void *xsave)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ const gdb_byte *regs = (const gdb_byte *) xsave;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Get `xstat_bv'. The supported bits in `xstat_bv' are 8 bytes. */
+ ULONGEST xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order);
+
+ /* Clear part in vector registers if its bit in xstat_bv is zero. */
+ ULONGEST clear_bv = (~(xstate_bv)) & tdep->xcr0;
+
+ return clear_bv;
+}
+
/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
void
i387_supply_xsave (struct regcache *regcache, int regnum,
const void *xsave)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
const gdb_byte *regs = (const gdb_byte *) xsave;
int i;
+ /* In 64-bit mode the split between "low" and "high" ZMM registers is at
+ ZMM16. Outside of 64-bit mode there are no "high" ZMM registers at all.
+ Precalculate the number to be used for the split point, with the all
+ registers in the "low" portion outside of 64-bit mode. */
+ unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep)
+ + std::min (tdep->num_zmm_regs, 16);
ULONGEST clear_bv;
- static const gdb_byte zero[MAX_REGISTER_SIZE] = { 0 };
+ static const gdb_byte zero[I386_MAX_REGISTER_SIZE] = { 0 };
enum
{
none = 0x0,
avx512_zmm_h = 0x20,
avx512_ymmh_avx512 = 0x40,
avx512_xmm_avx512 = 0x80,
+ pkeys = 0x100,
all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512
+ | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
} regclass;
gdb_assert (regs != NULL);
if (regnum == -1)
regclass = all;
+ else if (regnum >= I387_PKRU_REGNUM (tdep)
+ && regnum < I387_PKEYSEND_REGNUM (tdep))
+ regclass = pkeys;
else if (regnum >= I387_ZMM0H_REGNUM (tdep)
&& regnum < I387_ZMMENDH_REGNUM (tdep))
regclass = avx512_zmm_h;
else
regclass = none;
- if (regclass != none)
- {
- /* Get `xstat_bv'. The supported bits in `xstat_bv' are 8 bytes. */
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- ULONGEST xstate_bv = 0;
-
- xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order);
-
- /* Clear part in vector registers if its bit in xstat_bv is zero. */
- clear_bv = (~(xstate_bv)) & tdep->xcr0;
- }
- else
- clear_bv = X86_XSTATE_ALL_MASK;
+ clear_bv = i387_xsave_get_clear_bv (gdbarch, xsave);
/* With the delayed xsave mechanism, in between the program
starting, and the program accessing the vector registers for the
case none:
break;
+ case pkeys:
+ if ((clear_bv & X86_XSTATE_PKRU))
+ regcache->raw_supply (regnum, zero);
+ else
+ regcache->raw_supply (regnum, XSAVE_PKEYS_ADDR (tdep, regs, regnum));
+ return;
+
case avx512_zmm_h:
- if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- regcache_raw_supply (regcache, regnum, zero);
+ if ((clear_bv & (regnum < zmm_endlo_regnum ? X86_XSTATE_ZMM_H
+ : X86_XSTATE_ZMM)))
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum,
+ XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum));
return;
case avx512_k:
if ((clear_bv & X86_XSTATE_K))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_AVX512_K_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, XSAVE_AVX512_K_ADDR (tdep, regs, regnum));
return;
case avx512_ymmh_avx512:
if ((clear_bv & X86_XSTATE_ZMM))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum,
+ XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum));
return;
case avx512_xmm_avx512:
if ((clear_bv & X86_XSTATE_ZMM))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum,
+ XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum));
return;
case avxh:
if ((clear_bv & X86_XSTATE_AVX))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_AVXH_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, XSAVE_AVXH_ADDR (tdep, regs, regnum));
return;
case mpx:
if ((clear_bv & X86_XSTATE_BNDREGS))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- XSAVE_MPX_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, XSAVE_MPX_ADDR (tdep, regs, regnum));
return;
case sse:
if ((clear_bv & X86_XSTATE_SSE))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- FXSAVE_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, FXSAVE_ADDR (tdep, regs, regnum));
return;
case x87:
if ((clear_bv & X86_XSTATE_X87))
- regcache_raw_supply (regcache, regnum, zero);
+ regcache->raw_supply (regnum, zero);
else
- regcache_raw_supply (regcache, regnum,
- FXSAVE_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, FXSAVE_ADDR (tdep, regs, regnum));
return;
case all:
- /* Handle the upper ZMM registers. */
- if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ /* Handle PKEYS registers. */
+ if ((tdep->xcr0 & X86_XSTATE_PKRU))
{
- if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ if ((clear_bv & X86_XSTATE_PKRU))
{
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep);
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep);
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i,
- XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_PKEYS_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the upper halves of the low 8/16 ZMM registers. */
+ if ((tdep->xcr0 & X86_XSTATE_ZMM_H))
+ {
+ if ((clear_bv & X86_XSTATE_ZMM_H))
+ {
+ for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+ regcache->raw_supply (i, zero);
+ }
+ else
+ {
+ for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+ regcache->raw_supply (i,
+ XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
}
}
for (i = I387_K0_REGNUM (tdep);
i < I387_KEND_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_K0_REGNUM (tdep);
i < I387_KEND_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i,
- XSAVE_AVX512_K_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_AVX512_K_ADDR (tdep, regs, i));
}
}
- /* Handle the YMM_AVX512 registers. */
+ /* Handle the upper 16 ZMM/YMM/XMM registers (if any). */
if ((tdep->xcr0 & X86_XSTATE_ZMM))
{
if ((clear_bv & X86_XSTATE_ZMM))
{
+ for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
+ regcache->raw_supply (i, zero);
for (i = I387_YMM16H_REGNUM (tdep);
i < I387_YMMH_AVX512_END_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
for (i = I387_XMM16_REGNUM (tdep);
i < I387_XMM_AVX512_END_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
+ for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
+ regcache->raw_supply (i,
+ XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
for (i = I387_YMM16H_REGNUM (tdep);
i < I387_YMMH_AVX512_END_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i,
- XSAVE_YMM_AVX512_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_YMM_AVX512_ADDR (tdep, regs, i));
for (i = I387_XMM16_REGNUM (tdep);
i < I387_XMM_AVX512_END_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i,
- XSAVE_XMM_AVX512_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_XMM_AVX512_ADDR (tdep, regs, i));
}
}
/* Handle the upper YMM registers. */
for (i = I387_YMM0H_REGNUM (tdep);
i < I387_YMMENDH_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_YMM0H_REGNUM (tdep);
i < I387_YMMENDH_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i,
- XSAVE_AVXH_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_AVXH_ADDR (tdep, regs, i));
}
}
{
for (i = I387_BND0R_REGNUM (tdep);
i < I387_BNDCFGU_REGNUM (tdep); i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_BND0R_REGNUM (tdep);
i < I387_BNDCFGU_REGNUM (tdep); i++)
- regcache_raw_supply (regcache, i,
- XSAVE_MPX_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i));
}
}
{
for (i = I387_BNDCFGU_REGNUM (tdep);
i < I387_MPXEND_REGNUM (tdep); i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_BNDCFGU_REGNUM (tdep);
i < I387_MPXEND_REGNUM (tdep); i++)
- regcache_raw_supply (regcache, i,
- XSAVE_MPX_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i));
}
}
for (i = I387_XMM0_REGNUM (tdep);
i < I387_MXCSR_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_XMM0_REGNUM (tdep);
i < I387_MXCSR_REGNUM (tdep); i++)
- regcache_raw_supply (regcache, i,
- FXSAVE_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i));
}
}
for (i = I387_ST0_REGNUM (tdep);
i < I387_FCTRL_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, zero);
+ regcache->raw_supply (i, zero);
}
else
{
for (i = I387_ST0_REGNUM (tdep);
i < I387_FCTRL_REGNUM (tdep);
i++)
- regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i));
}
}
break;
for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
if (regnum == -1 || regnum == i)
{
+ if (clear_bv & X86_XSTATE_X87)
+ {
+ if (i == I387_FCTRL_REGNUM (tdep))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order,
+ I387_FCTRL_INIT_VAL);
+ regcache->raw_supply (i, buf);
+ }
+ else if (i == I387_FTAG_REGNUM (tdep))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order, 0xffff);
+ regcache->raw_supply (i, buf);
+ }
+ else
+ regcache->raw_supply (i, zero);
+ }
/* Most of the FPU control registers occupy only 16 bits in
the xsave extended state. Give those a special treatment. */
- if (i != I387_FIOFF_REGNUM (tdep)
- && i != I387_FOOFF_REGNUM (tdep))
+ else if (i != I387_FIOFF_REGNUM (tdep)
+ && i != I387_FOOFF_REGNUM (tdep))
{
gdb_byte val[4];
val[2] = val[3] = 0;
if (i == I387_FOP_REGNUM (tdep))
val[1] &= ((1 << 3) - 1);
- else if (i== I387_FTAG_REGNUM (tdep))
+ else if (i == I387_FTAG_REGNUM (tdep))
{
/* The fxsave area contains a simplified version of
the tag word. We have to look at the actual 80-bit
val[0] = ftag & 0xff;
val[1] = (ftag >> 8) & 0xff;
}
- regcache_raw_supply (regcache, i, val);
+ regcache->raw_supply (i, val);
}
- else
- regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ else
+ regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i));
}
if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
- FXSAVE_MXCSR_ADDR (regs));
+ {
+ /* The MXCSR register is placed into the xsave buffer if either the
+ AVX or SSE features are enabled. */
+ if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ == (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL);
+ regcache->raw_supply (I387_MXCSR_REGNUM (tdep), buf);
+ }
+ else
+ regcache->raw_supply (I387_MXCSR_REGNUM (tdep),
+ FXSAVE_MXCSR_ADDR (regs));
+ }
}
/* Similar to i387_collect_fxsave, but use XSAVE extended state. */
i387_collect_xsave (const struct regcache *regcache, int regnum,
void *xsave, int gcore)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_byte *regs = (gdb_byte *) xsave;
- int i;
+ gdb_byte *p, *regs = (gdb_byte *) xsave;
+ gdb_byte raw[I386_MAX_REGISTER_SIZE];
+ ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0;
+ unsigned int i;
+ /* See the comment in i387_supply_xsave(). */
+ unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep)
+ + std::min (tdep->num_zmm_regs, 16);
enum
{
- none = 0x0,
- check = 0x1,
- x87 = 0x2 | check,
- sse = 0x4 | check,
- avxh = 0x8 | check,
- mpx = 0x10 | check,
- avx512_k = 0x20 | check,
- avx512_zmm_h = 0x40 | check,
- avx512_ymmh_avx512 = 0x80 | check,
- avx512_xmm_avx512 = 0x100 | check,
+ x87_ctrl_or_mxcsr = 0x1,
+ x87 = 0x2,
+ sse = 0x4,
+ avxh = 0x8,
+ mpx = 0x10,
+ avx512_k = 0x20,
+ avx512_zmm_h = 0x40,
+ avx512_ymmh_avx512 = 0x80,
+ avx512_xmm_avx512 = 0x100,
+ pkeys = 0x200,
all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512
+ | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
} regclass;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
if (regnum == -1)
regclass = all;
+ else if (regnum >= I387_PKRU_REGNUM (tdep)
+ && regnum < I387_PKEYSEND_REGNUM (tdep))
+ regclass = pkeys;
else if (regnum >= I387_ZMM0H_REGNUM (tdep)
&& regnum < I387_ZMMENDH_REGNUM (tdep))
regclass = avx512_zmm_h;
else if (regnum >= I387_ST0_REGNUM (tdep)
&& regnum < I387_FCTRL_REGNUM (tdep))
regclass = x87;
+ else if ((regnum >= I387_FCTRL_REGNUM (tdep)
+ && regnum < I387_XMM0_REGNUM (tdep))
+ || regnum == I387_MXCSR_REGNUM (tdep))
+ regclass = x87_ctrl_or_mxcsr;
else
- regclass = none;
+ internal_error (__FILE__, __LINE__, _("invalid i387 regnum %d"), regnum);
if (gcore)
{
memcpy (XSAVE_XSTATE_BV_ADDR (regs), &tdep->xcr0, 8);
}
- if ((regclass & check))
+ /* The supported bits in `xstat_bv' are 8 bytes. */
+ initial_xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order);
+ clear_bv = (~(initial_xstate_bv)) & tdep->xcr0;
+
+ /* The XSAVE buffer was filled lazily by the kernel. Only those
+ features that are enabled were written into the buffer, disabled
+ features left the buffer uninitialised. In order to identify if any
+ registers have changed we will be comparing the register cache
+ version to the version in the XSAVE buffer, it is important then that
+ at this point we initialise to the default values any features in
+ XSAVE that are not yet initialised.
+
+ This could be made more efficient, we know which features (from
+ REGNUM) we will be potentially updating, and could limit ourselves to
+ only clearing that feature. However, the extra complexity does not
+ seem justified at this point. */
+ if (clear_bv)
{
- gdb_byte raw[I386_MAX_REGISTER_SIZE];
- ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0;
- gdb_byte *p;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ if ((clear_bv & X86_XSTATE_PKRU))
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep); i++)
+ memset (XSAVE_PKEYS_ADDR (tdep, regs, i), 0, 4);
- /* The supported bits in `xstat_bv' are 8 bytes. */
- initial_xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order);
- clear_bv = (~(initial_xstate_bv)) & tdep->xcr0;
+ if ((clear_bv & X86_XSTATE_BNDREGS))
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16);
- /* Clear register set if its bit in xstat_bv is zero. */
- if (clear_bv)
- {
- if ((clear_bv & X86_XSTATE_BNDREGS))
- for (i = I387_BND0R_REGNUM (tdep);
- i < I387_BNDCFGU_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_BNDCFG))
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8);
- if ((clear_bv & X86_XSTATE_BNDCFG))
- for (i = I387_BNDCFGU_REGNUM (tdep);
- i < I387_MPXEND_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8);
+ if ((clear_bv & X86_XSTATE_ZMM_H))
+ for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+ memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
- if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep); i++)
- memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
+ if ((clear_bv & X86_XSTATE_K))
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep); i++)
+ memset (XSAVE_AVX512_K_ADDR (tdep, regs, i), 0, 8);
- if ((clear_bv & X86_XSTATE_K))
- for (i = I387_K0_REGNUM (tdep);
- i < I387_KEND_REGNUM (tdep); i++)
- memset (XSAVE_AVX512_K_ADDR (tdep, regs, i), 0, 8);
+ if ((clear_bv & X86_XSTATE_ZMM))
+ {
+ for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
+ memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
+ memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16);
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ memset (XSAVE_XMM_AVX512_ADDR (tdep, regs, i), 0, 16);
+ }
- if ((clear_bv & X86_XSTATE_ZMM))
- {
- for (i = I387_YMM16H_REGNUM (tdep);
- i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
- memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16);
- for (i = I387_XMM16_REGNUM (tdep);
- i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
- memset (XSAVE_XMM_AVX512_ADDR (tdep, regs, i), 0, 16);
- }
+ if ((clear_bv & X86_XSTATE_AVX))
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep); i++)
+ memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16);
- if ((clear_bv & X86_XSTATE_AVX))
- for (i = I387_YMM0H_REGNUM (tdep);
- i < I387_YMMENDH_REGNUM (tdep); i++)
- memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_SSE))
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ memset (FXSAVE_ADDR (tdep, regs, i), 0, 16);
+
+ /* The mxcsr register is written into the xsave buffer if either AVX
+ or SSE is enabled, so only clear it if both of those features
+ require clearing. */
+ if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ == (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ store_unsigned_integer (FXSAVE_MXCSR_ADDR (regs), 2, byte_order,
+ I387_MXCSR_INIT_VAL);
- if ((clear_bv & X86_XSTATE_SSE))
- for (i = I387_XMM0_REGNUM (tdep);
- i < I387_MXCSR_REGNUM (tdep); i++)
- memset (FXSAVE_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_X87))
+ {
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep); i++)
+ memset (FXSAVE_ADDR (tdep, regs, i), 0, 10);
- if ((clear_bv & X86_XSTATE_X87))
- for (i = I387_ST0_REGNUM (tdep);
- i < I387_FCTRL_REGNUM (tdep); i++)
- memset (FXSAVE_ADDR (tdep, regs, i), 0, 10);
+ for (i = I387_FCTRL_REGNUM (tdep);
+ i < I387_XMM0_REGNUM (tdep); i++)
+ {
+ if (i == I387_FCTRL_REGNUM (tdep))
+ store_unsigned_integer (FXSAVE_ADDR (tdep, regs, i), 2,
+ byte_order, I387_FCTRL_INIT_VAL);
+ else
+ memset (FXSAVE_ADDR (tdep, regs, i), 0,
+ regcache_register_size (regcache, i));
+ }
}
+ }
- if (regclass == all)
- {
- /* Check if any ZMMH registers are changed. */
- if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep); i++)
+ if (regclass == all)
+ {
+ /* Check if any PKEYS registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_PKRU))
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_PKEYS_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 4) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 32) != 0)
- {
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
- memcpy (p, raw, 32);
- }
+ xstate_bv |= X86_XSTATE_PKRU;
+ memcpy (p, raw, 4);
}
+ }
- /* Check if any K registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_K))
- for (i = I387_K0_REGNUM (tdep);
- i < I387_KEND_REGNUM (tdep); i++)
+ /* Check if any ZMMH registers are changed. */
+ if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ for (i = I387_ZMM0H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 32) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVX512_K_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 8) != 0)
- {
- xstate_bv |= X86_XSTATE_K;
- memcpy (p, raw, 8);
- }
+ xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ memcpy (p, raw, 32);
+ }
+ }
+
+ /* Check if any K registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_K))
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_AVX512_K_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 8) != 0)
+ {
+ xstate_bv |= X86_XSTATE_K;
+ memcpy (p, raw, 8);
}
+ }
- /* Check if any XMM or upper YMM registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ /* Check if any XMM or upper YMM registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ {
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
{
- for (i = I387_YMM16H_REGNUM (tdep);
- i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
+ regcache->raw_collect (i, raw);
+ p = XSAVE_YMM_AVX512_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_YMM_AVX512_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
}
- for (i = I387_XMM16_REGNUM (tdep);
- i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ }
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_XMM_AVX512_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_XMM_AVX512_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
}
}
+ }
- /* Check if any upper YMM registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_AVX))
- for (i = I387_YMM0H_REGNUM (tdep);
- i < I387_YMMENDH_REGNUM (tdep); i++)
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_BNDREGS))
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVXH_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_AVX;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_BNDREGS;
+ memcpy (p, raw, 16);
}
- /* Check if any upper MPX registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_BNDREGS))
- for (i = I387_BND0R_REGNUM (tdep);
- i < I387_BNDCFGU_REGNUM (tdep); i++)
+ }
+
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_BNDCFG))
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 8))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_BNDREGS;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
}
+ }
- /* Check if any upper MPX registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_BNDCFG))
- for (i = I387_BNDCFGU_REGNUM (tdep);
- i < I387_MPXEND_REGNUM (tdep); i++)
+ /* Check if any upper YMM registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_AVX))
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_AVXH_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 8))
- {
- xstate_bv |= X86_XSTATE_BNDCFG;
- memcpy (p, raw, 8);
- }
+ xstate_bv |= X86_XSTATE_AVX;
+ memcpy (p, raw, 16);
}
+ }
- /* Check if any SSE registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_SSE))
- for (i = I387_XMM0_REGNUM (tdep);
- i < I387_MXCSR_REGNUM (tdep); i++)
+ /* Check if any SSE registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_SSE))
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = FXSAVE_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_SSE;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 16);
}
+ }
- /* Check if any X87 registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_X87))
- for (i = I387_ST0_REGNUM (tdep);
- i < I387_FCTRL_REGNUM (tdep); i++)
+ if ((tdep->xcr0 & X86_XSTATE_AVX) || (tdep->xcr0 & X86_XSTATE_SSE))
+ {
+ i = I387_MXCSR_REGNUM (tdep);
+ regcache->raw_collect (i, raw);
+ p = FXSAVE_MXCSR_ADDR (regs);
+ if (memcmp (raw, p, 4))
+ {
+ /* Now, we need to mark one of either SSE of AVX as enabled.
+ We could pick either. What we do is check to see if one
+ of the features is already enabled, if it is then we leave
+ it at that, otherwise we pick SSE. */
+ if ((xstate_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0)
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 4);
+ }
+ }
+
+ /* Check if any X87 registers are changed. Only the non-control
+ registers are handled here, the control registers are all handled
+ later on in this function. */
+ if ((tdep->xcr0 & X86_XSTATE_X87))
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep); i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 10))
{
- regcache_raw_collect (regcache, i, raw);
- p = FXSAVE_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 10))
- {
- xstate_bv |= X86_XSTATE_X87;
- memcpy (p, raw, 10);
- }
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, 10);
}
- }
- else
- {
- /* Check if REGNUM is changed. */
- regcache_raw_collect (regcache, regnum, raw);
+ }
+ }
+ else
+ {
+ /* Check if REGNUM is changed. */
+ regcache->raw_collect (regnum, raw);
- switch (regclass)
+ switch (regclass)
+ {
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("invalid i387 regclass"));
+
+ case pkeys:
+ /* This is a PKEYS register. */
+ p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 4) != 0)
{
- default:
- internal_error (__FILE__, __LINE__,
- _("invalid i387 regclass"));
-
- case avx512_zmm_h:
- /* This is a ZMM register. */
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 32) != 0)
- {
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
- memcpy (p, raw, 32);
- }
- break;
- case avx512_k:
- /* This is a AVX512 mask register. */
- p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 8) != 0)
- {
- xstate_bv |= X86_XSTATE_K;
- memcpy (p, raw, 8);
- }
- break;
+ xstate_bv |= X86_XSTATE_PKRU;
+ memcpy (p, raw, 4);
+ }
+ break;
- case avx512_ymmh_avx512:
- /* This is an upper YMM16-31 register. */
- p = XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_zmm_h:
+ /* This is a ZMM register. */
+ p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 32) != 0)
+ {
+ xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ memcpy (p, raw, 32);
+ }
+ break;
+ case avx512_k:
+ /* This is a AVX512 mask register. */
+ p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 8) != 0)
+ {
+ xstate_bv |= X86_XSTATE_K;
+ memcpy (p, raw, 8);
+ }
+ break;
- case avx512_xmm_avx512:
- /* This is an upper XMM16-31 register. */
- p = XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_ymmh_avx512:
+ /* This is an upper YMM16-31 register. */
+ p = XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
+ }
+ break;
- case avxh:
- /* This is an upper YMM register. */
- p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_AVX;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_xmm_avx512:
+ /* This is an upper XMM16-31 register. */
+ p = XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
+ }
+ break;
- case mpx:
- if (regnum < I387_BNDCFGU_REGNUM (tdep))
- {
- regcache_raw_collect (regcache, regnum, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_BNDREGS;
- memcpy (p, raw, 16);
- }
- }
- else
- {
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- xstate_bv |= X86_XSTATE_BNDCFG;
- memcpy (p, raw, 8);
- }
- break;
+ case avxh:
+ /* This is an upper YMM register. */
+ p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16))
+ {
+ xstate_bv |= X86_XSTATE_AVX;
+ memcpy (p, raw, 16);
+ }
+ break;
- case sse:
- /* This is an SSE register. */
- p = FXSAVE_ADDR (tdep, regs, regnum);
+ case mpx:
+ if (regnum < I387_BNDCFGU_REGNUM (tdep))
+ {
+ regcache->raw_collect (regnum, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, regnum);
if (memcmp (raw, p, 16))
{
- xstate_bv |= X86_XSTATE_SSE;
+ xstate_bv |= X86_XSTATE_BNDREGS;
memcpy (p, raw, 16);
}
- break;
+ }
+ else
+ {
+ p = XSAVE_MPX_ADDR (tdep, regs, regnum);
+ xstate_bv |= X86_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
+ }
+ break;
- case x87:
- /* This is an x87 register. */
- p = FXSAVE_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 10))
- {
- xstate_bv |= X86_XSTATE_X87;
- memcpy (p, raw, 10);
- }
- break;
+ case sse:
+ /* This is an SSE register. */
+ p = FXSAVE_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16))
+ {
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 16);
}
- }
+ break;
- /* Update the corresponding bits in `xstate_bv' if any SSE/AVX
- registers are changed. */
- if (xstate_bv)
- {
- /* The supported bits in `xstat_bv' are 8 bytes. */
- initial_xstate_bv |= xstate_bv;
- store_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order,
- initial_xstate_bv);
+ case x87:
+ /* This is an x87 register. */
+ p = FXSAVE_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 10))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, 10);
+ }
+ break;
- switch (regclass)
+ case x87_ctrl_or_mxcsr:
+ /* We only handle MXCSR here. All other x87 control registers
+ are handled separately below. */
+ if (regnum == I387_MXCSR_REGNUM (tdep))
{
- default:
- internal_error (__FILE__, __LINE__,
- _("invalid i387 regclass"));
-
- case all:
- break;
-
- case x87:
- case sse:
- case avxh:
- case mpx:
- case avx512_k:
- case avx512_zmm_h:
- case avx512_ymmh_avx512:
- case avx512_xmm_avx512:
- /* Register REGNUM has been updated. Return. */
- return;
+ p = FXSAVE_MXCSR_ADDR (regs);
+ if (memcmp (raw, p, 2))
+ {
+ /* We're only setting MXCSR, so check the initial state
+ to see if either of AVX or SSE are already enabled.
+ If they are then we'll attribute this changed MXCSR to
+ that feature. If neither feature is enabled, then
+ we'll attribute this change to the SSE feature. */
+ xstate_bv |= (initial_xstate_bv
+ & (X86_XSTATE_AVX | X86_XSTATE_SSE));
+ if ((xstate_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE)) == 0)
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 2);
+ }
}
}
- else
- {
- /* Return if REGNUM isn't changed. */
- if (regclass != all)
- return;
- }
}
/* Only handle x87 control registers. */
{
gdb_byte buf[4];
- regcache_raw_collect (regcache, i, buf);
+ regcache->raw_collect (i, buf);
if (i == I387_FOP_REGNUM (tdep))
{
buf[0] |= (1 << fpreg);
}
}
- memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (p, buf, 2))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, buf, 2);
+ }
}
else
- regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ {
+ int regsize;
+
+ regcache->raw_collect (i, raw);
+ regsize = regcache_register_size (regcache, i);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, regsize))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, regsize);
+ }
+ }
}
- if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep),
- FXSAVE_MXCSR_ADDR (regs));
+ /* Update the corresponding bits in `xstate_bv' if any
+ registers are changed. */
+ if (xstate_bv)
+ {
+ /* The supported bits in `xstat_bv' are 8 bytes. */
+ initial_xstate_bv |= xstate_bv;
+ store_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order,
+ initial_xstate_bv);
+ }
}
/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff);
}
+
+/* See i387-tdep.h. */
+
+void
+i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (I387_BND0R_REGNUM (tdep) > 0)
+ {
+ gdb_byte bnd_buf[16];
+
+ memset (bnd_buf, 0, 16);
+ for (int i = 0; i < I387_NUM_BND_REGS; i++)
+ regcache->raw_write (I387_BND0R_REGNUM (tdep) + i, bnd_buf);
+ }
+}