[2/2] gdb, gdbserver: Add Intel APX register support

Message ID 20260602111122.3187712-3-christina.schimpe@intel.com
State New
Headers
Series Add Intel APX support |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Schimpe, Christina June 2, 2026, 11:11 a.m. UTC
  From: "H.J. Lu" <hjl.tools@gmail.com>

Intel(R) Advanced Performance Extensions (APX) doubles the number of
general-purpose registers (GPRs) from 16 to 32 (r16-r31).

Those new 64-bit Extended GPRs (EGPRs) do not change the size of the
XSAVE area, as they take up the space left behind by the deprecated
MPX registers.

In contrast to the legacy GPRS, EGPRs are not enabled by default in 64-bit
mode but are xcr0 enabled based on APX_F Intel APX state.  Define
X86_XSTATE_APX_F to support this new configuration.

Add gdb and gdbserver registers support for those new 64-bit EGPRs.
Also add byte, word and dword pseudo register support.

Co-authored-by:  Christina Schimpe <christina.schimpe@intel.com>
---
 gdb/NEWS                                      |   4 +
 gdb/amd64-linux-tdep.c                        |   2 +
 gdb/amd64-tdep.c                              | 262 ++++++++++++++----
 gdb/amd64-tdep.h                              |   2 +
 gdb/arch/amd64.c                              |   4 +
 gdb/arch/x86-linux-tdesc-features.c           |   1 +
 gdb/doc/gdb.texinfo                           |   4 +
 gdb/features/Makefile                         |   1 +
 gdb/features/i386/64bit-apx.c                 |  29 ++
 gdb/features/i386/64bit-apx.xml               |  26 ++
 gdb/i386-tdep.c                               |  32 ++-
 gdb/i386-tdep.h                               |  26 ++
 gdb/i387-tdep.c                               | 105 ++++++-
 gdb/i387-tdep.h                               |   6 +
 gdb/nat/x86-xstate.c                          |   1 +
 gdb/target-debug.h                            |   1 +
 gdb/testsuite/gdb.arch/amd64-apx-corefile.exp |  87 ++++++
 gdb/testsuite/gdb.arch/amd64-apx.c            |  83 ++++++
 gdb/testsuite/gdb.arch/amd64-apx.exp          | 106 +++++++
 gdb/testsuite/lib/gdb.exp                     |  59 ++++
 gdbserver/i387-fp.cc                          |  43 +++
 gdbserver/linux-x86-low.cc                    |   4 +-
 gdbsupport/x86-xstate.h                       |  12 +-
 23 files changed, 838 insertions(+), 62 deletions(-)
 create mode 100644 gdb/features/i386/64bit-apx.c
 create mode 100644 gdb/features/i386/64bit-apx.xml
 create mode 100644 gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-apx.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-apx.exp
  

Comments

Eli Zaretskii June 2, 2026, 12:25 p.m. UTC | #1
> From: Christina Schimpe <christina.schimpe@intel.com>
> Cc: hjl.tools@gmail.com,
> 	keiths@redhat.com
> Date: Tue,  2 Jun 2026 11:11:22 +0000
> 
> From: "H.J. Lu" <hjl.tools@gmail.com>
> 
> Intel(R) Advanced Performance Extensions (APX) doubles the number of
> general-purpose registers (GPRs) from 16 to 32 (r16-r31).
> 
> Those new 64-bit Extended GPRs (EGPRs) do not change the size of the
> XSAVE area, as they take up the space left behind by the deprecated
> MPX registers.
> 
> In contrast to the legacy GPRS, EGPRs are not enabled by default in 64-bit
> mode but are xcr0 enabled based on APX_F Intel APX state.  Define
> X86_XSTATE_APX_F to support this new configuration.
> 
> Add gdb and gdbserver registers support for those new 64-bit EGPRs.
> Also add byte, word and dword pseudo register support.
> 
> Co-authored-by:  Christina Schimpe <christina.schimpe@intel.com>
> ---
>  gdb/NEWS                                      |   4 +
>  gdb/amd64-linux-tdep.c                        |   2 +
>  gdb/amd64-tdep.c                              | 262 ++++++++++++++----
>  gdb/amd64-tdep.h                              |   2 +
>  gdb/arch/amd64.c                              |   4 +
>  gdb/arch/x86-linux-tdesc-features.c           |   1 +
>  gdb/doc/gdb.texinfo                           |   4 +
>  gdb/features/Makefile                         |   1 +
>  gdb/features/i386/64bit-apx.c                 |  29 ++
>  gdb/features/i386/64bit-apx.xml               |  26 ++
>  gdb/i386-tdep.c                               |  32 ++-
>  gdb/i386-tdep.h                               |  26 ++
>  gdb/i387-tdep.c                               | 105 ++++++-
>  gdb/i387-tdep.h                               |   6 +
>  gdb/nat/x86-xstate.c                          |   1 +
>  gdb/target-debug.h                            |   1 +
>  gdb/testsuite/gdb.arch/amd64-apx-corefile.exp |  87 ++++++
>  gdb/testsuite/gdb.arch/amd64-apx.c            |  83 ++++++
>  gdb/testsuite/gdb.arch/amd64-apx.exp          | 106 +++++++
>  gdb/testsuite/lib/gdb.exp                     |  59 ++++
>  gdbserver/i387-fp.cc                          |  43 +++
>  gdbserver/linux-x86-low.cc                    |   4 +-
>  gdbsupport/x86-xstate.h                       |  12 +-
>  23 files changed, 838 insertions(+), 62 deletions(-)
>  create mode 100644 gdb/features/i386/64bit-apx.c
>  create mode 100644 gdb/features/i386/64bit-apx.xml
>  create mode 100644 gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
>  create mode 100644 gdb/testsuite/gdb.arch/amd64-apx.c
>  create mode 100644 gdb/testsuite/gdb.arch/amd64-apx.exp

Thanks.

> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -83,6 +83,10 @@
>  
>  * Support for native Thread Local Storage (TLS) variables on Windows.
>  
> +* Support for Intel APX registers on amd64 GNU/Linux.
> +  Support displaying and modifying Intel APX registers (Extended GPRs
> +  $r16 - $r31) including byte, word and dword pseudo registers.

This part is okay.

> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -50709,6 +50709,10 @@ amd64, 32 bits on amd64 with 32-bit pointer size (X32) and 32 bits on i386.
>  Following the restriction of the Linux kernel, only @value{GDBN} for amd64
>  targets makes use of this feature for now.
>  
> +The @samp{org.gnu.gdb.i386.apx} feature is optional.  It should describe
> +16 Extended General Purpose registers (EGPRs) @samp{r16} - @samp{r31} with
> +64 bits each.  All APX registers are valid only on amd64.

"EGPR" and "APX" should be in @acronym.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index eef1924c9f0..7b6169bd35f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -83,6 +83,10 @@ 
 
 * Support for native Thread Local Storage (TLS) variables on Windows.
 
+* Support for Intel APX registers on amd64 GNU/Linux.
+  Support displaying and modifying Intel APX registers (Extended GPRs
+  $r16 - $r31) including byte, word and dword pseudo registers.
+
 * Configure changes
 
 ** --with-babeltrace has been removed.  The babeltrace library was
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index a5ac26654cf..814f1f77fa3 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -113,6 +113,8 @@  int amd64_linux_gregset_reg_offset[] =
   -1, -1, -1, -1, -1, -1, -1, -1,
   -1,				/* PKEYS register pkru  */
   -1, 				/* CET user mode register PL3_SSP.  */
