]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/i387-tdep.c
gprofng: add hardware counters for AMD Zen3
[thirdparty/binutils-gdb.git] / gdb / i387-tdep.c
index 3de7c62f4a0f94952b8e142bccc4d60e7e9befbd..45bd43a50a9b944bc219ccb367c0a5a8a0b9c989 100644 (file)
@@ -1,6 +1,6 @@
 /* Intel 387 floating point stuff.
 
-   Copyright (C) 1988-2017 Free Software Foundation, Inc.
+   Copyright (C) 1988-2024 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include "defs.h"
-#include "doublest.h"
+#include "extract-store-integer.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.  */
 
@@ -36,23 +36,13 @@ static void
 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");
+  gdb_printf (file, "%s", str.c_str ());
 }
 
 /* Print the classification for the register contents RAW.  */
@@ -77,16 +67,16 @@ print_i387_ext (struct gdbarch *gdbarch,
     {
       if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
        /* Infinity.  */
-       fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
+       gdb_printf (file, " %cInf", (sign ? '-' : '+'));
       else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
        /* Real Indefinite (QNaN).  */
-       fputs_unfiltered (" Real Indefinite (QNaN)", file);
+       gdb_puts (" Real Indefinite (QNaN)", file);
       else if (fraction[1] & 0x40000000)
        /* QNaN.  */
-       fputs_filtered (" QNaN", file);
+       gdb_puts (" QNaN", file);
       else
        /* SNaN.  */
-       fputs_filtered (" SNaN", file);
+       gdb_puts (" SNaN", file);
     }
   else if (exponent < 0x7fff && exponent > 0x0000 && integer)
     /* Normal.  */
@@ -98,14 +88,14 @@ print_i387_ext (struct gdbarch *gdbarch,
       
       if (integer)
        /* Pseudo-denormal.  */
-       fputs_filtered (" Pseudo-denormal", file);
+       gdb_puts (" Pseudo-denormal", file);
       else if (fraction[0] || fraction[1])
        /* Denormal.  */
-       fputs_filtered (" Denormal", file);
+       gdb_puts (" Denormal", file);
     }
   else
     /* Unsupported.  */
-    fputs_filtered (" Unsupported", file);
+    gdb_puts (" Unsupported", file);
 }
 
 /* Print the status word STATUS.  If STATUS_P is false, then STATUS
@@ -115,35 +105,35 @@ static void
 print_i387_status_word (int status_p,
                        unsigned int status, struct ui_file *file)
 {
-  fprintf_filtered (file, "Status Word:         ");
+  gdb_printf (file, "Status Word:         ");
   if (!status_p)
     {
-      fprintf_filtered (file, "%s\n", _("<unavailable>"));
+      gdb_printf (file, "%s\n", _("<unavailable>"));
       return;
     }
 
-  fprintf_filtered (file, "%s", hex_string_custom (status, 4));
-  fputs_filtered ("  ", file);
-  fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : "  ");
-  fputs_filtered ("  ", file);
-  fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : "  ");
-  fputs_filtered ("  ", file);
-  fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : "  ");
-  fputs_filtered ("  ", file);
-  fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : "  ");
-  fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : "  ");
-
-  fputs_filtered ("\n", file);
-
-  fprintf_filtered (file,
-                   "                       TOP: %d\n", ((status >> 11) & 7));
+  gdb_printf (file, "%s", hex_string_custom (status, 4));
+  gdb_puts ("  ", file);
+  gdb_printf (file, " %s", (status & 0x0001) ? "IE" : "  ");
+  gdb_printf (file, " %s", (status & 0x0002) ? "DE" : "  ");
+  gdb_printf (file, " %s", (status & 0x0004) ? "ZE" : "  ");
+  gdb_printf (file, " %s", (status & 0x0008) ? "OE" : "  ");
+  gdb_printf (file, " %s", (status & 0x0010) ? "UE" : "  ");
+  gdb_printf (file, " %s", (status & 0x0020) ? "PE" : "  ");
+  gdb_puts ("  ", file);
+  gdb_printf (file, " %s", (status & 0x0080) ? "ES" : "  ");
+  gdb_puts ("  ", file);
+  gdb_printf (file, " %s", (status & 0x0040) ? "SF" : "  ");
+  gdb_puts ("  ", file);
+  gdb_printf (file, " %s", (status & 0x0100) ? "C0" : "  ");
+  gdb_printf (file, " %s", (status & 0x0200) ? "C1" : "  ");
+  gdb_printf (file, " %s", (status & 0x0400) ? "C2" : "  ");
+  gdb_printf (file, " %s", (status & 0x4000) ? "C3" : "  ");
+
+  gdb_puts ("\n", file);
+
+  gdb_printf (file,
+             "                       TOP: %d\n", ((status >> 11) & 7));
 }
 
 /* Print the control word CONTROL.  If CONTROL_P is false, then
@@ -153,55 +143,55 @@ static void
 print_i387_control_word (int control_p,
                         unsigned int control, struct ui_file *file)
 {
-  fprintf_filtered (file, "Control Word:        ");
+  gdb_printf (file, "Control Word:        ");
   if (!control_p)
     {
-      fprintf_filtered (file, "%s\n", _("<unavailable>"));
+      gdb_printf (file, "%s\n", _("<unavailable>"));
       return;
     }
 
-  fprintf_filtered (file, "%s", hex_string_custom (control, 4));
-  fputs_filtered ("  ", file);
-  fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : "  ");
-  fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : "  ");
-  fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : "  ");
-  fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : "  ");
-  fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : "  ");
-  fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : "  ");
+  gdb_printf (file, "%s", hex_string_custom (control, 4));
+  gdb_puts ("  ", file);
+  gdb_printf (file, " %s", (control & 0x0001) ? "IM" : "  ");
+  gdb_printf (file, " %s", (control & 0x0002) ? "DM" : "  ");
+  gdb_printf (file, " %s", (control & 0x0004) ? "ZM" : "  ");
+  gdb_printf (file, " %s", (control & 0x0008) ? "OM" : "  ");
+  gdb_printf (file, " %s", (control & 0x0010) ? "UM" : "  ");
+  gdb_printf (file, " %s", (control & 0x0020) ? "PM" : "  ");
 
-  fputs_filtered ("\n", file);
+  gdb_puts ("\n", file);
 
-  fputs_filtered ("                       PC: ", file);
+  gdb_puts ("                       PC: ", file);
   switch ((control >> 8) & 3)
     {
     case 0:
-      fputs_filtered ("Single Precision (24-bits)\n", file);
+      gdb_puts ("Single Precision (24-bits)\n", file);
       break;
     case 1:
-      fputs_filtered ("Reserved\n", file);
+      gdb_puts ("Reserved\n", file);
       break;
     case 2:
-      fputs_filtered ("Double Precision (53-bits)\n", file);
+      gdb_puts ("Double Precision (53-bits)\n", file);
       break;
     case 3:
-      fputs_filtered ("Extended Precision (64-bits)\n", file);
+      gdb_puts ("Extended Precision (64-bits)\n", file);
       break;
     }
       
-  fputs_filtered ("                       RC: ", file);
+  gdb_puts ("                       RC: ", file);
   switch ((control >> 10) & 3)
     {
     case 0:
-      fputs_filtered ("Round to nearest\n", file);
+      gdb_puts ("Round to nearest\n", file);
       break;
     case 1:
-      fputs_filtered ("Round down\n", file);
+      gdb_puts ("Round down\n", file);
       break;
     case 2:
-      fputs_filtered ("Round up\n", file);
+      gdb_puts ("Round up\n", file);
       break;
     case 3:
-      fputs_filtered ("Round toward zero\n", file);
+      gdb_puts ("Round toward zero\n", file);
       break;
     }
 }
@@ -212,9 +202,9 @@ print_i387_control_word (int control_p,
 
 void
 i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
-                      struct frame_info *frame, const char *args)
+                      const frame_info_ptr &frame, const char *args)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
   ULONGEST fctrl;
   int fctrl_p;
   ULONGEST fstat;
@@ -264,7 +254,7 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
          int i;
          int tag = -1;
 
-         fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
+         gdb_printf (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
 
          if (ftag_p)
            {
@@ -273,60 +263,60 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
              switch (tag)
                {
                case 0:
-                 fputs_filtered ("Valid   ", file);
+                 gdb_puts ("Valid   ", file);
                  break;
                case 1:
-                 fputs_filtered ("Zero    ", file);
+                 gdb_puts ("Zero    ", file);
                  break;
                case 2:
-                 fputs_filtered ("Special ", file);
+                 gdb_puts ("Special ", file);
                  break;
                case 3:
-                 fputs_filtered ("Empty   ", file);
+                 gdb_puts ("Empty   ", file);
                  break;
                }
            }
          else
-           fputs_filtered ("Unknown ", file);
+           gdb_puts ("Unknown ", file);
 
          regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep);
          regval = get_frame_register_value (frame, regnum);
 
-         if (value_entirely_available (regval))
+         if (regval->entirely_available ())
            {
-             const gdb_byte *raw = value_contents (regval);
+             const gdb_byte *raw = regval->contents ().data ();
 
-             fputs_filtered ("0x", file);
+             gdb_puts ("0x", file);
              for (i = 9; i >= 0; i--)
-               fprintf_filtered (file, "%02x", raw[i]);
+               gdb_printf (file, "%02x", raw[i]);
 
              if (tag != -1 && tag != 3)
                print_i387_ext (gdbarch, raw, file);
            }
          else
-           fprintf_filtered (file, "%s", _("<unavailable>"));
+           gdb_printf (file, "%s", _("<unavailable>"));
 
-         fputs_filtered ("\n", file);
+         gdb_puts ("\n", file);
        }
     }
 
-  fputs_filtered ("\n", file);
+  gdb_puts ("\n", file);
   print_i387_status_word (fstat_p, fstat, file);
   print_i387_control_word (fctrl_p, fctrl, file);
-  fprintf_filtered (file, "Tag Word:            %s\n",
-                   ftag_p ? hex_string_custom (ftag, 4) : _("<unavailable>"));
-  fprintf_filtered (file, "Instruction Pointer: %s:",
-                   fiseg_p ? hex_string_custom (fiseg, 2) : _("<unavailable>"));
-  fprintf_filtered (file, "%s\n",
-                   fioff_p ? hex_string_custom (fioff, 8) : _("<unavailable>"));
-  fprintf_filtered (file, "Operand Pointer:     %s:",
-                   foseg_p ? hex_string_custom (foseg, 2) : _("<unavailable>"));
-  fprintf_filtered (file, "%s\n",
-                   fooff_p ? hex_string_custom (fooff, 8) : _("<unavailable>"));
-  fprintf_filtered (file, "Opcode:              %s\n",
-                   fop_p
-                   ? (hex_string_custom (fop ? (fop | 0xd800) : 0, 4))
-                   : _("<unavailable>"));
+  gdb_printf (file, "Tag Word:            %s\n",
+             ftag_p ? hex_string_custom (ftag, 4) : _("<unavailable>"));
+  gdb_printf (file, "Instruction Pointer: %s:",
+             fiseg_p ? hex_string_custom (fiseg, 2) : _("<unavailable>"));
+  gdb_printf (file, "%s\n",
+             fioff_p ? hex_string_custom (fioff, 8) : _("<unavailable>"));
+  gdb_printf (file, "Operand Pointer:     %s:",
+             foseg_p ? hex_string_custom (foseg, 2) : _("<unavailable>"));
+  gdb_printf (file, "%s\n",
+             fooff_p ? hex_string_custom (fooff, 8) : _("<unavailable>"));
+  gdb_printf (file, "Opcode:              %s\n",
+             fop_p
+             ? (hex_string_custom (fop ? (fop | 0xd800) : 0, 4))
+             : _("<unavailable>"));
 }
 \f
 
@@ -342,7 +332,7 @@ i387_convert_register_p (struct gdbarch *gdbarch, int regnum,
       /* Floating point registers must be converted unless we are
         accessing them in their hardware type or TYPE is not float.  */
       if (type == i387_ext_type (gdbarch)
-         || TYPE_CODE (type) != TYPE_CODE_FLT)
+         || type->code () != TYPE_CODE_FLT)
        return 0;
       else
        return 1;
