diff --git a/gdb/features/i386/32bit-linux.c b/gdb/features/i386/32bit-linux.c
index 686a2f1..1b50882 100644
--- a/gdb/features/i386/32bit-linux.c
+++ b/gdb/features/i386/32bit-linux.c
@@ -9,6 +9,7 @@ create_feature_i386_32bit_linux (struct target_desc *result, long regnum)
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.linux");
+  regnum = 41;
   tdesc_create_reg (feature, "orig_eax", regnum++, 1, NULL, 32, "int");
   return regnum;
 }
diff --git a/gdb/features/i386/32bit-sse.c b/gdb/features/i386/32bit-sse.c
index 032623e..c0684fb 100644
--- a/gdb/features/i386/32bit-sse.c
+++ b/gdb/features/i386/32bit-sse.c
@@ -61,6 +61,7 @@ create_feature_i386_32bit_sse (struct target_desc *result, long regnum)
   tdesc_add_flag (type, 12, "PM");
   tdesc_add_flag (type, 15, "FZ");
 
+  regnum = 32;
   tdesc_create_reg (feature, "xmm0", regnum++, 1, NULL, 128, "vec128");
   tdesc_create_reg (feature, "xmm1", regnum++, 1, NULL, 128, "vec128");
   tdesc_create_reg (feature, "xmm2", regnum++, 1, NULL, 128, "vec128");
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index e986d6f..4c0f597 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -45,13 +45,14 @@
 
 #include "record-full.h"
 #include "linux-record.h"
-#include "features/i386/i386-linux.c"
-#include "features/i386/i386-mmx-linux.c"
-#include "features/i386/i386-mpx-linux.c"
-#include "features/i386/i386-avx-mpx-linux.c"
-#include "features/i386/i386-avx-linux.c"
-#include "features/i386/i386-avx-avx512-linux.c"
-#include "features/i386/i386-avx-mpx-avx512-pku-linux.c"
+
+#include "features/i386/32bit-core.c"
+#include "features/i386/32bit-sse.c"
+#include "features/i386/32bit-linux.c"
+#include "features/i386/32bit-avx.c"
+#include "features/i386/32bit-mpx.c"
+#include "features/i386/32bit-avx512.c"
+#include "features/i386/32bit-pkeys.c"
 
 /* Return non-zero, when the register is in the corresponding register
    group.  Put the LINUX_ORIG_EAX register in the system group.  */
@@ -683,27 +684,50 @@ i386_linux_core_read_xcr0 (bfd *abfd)
 const struct target_desc *
 i386_linux_read_description (uint64_t xcr0)
 {
-  switch ((xcr0 & X86_XSTATE_ALL_MASK))
+  if (xcr0 == 0)
+    return NULL;
+
+  static struct target_desc *i386_linux_tdescs \
+    [2/*X87*/][2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
+  struct target_desc **tdesc;
+
+  tdesc = &i386_linux_tdescs[(xcr0 & X86_XSTATE_X87) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_SSE) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_MPX) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];
+
+  if (*tdesc == NULL)
     {
-    case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK:
-      return tdesc_i386_avx_mpx_avx512_pku_linux;
-    case X86_XSTATE_AVX_AVX512_MASK:
-      return tdesc_i386_avx_avx512_linux;
-    case X86_XSTATE_MPX_MASK:
-      return tdesc_i386_mpx_linux;
-    case X86_XSTATE_AVX_MPX_MASK:
-      return tdesc_i386_avx_mpx_linux;
-    case X86_XSTATE_AVX_MASK:
-      return tdesc_i386_avx_linux;
-    case X86_XSTATE_SSE_MASK:
-      return tdesc_i386_linux;
-    case X86_XSTATE_X87_MASK:
-      return tdesc_i386_mmx_linux;
-    default:
-      break;
+      *tdesc = allocate_target_description ();
+      set_tdesc_architecture (*tdesc, bfd_scan_arch ("i386"));
+      set_tdesc_osabi (*tdesc, osabi_from_tdesc_string ("GNU/Linux"));
+
+      long regnum = 0;
+
+      if (xcr0 & X86_XSTATE_X87)
+	regnum = create_feature_i386_32bit_core (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_SSE)
+	regnum = create_feature_i386_32bit_sse (*tdesc, regnum);
+
+      regnum = create_feature_i386_32bit_linux (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_AVX)
+	regnum = create_feature_i386_32bit_avx (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_MPX)
+	regnum = create_feature_i386_32bit_mpx (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_AVX512)
+	regnum = create_feature_i386_32bit_avx512 (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_PKRU)
+	regnum = create_feature_i386_32bit_pkeys (*tdesc, regnum);
     }
 
-  return NULL;
+  return *tdesc;
 }
 
 /* Get Linux/x86 target description from core dump.  */
@@ -1092,13 +1116,4 @@ _initialize_i386_linux_tdep (void)
 {
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
 			  i386_linux_init_abi);
-
-  /* Initialize the Linux target description.  */
-  initialize_tdesc_i386_linux ();
-  initialize_tdesc_i386_mmx_linux ();
-  initialize_tdesc_i386_avx_linux ();
-  initialize_tdesc_i386_mpx_linux ();
-  initialize_tdesc_i386_avx_mpx_linux ();
-  initialize_tdesc_i386_avx_avx512_linux ();
-  initialize_tdesc_i386_avx_mpx_avx512_pku_linux ();
 }
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index 518f2dc..d1755f4 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -2101,6 +2101,48 @@ public:
 
   void visit (const tdesc_reg *reg) override
   {
+    /* Most "reg" in XML target descriptions don't have "regnum"
+       attribute, so the register number is allocated sequentially.
+       In case that reg has "regnum" attribute, register number
+       should be set by that explicitly.  */
+
+    if (reg->target_regnum < m_next_regnum)
+      {
+	/* The integrity check, it can catch some errors on register
+	   number collision, like this,
+
+	  <reg name="x0" bitsize="32"/>
+	  <reg name="x1" bitsize="32"/>
+	  <reg name="x2" bitsize="32"/>
+	  <reg name="x3" bitsize="32"/>
+	  <reg name="ps" bitsize="32" regnum="3"/>
+
+	  but it also has false negatives.  The target description
+	  below is correct,
+
+	  <reg name="x1" bitsize="32" regnum="1"/>
+	  <reg name="x3" bitsize="32" regnum="3"/>
+	  <reg name="x2" bitsize="32" regnum="2"/>
+	  <reg name="x4" bitsize="32" regnum="4"/>
+
+	  but it is not a good practice, so still error on this,
+	  and also print the message so that it can be saved in the
+	  generated c file.  */
+
+	printf_unfiltered ("ERROR: \"regnum\" attribute %ld ",
+			   reg->target_regnum);
+	printf_unfiltered ("is not the largest number (%d).\n",
+			   m_next_regnum);
+	error (_("\"regnum\" attribute %ld is not the largest number (%d)."),
+	       reg->target_regnum, m_next_regnum);
+      }
+
+    if (reg->target_regnum > m_next_regnum)
+      {
+	printf_unfiltered ("  regnum = %ld;\n", reg->target_regnum);
+	m_next_regnum = reg->target_regnum;
+      }
+
     printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
 		       reg->name, reg->save_restore);
     if (reg->group)
@@ -2108,8 +2150,13 @@ public:
     else
       printf_unfiltered ("NULL, ");
     printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+
+    m_next_regnum++;
   }
 
+private:
+  /* The register number to use for the next register we see.  */
+  int m_next_regnum = 0;
 };
 
 static void