+  -1, -1, -1, -1, -1, -1, -1, -1,     /* r16 ... r31.  */
+  -1, -1, -1, -1, -1, -1, -1, -1,
 
   /* End of hardware registers */
   21 * 8, 22 * 8,		      /* fs_base and gs_base.  */
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 0d23abb3164..a74f94731e1 100755
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -61,6 +61,36 @@ 
 
 /* Register information.  */
 
+/* Number of general purpose registers without APX.  */
+#define AMD64_NUM_GPRS 16
+
+/* Number of lower byte registers without APX.  */
+#define AMD64_NUM_LOWER_BYTE_REGS AMD64_NUM_GPRS
+
+/* Number of byte registers without APX.  */
+#define AMD64_NUM_BYTE_REGS (AMD64_NUM_LOWER_BYTE_REGS + 4)
+
+/* Number of word registers without APX.  */
+#define AMD64_NUM_WORD_REGS AMD64_NUM_GPRS
+
+/* Number of dword registers without APX.  */
+#define AMD64_NUM_DWORD_REGS AMD64_NUM_GPRS
+
+/* Number of general purpose registers with APX.  */
+#define AMD64_APX_NUM_GPRS 32
+
+/* Number of APX lower byte registers.  */
+#define AMD64_APX_NUM_LOWER_BYTE_REGS AMD64_APX_NUM_GPRS
+
+/* Number of APX byte registers.  */
+#define AMD64_APX_NUM_BYTE_REGS (AMD64_APX_NUM_LOWER_BYTE_REGS + 4)
+
+/* Number of APX word registers.  */
+#define AMD64_APX_NUM_WORD_REGS AMD64_APX_NUM_GPRS
+
+/* Number of APX dword registers.  */
+#define AMD64_APX_NUM_DWORD_REGS AMD64_APX_NUM_GPRS
+
 static const char * const amd64_register_names[] =
 {
   "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp",
@@ -87,6 +117,12 @@  static const char * const amd64_ymm_names[] =
   "ymm12", "ymm13", "ymm14", "ymm15"
 };
 
+static const char * const amd64_apx_names[] =
+{
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
 static const char * const amd64_ymm_avx512_names[] =
 {
   "ymm16", "ymm17", "ymm18", "ymm19",
@@ -252,7 +288,20 @@  static int amd64_dwarf_regmap[] =
   AMD64_K0_REGNUM + 0, AMD64_K0_REGNUM + 1,
   AMD64_K0_REGNUM + 2, AMD64_K0_REGNUM + 3,
   AMD64_K0_REGNUM + 4, AMD64_K0_REGNUM + 5,
-  AMD64_K0_REGNUM + 6, AMD64_K0_REGNUM + 7
+  AMD64_K0_REGNUM + 6, AMD64_K0_REGNUM + 7,
+
+  /* Reserved.  */
+  -1, -1, -1, -1,
+
+  /* r16-r31.  */
+  AMD64_R16_REGNUM + 0, AMD64_R16_REGNUM + 1,
+  AMD64_R16_REGNUM + 2, AMD64_R16_REGNUM + 3,
+  AMD64_R16_REGNUM + 4, AMD64_R16_REGNUM + 5,
+  AMD64_R16_REGNUM + 6, AMD64_R16_REGNUM + 7,
+  AMD64_R16_REGNUM + 8, AMD64_R16_REGNUM + 9,
+  AMD64_R16_REGNUM + 10, AMD64_R16_REGNUM + 11,
+  AMD64_R16_REGNUM + 12, AMD64_R16_REGNUM + 13,
+  AMD64_R16_REGNUM + 14, AMD64_R16_REGNUM + 15
 };
 
 static const int amd64_dwarf_regmap_len =
@@ -322,8 +371,19 @@  static const char * const amd64_byte_names[] =
   "ah", "bh", "ch", "dh"
 };
 
-/* Number of lower byte registers.  */
-#define AMD64_NUM_LOWER_BYTE_REGS 16
+static_assert (ARRAY_SIZE (amd64_byte_names) == AMD64_NUM_BYTE_REGS);
+
+static const char * const amd64_apx_byte_names[] =
+{
+  "al", "bl", "cl", "dl", "sil", "dil", "bpl", "spl",
+  "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l",
+  "r16l", "r17l", "r18l", "r19l", "r20l", "r21l", "r22l", "r23l",
+  "r24l", "r25l", "r26l", "r27l", "r28l", "r29l", "r30l", "r31l",
+  "ah", "bh", "ch", "dh"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_byte_names)
+	       == AMD64_APX_NUM_BYTE_REGS);
 
 /* Register names for word pseudo-registers.  */
 
@@ -333,6 +393,19 @@  static const char * const amd64_word_names[] =
   "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
 };
 
+static_assert (ARRAY_SIZE (amd64_word_names) == AMD64_NUM_WORD_REGS);
+
+static const char * const amd64_apx_word_names[] =
+{
+  "ax", "bx", "cx", "dx", "si", "di", "bp", "",
+  "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
+  "r16w", "r17w", "r18w", "r19w", "r20w", "r21w", "r22w", "r23w",
+  "r24w", "r25w", "r26w", "r27w", "r28w", "r29w", "r30w", "r31w"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_word_names)
+	       == AMD64_APX_NUM_WORD_REGS);
+
 /* Register names for dword pseudo-registers.  */
 
 static const char * const amd64_dword_names[] =
@@ -342,28 +415,90 @@  static const char * const amd64_dword_names[] =
   "eip"
 };
 
+static_assert (ARRAY_SIZE (amd64_dword_names) == AMD64_NUM_DWORD_REGS + 1);
+
+static const char * const amd64_apx_dword_names[] =
+{
+  "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
+  "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
+  "r16d", "r17d", "r18d", "r19d", "r20d", "r21d", "r22d", "r23d",
+  "r24d", "r25d", "r26d", "r27d", "r28d", "r29d", "r30d", "r31d",
+  "eip"
+};
+
+static_assert (ARRAY_SIZE (amd64_apx_dword_names)
+	       == AMD64_APX_NUM_DWORD_REGS + 1);
+
 /* Return the name of register REGNUM.  */
 
 static const char *
 amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
 {
   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-  if (i386_byte_regnum_p (gdbarch, regnum))
-    return amd64_byte_names[regnum - tdep->al_regnum];
-  else if (i386_zmm_regnum_p (gdbarch, regnum))
+  if (i386_zmm_regnum_p (gdbarch, regnum))
     return amd64_zmm_names[regnum - tdep->zmm0_regnum];
   else if (i386_ymm_regnum_p (gdbarch, regnum))
     return amd64_ymm_names[regnum - tdep->ymm0_regnum];
   else if (i386_ymm_avx512_regnum_p (gdbarch, regnum))
     return amd64_ymm_avx512_names[regnum - tdep->ymm16_regnum];
-  else if (i386_word_regnum_p (gdbarch, regnum))
-    return amd64_word_names[regnum - tdep->ax_regnum];
   else if (i386_dword_regnum_p (gdbarch, regnum))
-    return amd64_dword_names[regnum - tdep->eax_regnum];
+    return tdep->dword_names[regnum - tdep->eax_regnum];
   else
     return i386_pseudo_register_name (gdbarch, regnum);
 }
 