@@ -355,7 +345,7 @@ i387_convert_register_p (struct gdbarch *gdbarch, int regnum,
    return its contents in TO.  */
 
 int
-i387_register_to_value (struct frame_info *frame, int regnum,
+i387_register_to_value (const frame_info_ptr &frame, int regnum,
                        struct type *type, gdb_byte *to,
                        int *optimizedp, int *unavailablep)
 {
@@ -365,7 +355,7 @@ i387_register_to_value (struct frame_info *frame, int regnum,
   gdb_assert (i386_fp_regnum_p (gdbarch, regnum));
 
   /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (type->code () != TYPE_CODE_FLT)
     {
       warning (_("Cannot convert floating-point register value "
               "to non-floating-point type."));
@@ -374,12 +364,14 @@ i387_register_to_value (struct frame_info *frame, int regnum,
     }
 
   /* Convert to TYPE.  */
-  if (!get_frame_register_bytes (frame, regnum, 0,
-                                register_size (gdbarch, regnum),
-                                from, optimizedp, unavailablep))
+  auto from_view
+    = gdb::make_array_view (from, register_size (gdbarch, regnum));
+  frame_info_ptr next_frame = get_next_frame_sentinel_okay (frame);
+  if (!get_frame_register_bytes (next_frame, regnum, 0, from_view, 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;
 }
@@ -388,7 +380,7 @@ i387_register_to_value (struct frame_info *frame, int regnum,
    REGNUM in frame FRAME.  */
 
 void
-i387_value_to_register (struct frame_info *frame, int regnum,
+i387_value_to_register (const frame_info_ptr &frame, int regnum,
                        struct type *type, const gdb_byte *from)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
@@ -397,7 +389,7 @@ i387_value_to_register (struct frame_info *frame, int regnum,
   gdb_assert (i386_fp_regnum_p (gdbarch, regnum));
 
   /* We only support floating-point values.  */
-  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+  if (type->code () != TYPE_CODE_FLT)
     {
       warning (_("Cannot convert non-floating-point type "
               "to floating-point register value."));
@@ -405,8 +397,10 @@ i387_value_to_register (struct frame_info *frame, int regnum,
     }
 
   /* Convert from TYPE.  */
-  convert_typed_floating (from, type, to, i387_ext_type (gdbarch));
-  put_frame_register (frame, regnum, to);
+  struct type *to_type = i387_ext_type (gdbarch);
+  target_float_convert (from, type, to, to_type);
+  auto to_view = gdb::make_array_view (to, to_type->length ());
+  put_frame_register (get_next_frame_sentinel_okay (frame), regnum, to_view);
 }
 \f
 
@@ -447,8 +441,8 @@ static int fsave_offset[] =
 void
 i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct gdbarch *gdbarch = regcache->arch ();
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   const gdb_byte *regs = (const gdb_byte *) fsave;
   int i;
@@ -460,7 +454,7 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
       {
        if (fsave == NULL)
          {
-           regcache_raw_supply (regcache, i, NULL);
+           regcache->raw_supply (i, NULL);
            continue;
          }
 
@@ -475,22 +469,22 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
            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);
     }
 }
 
@@ -502,7 +496,8 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
 void
 i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+  gdbarch *arch = regcache->arch ();
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch);
   gdb_byte *regs = (gdb_byte *) fsave;
   int i;
 
@@ -512,25 +507,25 @@ i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
     if (regnum == -1 || regnum == i)
       {
        /* Most of the FPU control registers occupy only 16 bits in
-           the fsave area.  Give those a special treatment.  */
+          the fsave area.  Give those a special treatment.  */
        if (i >= I387_FCTRL_REGNUM (tdep)
            && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
          {
            gdb_byte buf[4];
 
-           regcache_raw_collect (regcache, i, buf);
+           regcache->raw_collect (i, buf);
 
            if (i == I387_FOP_REGNUM (tdep))
              {
                /* The opcode occupies only 11 bits.  Make sure we
-                   don't touch the other bits.  */
+                  don't touch the other bits.  */
                buf[1] &= ((1 << 3) - 1);
                buf[1] |= ((FSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1));
              }
            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
@@ -595,7 +590,8 @@ static int i387_tag (const gdb_byte *raw);
 void
 i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+  gdbarch *arch = regcache->arch ();
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch);
   const gdb_byte *regs = (const gdb_byte *) fxsave;
   int i;
 
@@ -607,7 +603,7 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
       {
        if (regs == NULL)
          {
-           regcache_raw_supply (regcache, i, NULL);
+           regcache->raw_supply (i, NULL);
            continue;
          }
 
@@ -643,7 +639,7 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
                    if (val[0] & (1 << fpreg))
                      {
                        int thisreg = (fpreg + 8 - top) % 8 
-                                      + I387_ST0_REGNUM (tdep);
+                                      + I387_ST0_REGNUM (tdep);
                        tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg));
                      }
                    else
@@ -654,18 +650,18 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
                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));
     }
 }
@@ -678,7 +674,8 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
 void
 i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+  gdbarch *arch = regcache->arch ();
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch);
   gdb_byte *regs = (gdb_byte *) fxsave;
   int i;
 
@@ -689,18 +686,18 @@ i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
     if (regnum == -1 || regnum == i)
       {
        /* Most of the FPU control registers occupy only 16 bits in
-           the fxsave area.  Give those a special treatment.  */
+          the fxsave area.  Give those a special treatment.  */
        if (i >= I387_FCTRL_REGNUM (tdep) && i < I387_XMM0_REGNUM (tdep)
            && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
          {
            gdb_byte buf[4];
 
-           regcache_raw_collect (regcache, i, buf);
+           regcache->raw_collect (i, buf);
 
            if (i == I387_FOP_REGNUM (tdep))
              {
                /* The opcode occupies only 11 bits.  Make sure we
-                   don't touch the other bits.  */
+                  don't touch the other bits.  */
                buf[1] &= ((1 << 3) - 1);
                buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1));
              }
@@ -726,181 +723,339 @@ i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
            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));
 }
 
 /* `xstate_bv' is at byte offset 512.  */
 #define XSAVE_XSTATE_BV_ADDR(xsave) (xsave + 512)
 
-/* At xsave_avxh_offset[REGNUM] you'll find the offset to the location in
-   the upper 128bit of AVX register data structure used by the "xsave"
-   instruction where GDB register REGNUM is stored.  */
+/* At xsave_avxh_offset[REGNUM] you'll find the relative offset within
+   the AVX region of the XSAVE extended state where the upper 128bits
+   of GDB register YMM0 + REGNUM is stored.  */
 
 static int xsave_avxh_offset[] =
 {
-  576 + 0 * 16,                /* Upper 128bit of %ymm0 through ...  */
-  576 + 1 * 16,
-  576 + 2 * 16,
-  576 + 3 * 16,
-  576 + 4 * 16,
-  576 + 5 * 16,
-  576 + 6 * 16,
-  576 + 7 * 16,
-  576 + 8 * 16,
-  576 + 9 * 16,
-  576 + 10 * 16,
-  576 + 11 * 16,
-  576 + 12 * 16,
-  576 + 13 * 16,
-  576 + 14 * 16,
-  576 + 15 * 16                /* Upper 128bit of ... %ymm15 (128 bits each).  */
+  0 * 16,              /* Upper 128bit of %ymm0 through ...  */
+  1 * 16,
+  2 * 16,
+  3 * 16,
+  4 * 16,
+  5 * 16,
+  6 * 16,
+  7 * 16,
+  8 * 16,
+  9 * 16,
+  10 * 16,
+  11 * 16,
+  12 * 16,
+  13 * 16,
+  14 * 16,
+  15 * 16              /* Upper 128bit of ... %ymm15 (128 bits each).  */
 };
 