+/* Return the raw byte register number.  *PART is set to 1 for high
+   byte register and 0 otherwise.  */
+
+static int
+amd64_raw_byte_register (i386_gdbarch_tdep *tdep, int regnum, int *part)
+{
+  int gpnum = regnum - tdep->al_regnum;
+
+  /* Extract (always little endian).  */
+  if (gpnum >= tdep->num_lower_byte_regs)
+    {
+      /* Special handling for AH, BH, CH, DH.  */
+      *part = 1;
+      gpnum -= tdep->num_lower_byte_regs;
+    }
+  else
+    {
+      *part = 0;
+      if (gpnum >= AMD64_NUM_GPRS)
+	{
+	  gdb_assert (tdep->r16_regnum != -1);
+	  gpnum += tdep->r16_regnum - 16;
+	}
+    }
+  return gpnum;
+}
+
+/* Return the raw word register number.  */
+
+static int
+amd64_raw_word_register (i386_gdbarch_tdep *tdep, int regnum)
+{
+  int gpnum = regnum - tdep->ax_regnum;
+  if (gpnum >= 16)
+    gpnum += tdep->r16_regnum - 16;
+  return gpnum;
+}
+
+/* Return the raw dword register number.  For x32, the last dword
+   register is EIP.  */
+
+static int
+amd64_raw_dword_register (i386_gdbarch_tdep *tdep, int regnum)
+{
+  int gpnum = regnum - tdep->eax_regnum;
+  if (tdep->eip_regnum == gpnum)
+    return AMD64_RIP_REGNUM;
+  if (gpnum >= 16)
+    gpnum += tdep->r16_regnum - 16;
+  return gpnum;
+}
+
 static value *
 amd64_pseudo_register_read_value (gdbarch *gdbarch, const frame_info_ptr &next_frame,
 				  int regnum)