-#define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
+#define XSAVE_AVXH_ADDR(tdep, xsave, regnum)                   \
+  (xsave + (tdep)->xsave_layout.avx_offset                     \
+   + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
 
-/* At xsave_ymm_avx512_offset[REGNUM] you'll find the offset to the location in
-   the upper 128bit of ZMM register data structure used by the "xsave"
-   instruction where GDB register REGNUM is stored.  */
+/* At xsave_ymm_avx512_offset[REGNUM] you'll find the relative offset
+   within the ZMM region of the XSAVE extended state where the second
+   128bits of GDB register YMM16 + REGNUM is stored.  */
 
 static int xsave_ymm_avx512_offset[] =
 {
-  /* HI16_ZMM_area + 16 bytes + regnum* 64 bytes.  */
-  1664 + 16 + 0 * 64,          /* %ymm16 through...  */
-  1664 + 16 + 1 * 64,
-  1664 + 16 + 2 * 64,
-  1664 + 16 + 3 * 64,
-  1664 + 16 + 4 * 64,
-  1664 + 16 + 5 * 64,
-  1664 + 16 + 6 * 64,
-  1664 + 16 + 7 * 64,
-  1664 + 16 + 8 * 64,
-  1664 + 16 + 9 * 64,
-  1664 + 16 + 10 * 64,
-  1664 + 16 + 11 * 64,
-  1664 + 16 + 12 * 64,
-  1664 + 16 + 13 * 64,
-  1664 + 16 + 14 * 64,
-  1664 + 16 + 15 * 64          /* ...  %ymm31 (128 bits each).  */
+  16 + 0 * 64,         /* %ymm16 through...  */
+  16 + 1 * 64,
+  16 + 2 * 64,
+  16 + 3 * 64,
+  16 + 4 * 64,
+  16 + 5 * 64,
+  16 + 6 * 64,
+  16 + 7 * 64,
+  16 + 8 * 64,
+  16 + 9 * 64,
+  16 + 10 * 64,
+  16 + 11 * 64,
+  16 + 12 * 64,
+  16 + 13 * 64,
+  16 + 14 * 64,
+  16 + 15 * 64         /* ...  %ymm31 (128 bits each).  */
 };
 
-#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)])
+#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum)                     \
+  (xsave + (tdep)->xsave_layout.zmm_offset                             \
+   + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)])
+
+/* At xsave_xmm_avx512_offset[REGNUM] you'll find the relative offset
+   within the ZMM region of the XSAVE extended state where the first
+   128bits of GDB register XMM16 + REGNUM is stored.  */
 
 static int xsave_xmm_avx512_offset[] =
 {
-  1664 + 0 * 64,               /* %ymm16 through...  */
-  1664 + 1 * 64,
-  1664 + 2 * 64,
-  1664 + 3 * 64,
-  1664 + 4 * 64,
-  1664 + 5 * 64,
-  1664 + 6 * 64,
-  1664 + 7 * 64,
-  1664 + 8 * 64,
-  1664 + 9 * 64,
-  1664 + 10 * 64,
-  1664 + 11 * 64,
-  1664 + 12 * 64,
-  1664 + 13 * 64,
-  1664 + 14 * 64,
-  1664 + 15 * 64               /* ...  %ymm31 (128 bits each).  */
+  0 * 64,                      /* %xmm16 through...  */
+  1 * 64,
+  2 * 64,
+  3 * 64,
+  4 * 64,
+  5 * 64,
+  6 * 64,
+  7 * 64,
+  8 * 64,
+  9 * 64,
+  10 * 64,
+  11 * 64,
+  12 * 64,
+  13 * 64,
+  14 * 64,
+  15 * 64                      /* ...  %xmm31 (128 bits each).  */
 };
 
-#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
+#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum)                     \
+  (xsave + (tdep)->xsave_layout.zmm_offset                             \
+   + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
 
-static int xsave_mpx_offset[] = {
-  960 + 0 * 16,                        /* bnd0r...bnd3r registers.  */
-  960 + 1 * 16,
-  960 + 2 * 16,
-  960 + 3 * 16,
-  1024 + 0 * 8,                        /* bndcfg ... bndstatus.  */
-  1024 + 1 * 8,
+/* At xsave_bndregs_offset[REGNUM] you'll find the relative offset
+   within the BNDREGS region of the XSAVE extended state where the GDB
+   register BND0R + REGNUM is stored.  */
+
+static int xsave_bndregs_offset[] = {
+  0 * 16,                      /* bnd0r...bnd3r registers.  */
+  1 * 16,
+  2 * 16,
+  3 * 16
 };
 
-#define XSAVE_MPX_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)])
+#define XSAVE_BNDREGS_ADDR(tdep, xsave, regnum)                                \
+  (xsave + (tdep)->xsave_layout.bndregs_offset                         \
+   + xsave_bndregs_offset[regnum - I387_BND0R_REGNUM (tdep)])
 
-  /* At xsave_avx512__h_offset[REGNUM] you find the offset to the location
-   of the AVX512 opmask register data structure used by the "xsave"
-   instruction where GDB register REGNUM is stored.  */
+static int xsave_bndcfg_offset[] = {
+  0 * 8,                       /* bndcfg ... bndstatus.  */
+  1 * 8,
+};
+
+#define XSAVE_BNDCFG_ADDR(tdep, xsave, regnum)                 \
+  (xsave + (tdep)->xsave_layout.bndcfg_offset                  \
+   + xsave_bndcfg_offset[regnum - I387_BNDCFGU_REGNUM (tdep)])
+
+/* At xsave_avx512_k_offset[REGNUM] you'll find the relative offset
+   within the K region of the XSAVE extended state where the AVX512
+   opmask register K0 + REGNUM is stored.  */
 
 static int xsave_avx512_k_offset[] =
 {
-  1088 + 0 * 8,                        /* %k0 through...  */
-  1088 + 1 * 8,
-  1088 + 2 * 8,
-  1088 + 3 * 8,
-  1088 + 4 * 8,
-  1088 + 5 * 8,
-  1088 + 6 * 8,
-  1088 + 7 * 8                 /* %k7 (64 bits each).  */
+  0 * 8,                       /* %k0 through...  */
+  1 * 8,
+  2 * 8,
+  3 * 8,
+  4 * 8,
+  5 * 8,
+  6 * 8,
+  7 * 8                                /* %k7 (64 bits each).  */
+};
+
+#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum)               \
+  (xsave + (tdep)->xsave_layout.k_offset                       \
+   + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)])
+
+
+/* At xsave_avx512_zmm0_h_offset[REGNUM] you find the relative offset
+   within the ZMM_H region of the XSAVE extended state where the upper
+   256bits of the GDB register ZMM0 + REGNUM is stored.  */
+
+static int xsave_avx512_zmm0_h_offset[] =
+{
+  0 * 32,              /* Upper 256bit of %zmmh0 through...  */
+  1 * 32,
+  2 * 32,
+  3 * 32,
+  4 * 32,
+  5 * 32,
+  6 * 32,
+  7 * 32,
+  8 * 32,
+  9 * 32,
+  10 * 32,
+  11 * 32,
+  12 * 32,
+  13 * 32,
+  14 * 32,
+  15 * 32              /* Upper 256bit of...  %zmmh15 (256 bits each).  */
 };
 