@@ -372,23 +507,18 @@  amd64_pseudo_register_read_value (gdbarch *gdbarch, const frame_info_ptr &next_f
 
   if (i386_byte_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->al_regnum;
-
-      /* Extract (always little endian).  */
-      if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
-	{
-	  gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
-
-	  /* Special handling for AH, BH, CH, DH.  */
-	  return pseudo_from_raw_part (next_frame, regnum, gpnum, 1);
-	}
-      else
-	return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
+      int part;
+      const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+      return pseudo_from_raw_part (next_frame, regnum, gpnum, part);
+    }
+  else if (i386_word_regnum_p (gdbarch, regnum))
+    {
+      const int gpnum = amd64_raw_word_register (tdep, regnum);
+      return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->eax_regnum;
-
+      const int gpnum = amd64_raw_dword_register (tdep, regnum);
       return pseudo_from_raw_part (next_frame, regnum, gpnum, 0);
     }
   else
@@ -403,19 +533,18 @@  amd64_pseudo_register_write (gdbarch *gdbarch, const frame_info_ptr &next_frame,
 
   if (i386_byte_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->al_regnum;
-
-      if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
-	{
-	  gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
-	  pseudo_to_raw_part (next_frame, buf, gpnum, 1);
-	}
-      else
-	pseudo_to_raw_part (next_frame, buf, gpnum, 0);
+      int part;
+      const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+      pseudo_to_raw_part (next_frame, buf, gpnum, part);
+    }
+  else if (i386_word_regnum_p (gdbarch, regnum))
+    {
+      const int gpnum = amd64_raw_word_register (tdep, regnum);
+      pseudo_to_raw_part (next_frame, buf, gpnum, 0);
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->eax_regnum;
+      const int gpnum = amd64_raw_dword_register (tdep, regnum);
       pseudo_to_raw_part (next_frame, buf, gpnum, 0);
     }
   else
@@ -432,17 +561,18 @@  amd64_ax_pseudo_register_collect (struct gdbarch *gdbarch,
 
   if (i386_byte_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->al_regnum;
-
-      if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
-	ax_reg_mask (ax, gpnum - AMD64_NUM_LOWER_BYTE_REGS);
-      else
-	ax_reg_mask (ax, gpnum);
+      int part;
+      const int gpnum = amd64_raw_byte_register (tdep, regnum, &part);
+      ax_reg_mask (ax, gpnum);
+    }
+  else if (i386_word_regnum_p (gdbarch, regnum))
+    {
+      const int gpnum = amd64_raw_word_register (tdep, regnum);
+      ax_reg_mask (ax, gpnum);
     }
   else if (i386_dword_regnum_p (gdbarch, regnum))
     {
-      int gpnum = regnum - tdep->eax_regnum;
-
+      const int gpnum = amd64_raw_dword_register (tdep, regnum);
       ax_reg_mask (ax, gpnum);
     }
   else
@@ -3552,9 +3682,30 @@  amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
   if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp") != nullptr)
     tdep->ssp_regnum = AMD64_PL3_SSP_REGNUM;
 
-  tdep->num_byte_regs = 20;
-  tdep->num_word_regs = 16;
-  tdep->num_dword_regs = 16;
+  if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx") != nullptr)
+    {
+      tdep->apx_register_names = amd64_apx_names;
+      tdep->num_apx_regs = 16;
+      tdep->r16_regnum = AMD64_R16_REGNUM;
+      tdep->byte_names = amd64_apx_byte_names;
+      tdep->word_names = amd64_apx_word_names;
+      tdep->dword_names = amd64_apx_dword_names;
+      tdep->num_lower_byte_regs = AMD64_APX_NUM_LOWER_BYTE_REGS;
+      tdep->num_byte_regs = AMD64_APX_NUM_BYTE_REGS;
+      tdep->num_word_regs = AMD64_APX_NUM_WORD_REGS;
+      tdep->num_dword_regs = AMD64_APX_NUM_DWORD_REGS;
+    }
+  else
+    {
+      tdep->byte_names = amd64_byte_names;
+      tdep->word_names = amd64_word_names;
+      tdep->dword_names = amd64_dword_names;
+      tdep->num_lower_byte_regs = AMD64_NUM_LOWER_BYTE_REGS;
+      tdep->num_byte_regs = AMD64_NUM_BYTE_REGS;
+      tdep->num_word_regs = AMD64_NUM_WORD_REGS;
+      tdep->num_dword_regs = AMD64_NUM_DWORD_REGS;
+    }
+
   /* Avoid wiring in the MMX registers for now.  */
   tdep->num_mmx_regs = 0;
 
@@ -3663,15 +3814,13 @@  static struct type *
 amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 {
   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+  const int gpnum = regnum - tdep->eax_regnum;
 
-  switch (regnum - tdep->eax_regnum)
-    {
-    case AMD64_RBP_REGNUM:	/* %ebp */
-    case AMD64_RSP_REGNUM:	/* %esp */
-      return builtin_type (gdbarch)->builtin_data_ptr;
-    case AMD64_RIP_REGNUM:	/* %eip */
-      return builtin_type (gdbarch)->builtin_func_ptr;
-    }
+  if (gpnum == tdep->eip_regnum)		/* %eip.  */
+    return builtin_type (gdbarch)->builtin_func_ptr;
+  else if (gpnum == AMD64_RBP_REGNUM		/* %ebp.  */
+	   || gpnum == AMD64_RSP_REGNUM)	/* %esp.  */
+    return builtin_type (gdbarch)->builtin_data_ptr;
 
   return i386_pseudo_register_type (gdbarch, regnum);
 }
@@ -3684,7 +3833,10 @@  amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
 
   amd64_init_abi (info, gdbarch, default_tdesc);
 
-  tdep->num_dword_regs = 17;
+  /* Set %eip to the last dword register.  */
+  tdep->eip_regnum = tdep->num_dword_regs;
+  /* Increment 1 for %eip.  */
+  tdep->num_dword_regs += 1;
   set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
 
   set_gdbarch_long_bit (gdbarch, 32);
@@ -3706,12 +3858,14 @@  const struct target_desc *
 amd64_target_description (uint64_t xstate_bv, bool segments)
 {
   static const_target_desc_up amd64_tdescs \
-    [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*segments*/] = {};
+    [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*APX*/] \
+    [2/*segments*/] = {};
   const_target_desc_up &tdesc
     = amd64_tdescs[(xstate_bv & X86_XSTATE_AVX) ? 1 : 0]
 		  [(xstate_bv & X86_XSTATE_AVX512) ? 1 : 0]
 		  [(xstate_bv & X86_XSTATE_PKRU) ? 1 : 0]
 		  [(xstate_bv & X86_XSTATE_CET_U) ? 1 : 0]
+		  [(xstate_bv & X86_XSTATE_APX_F) ? 1 : 0]
 		  [segments ? 1 : 0];
 
   if (tdesc == nullptr)
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index 3de28952cca..93b3cb61b17 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -82,6 +82,8 @@  enum amd64_regnum
   AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31,
   AMD64_PKRU_REGNUM,
   AMD64_PL3_SSP_REGNUM,
+  AMD64_R16_REGNUM,
+  AMD64_R31_REGNUM = AMD64_R16_REGNUM + 15,
   AMD64_FSBASE_REGNUM,
   AMD64_GSBASE_REGNUM
 };
diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c
index d1a871dd6cb..3992bbf512e 100644
--- a/gdb/arch/amd64.c
+++ b/gdb/arch/amd64.c
@@ -23,6 +23,7 @@ 
 #include "../features/i386/64bit-avx.c"
 #include "../features/i386/64bit-avx512.c"
 #include "../features/i386/64bit-core.c"
+#include "../features/i386/64bit-apx.c"
 #include "../features/i386/64bit-linux.c"
 #include "../features/i386/64bit-segments.c"
 #include "../features/i386/64bit-sse.c"
@@ -78,5 +79,8 @@  amd64_create_target_description (uint64_t xstate_bv, bool is_x32,
 	regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
     }
 
+  if (xstate_bv & X86_XSTATE_APX_F)
+    regnum = create_feature_i386_64bit_apx (tdesc.get (), regnum);
+
   return tdesc;
 }
diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c
index 5d6ea7cc701..0191f326834 100644
--- a/gdb/arch/x86-linux-tdesc-features.c
+++ b/gdb/arch/x86-linux-tdesc-features.c
@@ -65,6 +65,7 @@  struct x86_xstate_feature {
 
 static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = {
   /* Feature,           i386,	amd64,	x32.  */
+  { X86_XSTATE_APX_F,	false,	true, 	true },
   { X86_XSTATE_CET_U,	false,	true, 	true },
   { X86_XSTATE_PKRU,	true,	true, 	true },
   { X86_XSTATE_AVX512,	true,	true, 	true },
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 636fd0d6b1f..da887665e19 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -50709,6 +50709,10 @@  amd64, 32 bits on amd64 with 32-bit pointer size (X32) and 32 bits on i386.
 Following the restriction of the Linux kernel, only @value{GDBN} for amd64
 targets makes use of this feature for now.
 
+The @samp{org.gnu.gdb.i386.apx} feature is optional.  It should describe
+16 Extended General Purpose registers (EGPRs) @samp{r16} - @samp{r31} with
+64 bits each.  All APX registers are valid only on amd64.
+
 @node LoongArch Features
 @subsection LoongArch Features
 @cindex target descriptions, LoongArch Features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 161a7453d66..df716ab6c5e 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -231,6 +231,7 @@  FEATURE_XMLFILES = aarch64-core.xml \
 	i386/32bit-avx512.xml \
 	i386/32bit-segments.xml \
 	i386/32bit-ssp.xml \
+	i386/64bit-apx.xml \
 	i386/64bit-avx512.xml \
 	i386/64bit-core.xml \
 	i386/64bit-segments.xml \
diff --git a/gdb/features/i386/64bit-apx.c b/gdb/features/i386/64bit-apx.c
new file mode 100644
index 00000000000..34cd47131d1
--- /dev/null
+++ b/gdb/features/i386/64bit-apx.c
@@ -0,0 +1,29 @@ 
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: 64bit-apx.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_i386_64bit_apx (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.i386.apx");
+  tdesc_create_reg (feature, "r16", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r17", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r18", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r19", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r20", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r21", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r22", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r23", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r24", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r25", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r26", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r27", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r28", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r29", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r30", regnum++, 1, NULL, 64, "int64");
+  tdesc_create_reg (feature, "r31", regnum++, 1, NULL, 64, "int64");
+  return regnum;
+}
diff --git a/gdb/features/i386/64bit-apx.xml b/gdb/features/i386/64bit-apx.xml
new file mode 100644
index 00000000000..11a4ec67cae
--- /dev/null
+++ b/gdb/features/i386/64bit-apx.xml
@@ -0,0 +1,26 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2024 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.apx">
+  <reg name="r16" bitsize="64" type="int64"/>
+  <reg name="r17" bitsize="64" type="int64"/>
+  <reg name="r18" bitsize="64" type="int64"/>
+  <reg name="r19" bitsize="64" type="int64"/>
+  <reg name="r20" bitsize="64" type="int64"/>
+  <reg name="r21" bitsize="64" type="int64"/>
+  <reg name="r22" bitsize="64" type="int64"/>
+  <reg name="r23" bitsize="64" type="int64"/>
+  <reg name="r24" bitsize="64" type="int64"/>
+  <reg name="r25" bitsize="64" type="int64"/>
+  <reg name="r26" bitsize="64" type="int64"/>
+  <reg name="r27" bitsize="64" type="int64"/>
+  <reg name="r28" bitsize="64" type="int64"/>
+  <reg name="r29" bitsize="64" type="int64"/>
+  <reg name="r30" bitsize="64" type="int64"/>
+  <reg name="r31" bitsize="64" type="int64"/>
+</feature>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index fa935b5fcdb..f36ce36793c 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -412,9 +412,9 @@  i386_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
   else if (i386_zmm_regnum_p (gdbarch, regnum))
     return i386_zmm_names[regnum - tdep->zmm0_regnum];
   else if (i386_byte_regnum_p (gdbarch, regnum))
-    return i386_byte_names[regnum - tdep->al_regnum];
+    return tdep->byte_names[regnum - tdep->al_regnum];
   else if (i386_word_regnum_p (gdbarch, regnum))
-    return i386_word_names[regnum - tdep->ax_regnum];
+    return tdep->word_names[regnum - tdep->ax_regnum];
 
   internal_error (_("invalid regnum"));
 }
@@ -8479,7 +8479,8 @@  i386_xcr0_from_tdesc (const struct target_desc *tdesc)
   const struct tdesc_feature *feature_core;
 
   const struct tdesc_feature *feature_sse, *feature_avx,
-			     *feature_avx512, *feature_pkeys;
+			     *feature_avx512, *feature_pkeys,
+			     *feature_apx;
 
   /* Get core registers.  */
   feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.core");
@@ -8495,6 +8496,9 @@  i386_xcr0_from_tdesc (const struct target_desc *tdesc)
   /* Try AVX512 registers.  */
   feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
 
+  /* Try APX registers.  */
+  feature_apx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx");
+
   /* Try PKEYS  */
   feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys");
 
@@ -8522,6 +8526,9 @@  i386_xcr0_from_tdesc (const struct target_desc *tdesc)
       xcr0 |= X86_XSTATE_AVX512;
     }
 
+  if (feature_apx)
+    xcr0 |= X86_XSTATE_APX_F;
+
   if (feature_pkeys)
     xcr0 |= X86_XSTATE_PKRU;
 
@@ -8537,7 +8544,7 @@  i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
 
   const struct tdesc_feature *feature_sse, *feature_avx, *feature_avx512,
 			     *feature_pkeys, *feature_segments,
-			     *feature_pl3_ssp;
+			     *feature_pl3_ssp, *feature_apx;
   int i, num_regs, valid_p;
 
   if (! tdesc_has_registers (tdesc))
@@ -8557,6 +8564,9 @@  i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
   /* Try AVX512 registers.  */
   feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
 
+  /* Try APX registers.  */
+  feature_apx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.apx");
+
   /* Try segment base registers.  */
   feature_segments = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments");
 
@@ -8641,6 +8651,18 @@  i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
       tdep->num_xmm_regs = 0;
     }
 
+  if (feature_apx
+      && tdep->r16_regnum != -1
+      && tdep->apx_register_names != nullptr
+      && tdep->num_apx_regs > 0)
+    {
+      tdep->xcr0 |= X86_XSTATE_APX_F;
+      for (i = 0; i < tdep->num_apx_regs; i++)
+	valid_p &= tdesc_numbered_register (feature_apx, tdesc_data,
+					    tdep->r16_regnum + i,
+					    tdep->apx_register_names[i]);
+    }
+
   num_regs = tdep->num_core_regs;
   for (i = 0; i < num_regs; i++)
     valid_p &= tdesc_numbered_register (feature_core, tdesc_data, i,
@@ -8908,6 +8930,8 @@  i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   tdep->num_core_regs = I386_NUM_GREGS + I387_NUM_REGS;
   tdep->register_names = i386_register_names;
+  tdep->byte_names = i386_byte_names;
+  tdep->word_names = i386_word_names;
 
   tdep->num_byte_regs = 8;
   tdep->num_word_regs = 8;
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index d64d5241754..bdafd523834 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -108,6 +108,9 @@  struct i386_gdbarch_tdep : gdbarch_tdep_base
      value >= 0.  */
   int al_regnum = -1;
 
+  /* Number of pseudo lower byte registers.  Only used for AMD64.  */
+  int num_lower_byte_regs = 0;
+
   /* Number of pseudo word registers.  */
   int num_word_regs = 0;
 
@@ -121,9 +124,16 @@  struct i386_gdbarch_tdep : gdbarch_tdep_base
      registers are supported.  */
   int eax_regnum = -1;
 
+  /* Register number for %eip.  Set this to a value >= 0 in case of %eip
+     support.  Only used for AMD64.  */
+  int eip_regnum = -1;
+
   /* Number of core registers.  */
   int num_core_regs = 0;
 
+  /* Number of registers added in APX.  Only used for AMD64.  */
+  int num_apx_regs = 0;
+
   /* Number of SSE registers.  */
   int num_xmm_regs = 0;
 
@@ -159,6 +169,15 @@  struct i386_gdbarch_tdep : gdbarch_tdep_base
      supported.  */
   int ymm0h_regnum = -1;
 
+  /* Byte register names.  */
+  const char * const *byte_names = nullptr;
+
+  /* Word register names.  */
+  const char * const *word_names = nullptr;
+
+  /* Dword register names.  Only used for AMD64.  */
+  const char * const *dword_names = nullptr;
+
   /* Upper YMM register names.  Only used for tdesc_numbered_register.  */
   const char * const *ymmh_register_names = nullptr;
 
@@ -173,6 +192,13 @@  struct i386_gdbarch_tdep : gdbarch_tdep_base
      registers are supported.  */
   int zmm0h_regnum = -1;
 
+  /* Register number for %r16.  Set this to a value >= 0 if r16-r31
+     registers are supported.  Only used for AMD64.  */
+  int r16_regnum = -1;
+
+  /* r16-r31 register names.  Only used for tdesc_numbered_register.  */
+  const char * const *apx_register_names = nullptr;
+
   /* OpMask register names.  */
   const char * const *k_register_names = nullptr;
 
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index f33f5ad046e..2b58375eefb 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -818,6 +818,34 @@  static int xsave_xmm_avx512_offset[] =
   (xsave + (tdep)->xsave_layout.zmm_offset				\
    + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
 
+/* At xsave_apx_egpr_offset[REGNUM] you'll find the relative offset
+   within the APX region of the XSAVE extended state where the GDB
+   registers r16 - r31 is stored.  */
+
+static int xsave_apx_egpr_offset[] =
+{
+  0 * 8,			/* r16...r31 registers.  */
+  1 * 8,
+  2 * 8,
+  3 * 8,
+  4 * 8,
+  5 * 8,
+  6 * 8,
+  7 * 8,
+  8 * 8,
+  9 * 8,
+  10 * 8,
+  11 * 8,
+  12 * 8,
+  13 * 8,
+  14 * 8,
+  15 * 8
+};
+
+#define XSAVE_APX_EGPR_ADDR(tdep, xsave, regnum)		\
+  (xsave + (tdep)->xsave_layout.apx_offset			\
+   + xsave_apx_egpr_offset[regnum - I387_R16_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.  */
@@ -920,6 +948,7 @@  i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
     {
       /* Intel CPUs supporting PKRU.  */
       layout.avx_offset = 576;
+      layout.apx_offset = 960;
       layout.k_offset = 1088;
       layout.zmm_h_offset = 1152;
       layout.zmm_offset = 1664;
@@ -938,6 +967,7 @@  i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
     {
       /* Intel CPUs supporting AVX512.  */
       layout.avx_offset = 576;
+      layout.apx_offset = 960;
       layout.k_offset = 1088;
       layout.zmm_h_offset = 1152;
       layout.zmm_offset = 1664;
@@ -968,6 +998,7 @@  i387_fallback_xsave_layout (uint64_t xcr0)
     {
       /* Intel CPUs supporting PKRU.  */
       layout.avx_offset = 576;
+      layout.apx_offset = 960;
       layout.k_offset = 1088;
       layout.zmm_h_offset = 1152;
       layout.zmm_offset = 1664;
@@ -978,6 +1009,7 @@  i387_fallback_xsave_layout (uint64_t xcr0)
     {
       /* Intel CPUs supporting AVX512.  */
       layout.avx_offset = 576;
+      layout.apx_offset = 960;
       layout.k_offset = 1088;
       layout.zmm_h_offset = 1152;
       layout.zmm_offset = 1664;
@@ -1043,8 +1075,9 @@  i387_supply_xsave (struct regcache *regcache, int regnum,
       avx512_ymmh_avx512 = 0x40,
       avx512_xmm_avx512 = 0x80,
       pkeys = 0x100,
+      apx = 0x200,
       all = x87 | sse | avxh | avx512_k | avx512_zmm0_h | avx512_zmm16_h
-	    | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+	    | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys | apx
     } regclass;
 
   gdb_assert (regs != NULL);
@@ -1053,6 +1086,9 @@  i387_supply_xsave (struct regcache *regcache, int regnum,
 
   if (regnum == -1)
     regclass = all;
+  else if (regnum >= I387_R16_REGNUM (tdep)
+	   && regnum < I387_APX_END_REGNUM (tdep))
+    regclass = apx;
   else if (regnum >= I387_PKRU_REGNUM (tdep)
 	   && regnum < I387_PKEYSEND_REGNUM (tdep))
     regclass = pkeys;
@@ -1099,6 +1135,13 @@  i387_supply_xsave (struct regcache *regcache, int regnum,
     case none:
       break;
 
+    case apx:
+      if ((clear_bv & X86_XSTATE_APX_F))
+	regcache->raw_supply_zeroed (regnum);
+      else
+	regcache->raw_supply (regnum, XSAVE_APX_EGPR_ADDR (tdep, regs, regnum));
+      return;
+
     case pkeys:
       if ((clear_bv & X86_XSTATE_PKRU))
 	regcache->raw_supply_zeroed (regnum);
@@ -1274,6 +1317,25 @@  i387_supply_xsave (struct regcache *regcache, int regnum,
 	    }
 	}
 
+      /* Handle the APX register.  */
+      if ((tdep->xcr0 & X86_XSTATE_APX_F) != 0)
+	{
+	  if ((clear_bv & X86_XSTATE_APX_F) != 0)
+	    {
+	      for (i = I387_R16_REGNUM (tdep);
+		   i < I387_APX_END_REGNUM (tdep);
+		   i++)
+		regcache->raw_supply_zeroed (i);
+	    }
+	  else
+	    {
+	      for (i = I387_R16_REGNUM (tdep);
+		   i < I387_APX_END_REGNUM (tdep);
+		   i++)
+		regcache->raw_supply (i, XSAVE_APX_EGPR_ADDR (tdep, regs, i));
+	    }
+	}
+
       /* Handle the XMM registers.  */
       if ((tdep->xcr0 & X86_XSTATE_SSE))
 	{
@@ -1432,8 +1494,9 @@  i387_collect_xsave (const struct regcache *regcache, int regnum,
       avx512_ymmh_avx512 = 0x80,
       avx512_xmm_avx512 = 0x100,
       pkeys = 0x200,
+      apx = 0x400,
       all = x87 | sse | avxh | avx512_k | avx512_zmm0_h | avx512_zmm16_h
-	    | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+	    | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys | apx
     } regclass;
 
   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
@@ -1441,6 +1504,9 @@  i387_collect_xsave (const struct regcache *regcache, int regnum,
 
   if (regnum == -1)
     regclass = all;
+  else if (regnum >= I387_R16_REGNUM (tdep)
+	   && regnum < I387_APX_END_REGNUM (tdep))
+    regclass = apx;
   else if (regnum >= I387_PKRU_REGNUM (tdep)
 	   && regnum < I387_PKEYSEND_REGNUM (tdep))
     regclass = pkeys;
@@ -1505,6 +1571,14 @@  i387_collect_xsave (const struct regcache *regcache, int regnum,
      seem justified at this point.  */
   if (clear_bv)
     {
+      if ((clear_bv & X86_XSTATE_APX_F))
+	{
+	  for (i = I387_R16_REGNUM (tdep);
+	       i < I387_APX_END_REGNUM (tdep);
+	       i++)
+	    memset (XSAVE_APX_EGPR_ADDR (tdep, regs, i), 0, 8);
+	}
+
       if ((clear_bv & X86_XSTATE_PKRU))
 	for (i = I387_PKRU_REGNUM (tdep);
 	     i < I387_PKEYSEND_REGNUM (tdep); i++)
@@ -1571,6 +1645,23 @@  i387_collect_xsave (const struct regcache *regcache, int regnum,
 
   if (regclass == all)
     {
+      /* Check if any APX registers are changed.  */
+      if ((tdep->xcr0 & X86_XSTATE_APX_F))
+	{
+	  for (i = I387_R16_REGNUM (tdep);
+	       i < I387_APX_END_REGNUM (tdep);
+	       i++)
+	    {
+	      regcache->raw_collect (i, raw);
+	      p = XSAVE_APX_EGPR_ADDR (tdep, regs, i);
+	      if (memcmp (raw, p, 8) != 0)
+		{
+		  xstate_bv |= X86_XSTATE_APX_F;
+		  memcpy (p, raw, 8);
+		}
+	    }
+	}
+
       /* Check if any PKEYS registers are changed.  */
       if ((tdep->xcr0 & X86_XSTATE_PKRU))
 	for (i = I387_PKRU_REGNUM (tdep);
@@ -1723,6 +1814,16 @@  i387_collect_xsave (const struct regcache *regcache, int regnum,
 	default:
 	  internal_error (_("invalid i387 regclass"));
 
+	case apx:
+	  regcache->raw_collect (regnum, raw);
+	  p = XSAVE_APX_EGPR_ADDR (tdep, regs, regnum);
+	  if (memcmp (raw, p, 8))
+	    {
+	      xstate_bv |= X86_XSTATE_APX_F;
+	      memcpy (p, raw, 8);
+	    }
+	  break;
+
 	case pkeys:
 	  /* This is a PKEYS register.  */
 	  p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
index 5d063502bce..f029c1e5119 100644
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -37,6 +37,9 @@  struct x86_xsave_layout;
 #define I387_NUM_YMM_REGS(tdep) ((tdep)->num_ymm_regs)
 #define I387_YMM0H_REGNUM(tdep) ((tdep)->ymm0h_regnum)
 
+#define I387_R16_REGNUM(tdep) ((tdep)->r16_regnum)
+#define I387_NUM_APX_REGS(tdep) ((tdep)->num_apx_regs)
+
 /* Set of constants used for 32 and 64-bit.  */
 #define I387_NUM_K_REGS 8
 #define I387_NUM_PKEYS_REGS 1
@@ -75,6 +78,9 @@  struct x86_xsave_layout;
 #define I387_XMM_AVX512_END_REGNUM(tdep) \
   (I387_XMM16_REGNUM (tdep) + I387_NUM_XMM_AVX512_REGS (tdep))
 
+#define I387_APX_END_REGNUM(tdep) \
+  (I387_R16_REGNUM (tdep) + I387_NUM_APX_REGS (tdep))
+
 #define I387_PKEYSEND_REGNUM(tdep) \
   (I387_PKRU_REGNUM (tdep) + I387_NUM_PKEYS_REGS)
 
diff --git a/gdb/nat/x86-xstate.c b/gdb/nat/x86-xstate.c
index c45570179a6..f0f0b00e859 100644
--- a/gdb/nat/x86-xstate.c
+++ b/gdb/nat/x86-xstate.c
@@ -56,6 +56,7 @@  x86_fetch_xsave_layout (uint64_t xcr0, int len)
   x86_xsave_layout layout;
   layout.sizeof_xsave = len;
   layout.avx_offset = xsave_feature_offset (xcr0, X86_XSTATE_AVX_ID);
+  layout.apx_offset = xsave_feature_offset (xcr0, X86_XSTATE_APX_F_ID);
   layout.k_offset = xsave_feature_offset (xcr0, X86_XSTATE_K_ID);
   layout.zmm_h_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_H_ID);
   layout.zmm_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_ID);
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index c86affbc838..949847b181c 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -380,6 +380,7 @@  target_debug_print_x86_xsave_layout (const x86_xsave_layout &layout)
   POFFS(zmm_h);
   POFFS(zmm);
   POFFS(pkru);
+  POFFS(apx);
 
 #undef POFFS
 
diff --git a/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp b/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
new file mode 100644
index 00000000000..6b357a06395
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx-corefile.exp
@@ -0,0 +1,87 @@ 
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# Test apx corefiles.
+
+require allow_apx_tests
+
+standard_testfile amd64-apx.c
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	{debug additional_flags=-mapxf}] } {
+    return -1
+}
+
+set nr_regs 16
+set egpr(1) r16
+set egpr(2) r17
+set egpr(3) r18
+set egpr(4) r19
+set egpr(5) r20
+set egpr(6) r21
+set egpr(7) r22
+set egpr(8) r23
+set egpr(9) r24
+set egpr(10) r25
+set egpr(11) r26
+set egpr(12) r27
+set egpr(13) r28
+set egpr(14) r29
+set egpr(15) r30
+set egpr(16) r31
+
+proc test_apx_corefiles {setting} {
+    global egpr nr_regs
+
+    clean_restart "$::testfile"
+    if { ![runto_main] } {
+	continue
+    }
+
+    set line [gdb_get_line_number "break here"]
+    gdb_breakpoint $line
+    gdb_continue_to_breakpoint "break here" ".*$::srcfile:$line.*"
+
+    gdb_test_no_output "maint set gcore xml-target-description ${setting}"
+
+    set gcorefile "${::binfile}_${setting}.gcore"
+    if { ![gdb_gcore_cmd $gcorefile "save a corefile"] } {
+	return -1
+    }
+
+    # Now restart gdb and load the corefile.
+    clean_restart "$::testfile"
+
+    gdb_test "core ${gcorefile}" \
+	"Core was generated by .*" "re-load generated corefile"
+
+    with_test_prefix "test egpr after corefile load" {
+	for { set r 1 } { $r <= $nr_regs  } { incr r } {
+	set hexr [format %x [expr $r-1]]
+	gdb_test "print/z \$$egpr($r)" \
+	    "= 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1"
+	}
+    }
+}
+
+test_apx_corefiles "on"
+
+# Test the code path without the NT_GDB_TDESC note
+with_test_prefix "no NT_GDB_TDESC" {
+    test_apx_corefiles "off"
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx.c b/gdb/testsuite/gdb.arch/amd64-apx.c
new file mode 100644
index 00000000000..35ce63ab482
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx.c
@@ -0,0 +1,83 @@ 
+/* Copyright 2024 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   Test program for APX Extended GPRs (EGPRs).  */
+
+long data[] = {
+  0x0000000004030201,
+  0x0000000014131211,
+  0x0000000024232221,
+  0x0000000034333231,
+  0x0000000044434241,
+  0x0000000054535251,
+  0x0000000064636261,
+  0x0000000074737271,
+  0x0000000084838281,
+  0x0000000094939291,
+  0x00000000a4a3a2a1,
+  0x00000000b4b3b2b1,
+  0x00000000c4c3c2c1,
+  0x00000000d4d3d2d1,
+  0x00000000e4e3e2e1,
+  0x00000000f4f3f2f1,
+};
+
+int
+main (int argc, char **argv)
+{
+  register long r16 asm ("r16");
+  register long r17 asm ("r17");
+  register long r18 asm ("r18");
+  register long r19 asm ("r19");
+  register long r20 asm ("r20");
+  register long r21 asm ("r21");
+  register long r22 asm ("r22");
+  register long r23 asm ("r23");
+  register long r24 asm ("r24");
+  register long r25 asm ("r25");
+  register long r26 asm ("r26");
+  register long r27 asm ("r27");
+  register long r28 asm ("r28");
+  register long r29 asm ("r29");
+  register long r30 asm ("r30");
+  register long r31 asm ("r31");
+
+  asm ("mov 0(%0), %%r16\n\t"
+       "mov 8(%0), %%r17\n\t"
+       "mov 16(%0), %%r18\n\t"
+       "mov 24(%0), %%r19\n\t"
+       "mov 32(%0), %%r20\n\t"
+       "mov 40(%0), %%r21\n\t"
+       "mov 48(%0), %%r22\n\t"
+       "mov 56(%0), %%r23\n\t"
+       "mov 64(%0), %%r24\n\t"
+       "mov 72(%0), %%r25\n\t"
+       "mov 80(%0), %%r26\n\t"
+       "mov 88(%0), %%r27\n\t"
+       "mov 96(%0), %%r28\n\t"
+       "mov 104(%0), %%r29\n\t"
+       "mov 112(%0), %%r30\n\t"
+       "mov 120(%0), %%r31\n\t"
+       : /* no output operands */
+       : "r" (data)
+       : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+	 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+
+  asm ("nop"); /* break here */
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-apx.exp b/gdb/testsuite/gdb.arch/amd64-apx.exp
new file mode 100644
index 00000000000..ab03e4e7b60
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-apx.exp
@@ -0,0 +1,106 @@ 
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# Test apx dword, word, byte and raw registers.
+
+set nr_regs 16
+set regs(1) r16
+set regs(2) r17
+set regs(3) r18
+set regs(4) r19
+set regs(5) r20
+set regs(6) r21
+set regs(7) r22
+set regs(8) r23
+set regs(9) r24
+set regs(10) r25
+set regs(11) r26
+set regs(12) r27
+set regs(13) r28
+set regs(14) r29
+set regs(15) r30
+set regs(16) r31
+
+proc get_reg_val { type r } {
+    set hexr [format %x [expr $r-1]]
+    if { $type == "d"} {
+	return 0x${hexr}4${hexr}3${hexr}2${hexr}1
+    }
+    if { $type == "w" } {
+	return 0x${hexr}2${hexr}1
+    }
+    if { $type == "l" } {
+	return 0x${hexr}1
+    }
+    if { $type == "" } {
+	return 0x00000000${hexr}4${hexr}3${hexr}2${hexr}1
+    }
+}
+
+proc check_reg_content { type } {
+    global nr_regs
+    global regs
+
+    for { set r 1 } { $r <= $nr_regs  } { incr r } {
+	set regval [get_reg_val $type $r]
+	gdb_test "print/z \$$regs($r)$type" "= $regval"
+    }
+}
+
+require allow_apx_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	{debug additional_flags=-mapxf}] } {
+    return
+}
+
+if { ![runto_main] } {
+    return
+}
+
+set line [gdb_get_line_number "break here"]
+gdb_breakpoint $line
+gdb_continue_to_breakpoint "break here" ".*$srcfile:$line.*"
+
+# Run test for dword, word, byte pseudo registers, as well as raw registers.
+set regtypes [list  "d" "w" "l" ""]
+set regtype_names [list  "dword" "word" "byte" "raw"]
+
+# Check initial register content written by testprogram.
+for { set i 0 } { $i < [llength $regtypes] } { incr i } {
+    set type [lindex $regtypes $i]
+    set type_name [lindex $regtype_names $i]
+    with_test_prefix "$type_name register" {
+	check_reg_content $type
+    }
+}
+
+# Check writing registers with GDB.
+for { set i 0 } { $i < [llength $regtypes] } { incr i } {
+    set type [lindex $regtypes $i]
+    set type_name [lindex $regtype_names $i]
+    with_test_prefix "$type_name register" {
+	for { set r 1 } { $r <= $nr_regs  } { incr r } {
+	    set val [expr $r + $i]
+	    gdb_test_no_output "set var \$$regs($r)$type = $val"
+	    gdb_test "print \$$regs($r)$type" "= $val"
+	}
+    }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index c87876664f0..74b6b7ec6d0 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4730,6 +4730,65 @@  gdb_caching_proc allow_lam_tests {} {
     return $allow_lam_tests
 }
 
+# Run a test on the target to see if it supports APX.  Return 1 if so,
+# 0 if it does not.
+
+gdb_caching_proc allow_apx_tests {} {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "allow_apx_tests"
+    if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+	verbose "$me:  target does not support apx, returning 0" 2
+	return 0
+    }
+
+    # Compile a test program.
+    set src {
+	int data[] = {12345};
+
+	int
+	main (int argc, char **argv)
+	  {
+	    asm ("mov 0(%0), %%r30\n\t"
+		 :  /* no output operands */
+		 : "r" (data));
+	    return 0;
+	  }
+    }
+    set compile_flags "{additional_flags=-mapxf}"
+    if { ![gdb_simple_compile $me $src executable $compile_flags] } {
+	return 0
+    }
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load "$obj"
+    gdb_run_cmd
+    gdb_expect {
+	-re ".*Illegal instruction.*${gdb_prompt} $" {
+	    verbose -log "$me:  apx hardware not detected."
+	    set allow_apx_tests 0
+	}
+	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+	    verbose -log "$me:  apx hardware detected."
+	    set allow_apx_tests 1
+	}
+	default {
+	    warning "\n$me:  default case taken."
+	    set allow_apx_tests 0
+	}
+    }
+    gdb_exit
+    remote_file build delete $obj
+
+    verbose "$me:  returning $allow_apx_tests" 2
+    return $allow_apx_tests
+}
+
+
 # Run a test on the target to see if it supports btrace hardware.  Return 1 if so,
 # 0 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
 
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
index 164b666979f..346f30c637b 100644
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -23,6 +23,7 @@ 
 /* Default to SSE.  */
 static uint64_t x86_xstate_bv = X86_XSTATE_SSE_MASK;
 
+static const int num_apx_registers = 16;
 static const int num_avx512_k_registers = 8;
 static const int num_pkeys_registers = 1;
 
@@ -116,6 +117,10 @@  public:
   unsigned char *ymmh_space ()
   { return xsave () + xsave_layout.avx_offset; }
 
+  /* Memory address of 16 EGPR register values of 64 bits.  */
+  unsigned char *apx_space ()
+  { return xsave () + xsave_layout.apx_offset; }
+
   /* Memory address of 8 OpMask register values of 64 bits.  */
   unsigned char *k_space ()
   { return xsave () + xsave_layout.k_offset; }
@@ -312,6 +317,10 @@  i387_cache_to_xsave (struct regcache *regcache, void *buf)
       if ((clear_bv & X86_XSTATE_PKRU))
 	for (i = 0; i < num_pkeys_registers; i++)
 	  memset (fp->pkru_space () + i * 4, 0, 4);
+
+     if (amd64 && (clear_bv & X86_XSTATE_APX_F) != 0)
+	for (i = 0; i < num_apx_registers; i++)
+	  memset (fp->apx_space () + i * 8, 0, 8);
     }
 
   /* Check if any x87 registers are changed.  */
@@ -465,6 +474,23 @@  i387_cache_to_xsave (struct regcache *regcache, void *buf)
 	}
     }
 
+  /* Check if any APX registers are changed.  */
+  if (amd64 && (x86_xstate_bv & X86_XSTATE_APX_F)!= 0)
+    {
+      int r16_regnum = find_regno (regcache->tdesc, "r16");
+
+      for (i = 0; i < num_apx_registers; i++)
+	{
+	  collect_register (regcache, i + r16_regnum, raw);
+	  p = fp->apx_space () + i * 8;
+	  if (memcmp (raw, p, 8) != 0)
+	    {
+	      xstate_bv |= X86_XSTATE_APX_F;
+	      memcpy (p, raw, 8);
+	    }
+	}
+    }
+
   if (x86_xstate_bv & X86_XSTATE_X87)
     {
       collect_register_by_name (regcache, "fioff", raw);
@@ -790,6 +816,23 @@  i387_xsave_to_cache (struct regcache *regcache, const void *buf)
 	}
     }
 
+  if (amd64 && (x86_xstate_bv & X86_XSTATE_APX_F) != 0)
+    {
+      int r16_regnum = find_regno (regcache->tdesc, "r16");
+
+      if ((clear_bv & X86_XSTATE_APX_F) != 0)
+	{
+	  for (i = 0; i < num_apx_registers; i++)
+	    supply_register_zeroed (regcache, i + r16_regnum);
+	}
+      else
+	{
+	  p = fp->apx_space ();
+	  for (i = 0; i < num_apx_registers; i++)
+	    supply_register (regcache, i + r16_regnum, p + i * 8);
+	}
+    }
+
   if ((clear_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX))
       == (X86_XSTATE_SSE | X86_XSTATE_AVX))
     {
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 28a3d78f747..3c9c2e7c452 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -260,7 +260,9 @@  static const int x86_64_regmap[] =
   -1, -1, -1, -1, -1, -1, -1, -1,
   -1, -1, -1, -1, -1, -1, -1, -1,
   -1,					/* pkru  */
-  -1					/* CET user mode register PL3_SSP.  */
+  -1,					/* CET user mode register PL3_SSP.  */
+  -1, -1, -1, -1, -1, -1, -1, -1,       /* r16...r31 (APX).  */
+  -1, -1, -1, -1, -1, -1, -1, -1,
 };
 
 #define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0]))
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
index ee8660f8cb4..3602fa40cd9 100644
--- a/gdbsupport/x86-xstate.h
+++ b/gdbsupport/x86-xstate.h
@@ -29,11 +29,13 @@ 
 #define X86_XSTATE_ZMM_ID	7
 #define X86_XSTATE_PKRU_ID	9
 #define X86_XSTATE_CET_U_ID	11
+#define X86_XSTATE_APX_F_ID	19
 
 /* The extended state feature bits.  */
 #define X86_XSTATE_X87		(1ULL << X86_XSTATE_X87_ID)
 #define X86_XSTATE_SSE		(1ULL << X86_XSTATE_SSE_ID)
 #define X86_XSTATE_AVX		(1ULL << X86_XSTATE_AVX_ID)
+#define X86_XSTATE_APX_F	(1ULL << X86_XSTATE_APX_F_ID)
 
 /* AVX 512 adds three feature bits.  All three must be enabled.  */
 #define X86_XSTATE_K		(1ULL << X86_XSTATE_K_ID)
@@ -53,6 +55,7 @@  struct x86_xsave_layout
 {
   int sizeof_xsave = 0;
   int avx_offset = 0;
+  int apx_offset = 0;
   int k_offset = 0;
   int zmm_h_offset = 0;
   int zmm_offset = 0;
@@ -64,6 +67,7 @@  constexpr bool operator== (const x86_xsave_layout &lhs,
 {
   return lhs.sizeof_xsave == rhs.sizeof_xsave
     && lhs.avx_offset == rhs.avx_offset
+    && lhs.apx_offset == rhs.apx_offset
     && lhs.k_offset == rhs.k_offset
     && lhs.zmm_h_offset == rhs.zmm_h_offset
     && lhs.zmm_offset == rhs.zmm_offset
@@ -81,14 +85,19 @@  constexpr bool operator!= (const x86_xsave_layout &lhs,
 #define X86_XSTATE_X87_MASK	X86_XSTATE_X87
 #define X86_XSTATE_SSE_MASK	(X86_XSTATE_X87 | X86_XSTATE_SSE)
 #define X86_XSTATE_AVX_MASK	(X86_XSTATE_SSE_MASK | X86_XSTATE_AVX)
+#define X86_XSTATE_AVX_APX_MASK	(X86_XSTATE_AVX_MASK | X86_XSTATE_APX_F)
 #define X86_XSTATE_AVX_AVX512_MASK	(X86_XSTATE_AVX_MASK | X86_XSTATE_AVX512)
+#define X86_XSTATE_AVX_AVX512_APX_MASK\
+  (X86_XSTATE_AVX_AVX512_MASK | X86_XSTATE_APX_F)
 #define X86_XSTATE_AVX_AVX512_PKU_MASK 	(X86_XSTATE_AVX_MASK\
 					| X86_XSTATE_AVX512 | X86_XSTATE_PKRU)
+#define X86_XSTATE_AVX_AVX512_PKU_APX_MASK\
+  (X86_XSTATE_AVX_AVX512_PKU_MASK | X86_XSTATE_APX_F)
 
 /* Supported mask of state-component bitmap xstate_bv.  The SDM defines
    xstate_bv as XCR0 | IA32_XSS.  */
 
-#define X86_XSTATE_ALL_MASK		(X86_XSTATE_AVX_AVX512_PKU_MASK\
+#define X86_XSTATE_ALL_MASK		(X86_XSTATE_AVX_AVX512_PKU_APX_MASK\
 					| X86_XSTATE_CET_U)
 
 #define X86_XSTATE_SSE_SIZE	576
@@ -97,6 +106,7 @@  constexpr bool operator!= (const x86_xsave_layout &lhs,
 
 #define HAS_AVX(XCR0) (((XCR0) & X86_XSTATE_AVX) != 0)
 #define HAS_AVX512(XCR0) (((XCR0) & X86_XSTATE_AVX512) != 0)
+#define HAS_APX(XCR0) (((XCR0) & X86_XSTATE_APX_F) != 0)
 #define HAS_PKRU(XCR0) (((XCR0) & X86_XSTATE_PKRU) != 0)
 
 /* Initial value for fctrl register, as defined in the X86 manual, and