-#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)])
+#define XSAVE_AVX512_ZMM0_H_ADDR(tdep, xsave, regnum)                  \
+  (xsave + (tdep)->xsave_layout.zmm_h_offset                           \
+   + xsave_avx512_zmm0_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
 
-/* At xsave_avx512_zmm_h_offset[REGNUM] you find the offset to the location in
-   the upper 256bit of AVX512 ZMMH register data structure used by the "xsave"
-   instruction where GDB register REGNUM is stored.  */
+/* At xsave_avx512_zmm16_h_offset[REGNUM] you find the relative offset
+   within the ZMM_H region of the XSAVE extended state where the upper
+   256bits of the GDB register ZMM16 + REGNUM is stored.  */
 
-static int xsave_avx512_zmm_h_offset[] =
+static int xsave_avx512_zmm16_h_offset[] =
 {
-  1152 + 0 * 32,
-  1152 + 1 * 32,       /* Upper 256bit of %zmmh0 through...  */
-  1152 + 2 * 32,
-  1152 + 3 * 32,
-  1152 + 4 * 32,
-  1152 + 5 * 32,
-  1152 + 6 * 32,
-  1152 + 7 * 32,
-  1152 + 8 * 32,
-  1152 + 9 * 32,
-  1152 + 10 * 32,
-  1152 + 11 * 32,
-  1152 + 12 * 32,
-  1152 + 13 * 32,
-  1152 + 14 * 32,
-  1152 + 15 * 32,      /* Upper 256bit of...  %zmmh15 (256 bits each).  */
-  1664 + 32 + 0 * 64,   /* Upper 256bit of...  %zmmh16 (256 bits each).  */
-  1664 + 32 + 1 * 64,
-  1664 + 32 + 2 * 64,
-  1664 + 32 + 3 * 64,
-  1664 + 32 + 4 * 64,
-  1664 + 32 + 5 * 64,
-  1664 + 32 + 6 * 64,
-  1664 + 32 + 7 * 64,
-  1664 + 32 + 8 * 64,
-  1664 + 32 + 9 * 64,
-  1664 + 32 + 10 * 64,
-  1664 + 32 + 11 * 64,
-  1664 + 32 + 12 * 64,
-  1664 + 32 + 13 * 64,
-  1664 + 32 + 14 * 64,
-  1664 + 32 + 15 * 64   /* Upper 256bit of... %zmmh31 (256 bits each).  */
+  32 + 0 * 64,         /* Upper 256bit of...  %zmmh16 (256 bits each).  */
+  32 + 1 * 64,
+  32 + 2 * 64,
+  32 + 3 * 64,
+  32 + 4 * 64,
+  32 + 5 * 64,
+  32 + 6 * 64,
+  32 + 7 * 64,
+  32 + 8 * 64,
+  32 + 9 * 64,
+  32 + 10 * 64,
+  32 + 11 * 64,
+  32 + 12 * 64,
+  32 + 13 * 64,
+  32 + 14 * 64,
+  32 + 15 * 64         /* Upper 256bit of... %zmmh31 (256 bits each).  */
 };
 
-#define XSAVE_AVX512_ZMM_H_ADDR(tdep, xsave, regnum) \
-  (xsave + xsave_avx512_zmm_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
+#define XSAVE_AVX512_ZMM16_H_ADDR(tdep, xsave, regnum)                 \
+  (xsave + (tdep)->xsave_layout.zmm_offset                             \
+   + xsave_avx512_zmm16_h_offset[regnum - I387_ZMM16H_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.  */
+/* At xsave_pkeys_offset[REGNUM] you'll find the relative offset
+   within the PKEYS region of the XSAVE extended state where the PKRU
+   register is stored.  */
 
 static int xsave_pkeys_offset[] =
 {
-2688 + 0 * 8           /* %pkru (64 bits in XSTATE, 32-bit actually used by
+  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)])
+#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum)                          \
+  (xsave + (tdep)->xsave_layout.pkru_offset                            \
+   + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+
+
+/* See i387-tdep.h.  */
+
+bool
+i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
+                        x86_xsave_layout &layout)
+{
+  if (HAS_PKRU (xcr0) && xsave_size == 2696)
+    {
+      /* Intel CPUs supporting PKRU.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+      layout.k_offset = 1088;
+      layout.zmm_h_offset = 1152;
+      layout.zmm_offset = 1664;
+      layout.pkru_offset = 2688;
+    }
+  else if (HAS_PKRU (xcr0) && xsave_size == 2440)
+    {
+      /* AMD CPUs supporting PKRU.  */
+      layout.avx_offset = 576;
+      layout.k_offset = 832;
+      layout.zmm_h_offset = 896;
+      layout.zmm_offset = 1408;
+      layout.pkru_offset = 2432;
+    }
+  else if (HAS_AVX512 (xcr0) && xsave_size == 2688)
+    {
+      /* Intel CPUs supporting AVX512.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+      layout.k_offset = 1088;
+      layout.zmm_h_offset = 1152;
+      layout.zmm_offset = 1664;
+    }
+  else if (HAS_MPX (xcr0) && xsave_size == 1088)
+    {
+      /* Intel CPUs supporting MPX.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+    }
+  else if (HAS_AVX (xcr0) && xsave_size == 832)
+    {
+      /* Intel and AMD CPUs supporting AVX.  */
+      layout.avx_offset = 576;
+    }
+  else
+    return false;
+
+  layout.sizeof_xsave = xsave_size;
+  return true;
+}
+
+/* See i387-tdep.h.  */
+
+x86_xsave_layout
+i387_fallback_xsave_layout (uint64_t xcr0)
+{
+  x86_xsave_layout layout;
+
+  if (HAS_PKRU (xcr0))
+    {
+      /* Intel CPUs supporting PKRU.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+      layout.k_offset = 1088;
+      layout.zmm_h_offset = 1152;
+      layout.zmm_offset = 1664;
+      layout.pkru_offset = 2688;
+      layout.sizeof_xsave = 2696;
+    }
+  else if (HAS_AVX512 (xcr0))
+    {
+      /* Intel CPUs supporting AVX512.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+      layout.k_offset = 1088;
+      layout.zmm_h_offset = 1152;
+      layout.zmm_offset = 1664;
+      layout.sizeof_xsave = 2688;
+    }
+  else if (HAS_MPX (xcr0))
+    {
+      /* Intel CPUs supporting MPX.  */
+      layout.avx_offset = 576;
+      layout.bndregs_offset = 960;
+      layout.bndcfg_offset = 1024;
+      layout.sizeof_xsave = 1088;
+    }
+  else if (HAS_AVX (xcr0))
+    {
+      /* Intel and AMD CPUs supporting AVX.  */
+      layout.avx_offset = 576;
+      layout.sizeof_xsave = 832;
+    }
+
+  return layout;
+}
+
+/* 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;
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_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.  */
 
@@ -908,10 +1063,17 @@ void
 i387_supply_xsave (struct regcache *regcache, int regnum,
                   const void *xsave)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct gdbarch *gdbarch = regcache->arch ();
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_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[I386_MAX_REGISTER_SIZE] = { 0 };
   enum
@@ -920,14 +1082,16 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       x87 = 0x1,
       sse = 0x2,
       avxh = 0x4,
-      mpx  = 0x8,
-      avx512_k = 0x10,
-      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 | pkeys
+      bndregs = 0x8,
+      bndcfg = 0x10,
+      avx512_k = 0x20,
+      avx512_zmm0_h = 0x40,
+      avx512_zmm16_h = 0x80,
+      avx512_ymmh_avx512 = 0x100,
+      avx512_xmm_avx512 = 0x200,
+      pkeys = 0x400,
+      all = x87 | sse | avxh | bndregs | bndcfg | avx512_k | avx512_zmm0_h
+           | avx512_zmm16_h | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
     } regclass;
 
   gdb_assert (regs != NULL);
@@ -940,8 +1104,11 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
           && regnum < I387_PKEYSEND_REGNUM (tdep))
     regclass = pkeys;
   else if (regnum >= I387_ZMM0H_REGNUM (tdep)
+          && regnum < I387_ZMM16H_REGNUM (tdep))
+    regclass = avx512_zmm0_h;
+  else if (regnum >= I387_ZMM16H_REGNUM (tdep)
           && regnum < I387_ZMMENDH_REGNUM (tdep))
-    regclass = avx512_zmm_h;
+    regclass = avx512_zmm16_h;
   else if (regnum >= I387_K0_REGNUM (tdep)
           && regnum < I387_KEND_REGNUM (tdep))
     regclass = avx512_k;
@@ -955,8 +1122,11 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
           && regnum < I387_YMMENDH_REGNUM (tdep))
     regclass = avxh;
   else if (regnum >= I387_BND0R_REGNUM (tdep)
+          && regnum < I387_BNDCFGU_REGNUM (tdep))
+    regclass = bndregs;
+  else if (regnum >= I387_BNDCFGU_REGNUM (tdep)
           && regnum < I387_MPXEND_REGNUM (tdep))
-    regclass = mpx;
+    regclass = bndcfg;
   else if (regnum >= I387_XMM0_REGNUM (tdep)
           && regnum < I387_MXCSR_REGNUM (tdep))
     regclass = sse;
@@ -966,20 +1136,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
   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
@@ -997,74 +1154,83 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
 
     case pkeys:
       if ((clear_bv & X86_XSTATE_PKRU))
-       regcache_raw_supply (regcache, regnum, zero);
+       regcache->raw_supply (regnum, zero);
       else
-       regcache_raw_supply (regcache, regnum,
-                            XSAVE_PKEYS_ADDR (tdep, regs, regnum));
+       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);
+    case avx512_zmm0_h:
+      if ((clear_bv & X86_XSTATE_ZMM_H))
+       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_ZMM0_H_ADDR (tdep, regs, regnum));
+      return;
+
+    case avx512_zmm16_h:
+      if ((clear_bv & X86_XSTATE_ZMM))
+       regcache->raw_supply (regnum, zero);
+      else
+       regcache->raw_supply (regnum,
+                             XSAVE_AVX512_ZMM16_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 (regnum, XSAVE_AVXH_ADDR (tdep, regs, regnum));
+      return;
+
+    case bndcfg:
+      if ((clear_bv & X86_XSTATE_BNDCFG))
+       regcache->raw_supply (regnum, zero);
       else
-       regcache_raw_supply (regcache, regnum,
-                            XSAVE_AVXH_ADDR (tdep, regs, regnum));
+       regcache->raw_supply (regnum, XSAVE_BNDCFG_ADDR (tdep, regs, regnum));
       return;
 
-    case mpx:
+    case bndregs:
       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_BNDREGS_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:
@@ -1076,35 +1242,30 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
              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_PKRU_REGNUM (tdep);
                   i < I387_PKEYSEND_REGNUM (tdep);
                   i++)
-               regcache_raw_supply (regcache, i,
-                                    XSAVE_PKEYS_ADDR (tdep, regs, i));
+               regcache->raw_supply (i, XSAVE_PKEYS_ADDR (tdep, regs, i));
            }
        }
 
-      /* Handle the upper ZMM registers.  */
-      if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+      /* 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 | X86_XSTATE_ZMM)))
+         if ((clear_bv & X86_XSTATE_ZMM_H))
            {
-             for (i = I387_ZMM0H_REGNUM (tdep);
-                  i < I387_ZMMENDH_REGNUM (tdep);
-                  i++)
-               regcache_raw_supply (regcache, i, zero);
+             for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+               regcache->raw_supply (i, zero);
            }
          else
            {
-             for (i = I387_ZMM0H_REGNUM (tdep);
-                  i < I387_ZMMENDH_REGNUM (tdep);
-                  i++)
-               regcache_raw_supply (regcache, i,
-                                    XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
+             for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+               regcache->raw_supply (i,
+                                     XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, i));
            }
        }
 
@@ -1116,44 +1277,48 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
              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 = I387_ZMM16H_REGNUM (tdep);
+                  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 = I387_ZMM16H_REGNUM (tdep);
+                  i < I387_ZMMENDH_REGNUM (tdep); i++)
+               regcache->raw_supply (i,
+                                     XSAVE_AVX512_ZMM16_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.  */
@@ -1164,15 +1329,14 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
              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));
            }
        }
 
@@ -1183,14 +1347,13 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
            {
              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_BNDREGS_ADDR (tdep, regs, i));
            }
        }
 
@@ -1201,14 +1364,13 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
            {
              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_BNDCFG_ADDR (tdep, regs, i));
            }
        }
 
@@ -1220,14 +1382,13 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
              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));
            }
        }
 
@@ -1239,14 +1400,14 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
              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;
@@ -1256,10 +1417,30 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
   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];
 
@@ -1267,7 +1448,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
            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
@@ -1299,15 +1480,28 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
                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.  */
@@ -1316,25 +1510,32 @@ void
 i387_collect_xsave (const struct regcache *regcache, int regnum,
                    void *xsave, int gcore)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  gdb_byte *regs = (gdb_byte *) xsave;
-  int i;
+  struct gdbarch *gdbarch = regcache->arch ();
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+  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,
-      pkeys = 0x200 | check,
-      all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
-           | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+      x87_ctrl_or_mxcsr = 0x1,
+      x87 = 0x2,
+      sse = 0x4,
+      avxh = 0x8,
+      bndregs = 0x10,
+      bndcfg = 0x20,
+      avx512_k = 0x40,
+      avx512_zmm0_h = 0x80,
+      avx512_zmm16_h = 0x100,
+      avx512_ymmh_avx512 = 0x200,
+      avx512_xmm_avx512 = 0x400,
+      pkeys = 0x800,
+      all = x87 | sse | avxh | bndregs | bndcfg | avx512_k | avx512_zmm0_h
+           | avx512_zmm16_h | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
     } regclass;
 
   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
@@ -1346,8 +1547,11 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
           && regnum < I387_PKEYSEND_REGNUM (tdep))
     regclass = pkeys;
   else if (regnum >= I387_ZMM0H_REGNUM (tdep)
+          && regnum < I387_ZMM16H_REGNUM (tdep))
+    regclass = avx512_zmm0_h;
+  else if (regnum >= I387_ZMM16H_REGNUM (tdep)
           && regnum < I387_ZMMENDH_REGNUM (tdep))
-    regclass = avx512_zmm_h;
+    regclass = avx512_zmm16_h;
   else if (regnum >= I387_K0_REGNUM (tdep)
           && regnum < I387_KEND_REGNUM (tdep))
     regclass = avx512_k;
@@ -1361,21 +1565,28 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
           && regnum < I387_YMMENDH_REGNUM (tdep))
     regclass = avxh;
   else if (regnum >= I387_BND0R_REGNUM (tdep)
+          && regnum < I387_BNDCFGU_REGNUM (tdep))
+    regclass = bndregs;
+  else if (regnum >= I387_BNDCFGU_REGNUM (tdep)
           && regnum < I387_MPXEND_REGNUM (tdep))
-    regclass = mpx;
+    regclass = bndcfg;
   else if (regnum >= I387_XMM0_REGNUM (tdep)
           && regnum < I387_MXCSR_REGNUM (tdep))
     regclass = sse;
   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 (_("invalid i387 regnum %d"), regnum);
 
   if (gcore)
     {
       /* Clear XSAVE extended state.  */
-      memset (regs, 0, X86_XSTATE_SIZE (tdep->xcr0));
+      memset (regs, 0, tdep->xsave_layout.sizeof_xsave);
 
       /* Update XCR0 and `xstate_bv' with XCR0 for gcore.  */
       if (tdep->xsave_xcr0_offset != -1)
@@ -1383,361 +1594,408 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
       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);
-
-      /* 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_PKRU))
+       for (i = I387_PKRU_REGNUM (tdep);
+            i < I387_PKEYSEND_REGNUM (tdep); i++)
+         memset (XSAVE_PKEYS_ADDR (tdep, regs, i), 0, 4);
 
-      /* Clear register set if its bit in xstat_bv is zero.  */
-      if (clear_bv)
-       {
-         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);
+      if ((clear_bv & X86_XSTATE_BNDREGS))
+       for (i = I387_BND0R_REGNUM (tdep);
+            i < I387_BNDCFGU_REGNUM (tdep); i++)
+         memset (XSAVE_BNDREGS_ADDR (tdep, regs, i), 0, 16);
 
-         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_BNDCFG_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_ZMM0_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 = I387_ZMM16H_REGNUM (tdep); i < I387_ZMMENDH_REGNUM (tdep);
+              i++)
+           memset (XSAVE_AVX512_ZMM16_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 PKEYS registers are changed.  */
-         if ((tdep->xcr0 & X86_XSTATE_PKRU))
-           for (i = I387_PKRU_REGNUM (tdep);
-                i < I387_PKEYSEND_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_PKEYS_ADDR (tdep, regs, i);
-               if (memcmp (raw, p, 4) != 0)
-                 {
-                   xstate_bv |= X86_XSTATE_PKRU;
-                   memcpy (p, raw, 4);
-                 }
+               xstate_bv |= X86_XSTATE_PKRU;
+               memcpy (p, raw, 4);
+             }
+         }
+
+      /* Check if any ZMMH registers are changed.  */
+      if ((tdep->xcr0 & X86_XSTATE_ZMM))
+       for (i = I387_ZMM16H_REGNUM (tdep);
+            i < I387_ZMMENDH_REGNUM (tdep); i++)
+         {
+           regcache->raw_collect (i, raw);
+           p = XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, i);
+           if (memcmp (raw, p, 32) != 0)
+             {
+               xstate_bv |= X86_XSTATE_ZMM;
+               memcpy (p, raw, 32);
              }
+         }
 
-         /* 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 ((tdep->xcr0 & X86_XSTATE_ZMM_H))
+       for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+         {
+           regcache->raw_collect (i, raw);
+           p = XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, i);
+           if (memcmp (raw, p, 32) != 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_ZMM_H;
+               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++)
+      /* 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)
              {
-               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_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_BNDREGS_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_BNDCFG_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
+         }
+    }
+  else
+    {
+      /* Check if REGNUM is changed.  */
+      regcache->raw_collect (regnum, raw);
+
+      switch (regclass)
        {
-         /* Check if REGNUM is changed.  */
-         regcache_raw_collect (regcache, regnum, raw);
+       default:
+         internal_error (_("invalid i387 regclass"));
 
-         switch (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 pkeys:
-             /* This is a PKEYS register.  */
-             p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
-             if (memcmp (raw, p, 4) != 0)
-               {
-                 xstate_bv |= X86_XSTATE_PKRU;
-                 memcpy (p, raw, 4);
-               }
-             break;
+             xstate_bv |= X86_XSTATE_PKRU;
+             memcpy (p, raw, 4);
+           }
+         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_zmm16_h:
+         /* This is a ZMM16-31 register.  */
+         p = XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, regnum);
+         if (memcmp (raw, p, 32) != 0)
+           {
+             xstate_bv |= X86_XSTATE_ZMM;
+             memcpy (p, raw, 32);
+           }
+         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_zmm0_h:
+         /* This is a ZMM0-15 register.  */
+         p = XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, regnum);
+         if (memcmp (raw, p, 32) != 0)
+           {
+             xstate_bv |= X86_XSTATE_ZMM_H;
+             memcpy (p, raw, 32);
+           }
+         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_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 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_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 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 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 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;
+       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 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 bndregs:
+         regcache->raw_collect (regnum, raw);
+         p = XSAVE_BNDREGS_ADDR (tdep, regs, regnum);
+         if (memcmp (raw, p, 16))
+           {
+             xstate_bv |= X86_XSTATE_BNDREGS;
+             memcpy (p, raw, 16);
            }
-       }
+         break;
+
+       case bndcfg:
+         p = XSAVE_BNDCFG_ADDR (tdep, regs, regnum);
+         xstate_bv |= X86_XSTATE_BNDCFG;
+         memcpy (p, raw, 8);
+         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:
-           case pkeys:
-             /* 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.  */
@@ -1751,7 +2009,7 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
          {
            gdb_byte buf[4];
 
-           regcache_raw_collect (regcache, i, buf);
+           regcache->raw_collect (i, buf);
 
            if (i == I387_FOP_REGNUM (tdep))
              {
@@ -1779,15 +2037,38 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
                      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
@@ -1844,7 +2125,7 @@ i387_tag (const gdb_byte *raw)
 void
 i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
   ULONGEST fstat;
 
   /* Set the top of the floating-point register stack to 7.  The
@@ -1867,7 +2148,7 @@ i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
 void
 i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
 
   if (I387_BND0R_REGNUM (tdep) > 0)
     {
@@ -1875,6 +2156,6 @@ i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache)
 
       memset (bnd_buf, 0, 16);
       for (int i = 0; i < I387_NUM_BND_REGS; i++)
-       regcache_raw_write (regcache, I387_BND0R_REGNUM (tdep) + i, bnd_buf);
+       regcache->raw_write (I387_BND0R_REGNUM (tdep) + i, bnd_buf);
     }
 }