LoongArch: support disassembling certain pseudo-instructions
[binutils-gdb.git] / opcodes / i386-gen.c
index 8a42eb93efe8e00b2b82e209a4e36f31bfbb4584..1db555d86156770917652fe16556d541e7b2fce2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2020 Free Software Foundation, Inc.
+/* Copyright (C) 2007-2023 Free Software Foundation, Inc.
 
    This file is part of the GNU opcodes library.
 
@@ -18,6 +18,7 @@
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
+#include <stdbool.h>
 #include <stdio.h>
 #include <errno.h>
 #include "getopt.h"
@@ -27,9 +28,6 @@
 
 #include "i386-opc.h"
 
-#include <libintl.h>
-#define _(String) gettext (String)
-
 /* Build-time checks are preferrable over runtime ones.  Use this construct
    in preference where possible.  */
 #define static_assert(e) ((void)sizeof (struct { int _:1 - 2 * !(e); }))
 static const char *program_name = NULL;
 static int debug = 0;
 
-typedef struct initializer
+typedef struct dependency
 {
   const char *name;
-  const char *init;
-} initializer;
-
-static initializer cpu_flag_init[] =
-{
-  { "CPU_UNKNOWN_FLAGS",
-    "~(CpuL1OM|CpuK1OM)" },
-  { "CPU_GENERIC32_FLAGS",
-    "Cpu186|Cpu286|Cpu386" },
-  { "CPU_GENERIC64_FLAGS",
-    "CPU_PENTIUMPRO_FLAGS|CpuClflush|CpuSYSCALL|CPU_MMX_FLAGS|CPU_SSE2_FLAGS|CpuLM" },
-  { "CPU_NONE_FLAGS",
-   "0" },
-  { "CPU_I186_FLAGS",
-    "Cpu186" },
-  { "CPU_I286_FLAGS",
-    "CPU_I186_FLAGS|Cpu286" },
-  { "CPU_I386_FLAGS",
-    "CPU_I286_FLAGS|Cpu386" },
-  { "CPU_I486_FLAGS",
-    "CPU_I386_FLAGS|Cpu486" },
-  { "CPU_I586_FLAGS",
-    "CPU_I486_FLAGS|Cpu387|Cpu586" },
-  { "CPU_I686_FLAGS",
-    "CPU_I586_FLAGS|Cpu686|Cpu687|CpuCMOV|CpuFXSR" },
-  { "CPU_PENTIUMPRO_FLAGS",
-    "CPU_I686_FLAGS|CpuNop" },
-  { "CPU_P2_FLAGS",
-    "CPU_PENTIUMPRO_FLAGS|CPU_MMX_FLAGS" },
-  { "CPU_P3_FLAGS",
-    "CPU_P2_FLAGS|CPU_SSE_FLAGS" },
-  { "CPU_P4_FLAGS",
-    "CPU_P3_FLAGS|CpuClflush|CPU_SSE2_FLAGS" },
-  { "CPU_NOCONA_FLAGS",
-    "CPU_GENERIC64_FLAGS|CpuFISTTP|CPU_SSE3_FLAGS|CpuCX16" },
-  { "CPU_CORE_FLAGS",
-    "CPU_P4_FLAGS|CpuFISTTP|CPU_SSE3_FLAGS|CpuCX16" },
-  { "CPU_CORE2_FLAGS",
-    "CPU_NOCONA_FLAGS|CPU_SSSE3_FLAGS" },
-  { "CPU_COREI7_FLAGS",
-    "CPU_CORE2_FLAGS|CPU_SSE4_2_FLAGS|CpuRdtscp" },
-  { "CPU_K6_FLAGS",
-    "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuSYSCALL|Cpu387|CPU_MMX_FLAGS" },
-  { "CPU_K6_2_FLAGS",
-    "CPU_K6_FLAGS|Cpu3dnow" },
-  { "CPU_ATHLON_FLAGS",
-    "CPU_K6_2_FLAGS|Cpu686|Cpu687|CpuNop|Cpu3dnowA" },
-  { "CPU_K8_FLAGS",
-    "CPU_ATHLON_FLAGS|CpuRdtscp|CPU_SSE2_FLAGS|CpuLM" },
-  { "CPU_AMDFAM10_FLAGS",
-    "CPU_K8_FLAGS|CpuFISTTP|CPU_SSE4A_FLAGS|CpuLZCNT|CpuPOPCNT" },
-  { "CPU_BDVER1_FLAGS",
-    "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuRdtscp|CpuCX16|CPU_XOP_FLAGS|CpuLZCNT|CpuPOPCNT|CpuLWP|CpuSVME|CpuAES|CpuPCLMUL|CpuPRFCHW" },
-  { "CPU_BDVER2_FLAGS",
-    "CPU_BDVER1_FLAGS|CpuFMA|CpuBMI|CpuTBM|CpuF16C" },
-  { "CPU_BDVER3_FLAGS",
-    "CPU_BDVER2_FLAGS|CpuXsaveopt|CpuFSGSBase" },
-  { "CPU_BDVER4_FLAGS",
-    "CPU_BDVER3_FLAGS|CpuAVX2|CpuMovbe|CpuBMI2|CpuRdRnd|CpuMWAITX" },
-  { "CPU_ZNVER1_FLAGS",
-    "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuRdtscp|CpuCX16|CPU_AVX2_FLAGS|CpuSSE4A|CpuLZCNT|CpuPOPCNT|CpuSVME|CpuAES|CpuPCLMUL|CpuPRFCHW|CpuFMA|CpuBMI|CpuF16C|CpuXsaveopt|CpuFSGSBase|CpuMovbe|CpuBMI2|CpuRdRnd|CpuADX|CpuRdSeed|CpuSMAP|CpuSHA|CpuXSAVEC|CpuXSAVES|CpuClflushOpt|CpuCLZERO|CpuMWAITX" },
-  { "CPU_ZNVER2_FLAGS",
-    "CPU_ZNVER1_FLAGS|CpuCLWB|CpuRDPID|CpuRDPRU|CpuMCOMMIT|CpuWBNOINVD" },
-  { "CPU_BTVER1_FLAGS",
-    "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuCX16|CpuRdtscp|CPU_SSSE3_FLAGS|CpuSSE4A|CpuLZCNT|CpuPOPCNT|CpuPRFCHW|CpuCX16|CpuClflush|CpuFISTTP|CpuSVME" },
-  { "CPU_BTVER2_FLAGS",
-    "CPU_BTVER1_FLAGS|CPU_AVX_FLAGS|CpuBMI|CpuF16C|CpuAES|CpuPCLMUL|CpuMovbe|CpuXsaveopt|CpuPRFCHW" },
-  { "CPU_8087_FLAGS",
-    "Cpu8087" },
-  { "CPU_287_FLAGS",
-    "Cpu287" },
-  { "CPU_387_FLAGS",
-    "Cpu387" },
-  { "CPU_687_FLAGS",
-    "CPU_387_FLAGS|Cpu687" },
-  { "CPU_CMOV_FLAGS",
-    "CpuCMOV" },
-  { "CPU_FXSR_FLAGS",
-    "CpuFXSR" },
-  { "CPU_CLFLUSH_FLAGS",
-    "CpuClflush" },
-  { "CPU_NOP_FLAGS",
-    "CpuNop" },
-  { "CPU_SYSCALL_FLAGS",
-    "CpuSYSCALL" },
-  { "CPU_MMX_FLAGS",
-    "CpuMMX" },
-  { "CPU_SSE_FLAGS",
-    "CpuSSE" },
-  { "CPU_SSE2_FLAGS",
-    "CPU_SSE_FLAGS|CpuSSE2" },
-  { "CPU_SSE3_FLAGS",
-    "CPU_SSE2_FLAGS|CpuSSE3" },
-  { "CPU_SSSE3_FLAGS",
-    "CPU_SSE3_FLAGS|CpuSSSE3" },
-  { "CPU_SSE4_1_FLAGS",
-    "CPU_SSSE3_FLAGS|CpuSSE4_1" },
-  { "CPU_SSE4_2_FLAGS",
-    "CPU_SSE4_1_FLAGS|CpuSSE4_2|CpuPOPCNT" },
-  { "CPU_VMX_FLAGS",
-    "CpuVMX" },
-  { "CPU_SMX_FLAGS",
-    "CpuSMX" },
-  { "CPU_XSAVE_FLAGS",
-    "CpuXsave" },
-  { "CPU_XSAVEOPT_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuXsaveopt" },
-  { "CPU_AES_FLAGS",
-    "CPU_SSE2_FLAGS|CpuAES" },
-  { "CPU_PCLMUL_FLAGS",
-    "CPU_SSE2_FLAGS|CpuPCLMUL" },
-  { "CPU_FMA_FLAGS",
-    "CPU_AVX_FLAGS|CpuFMA" },
-  { "CPU_FMA4_FLAGS",
-    "CPU_AVX_FLAGS|CpuFMA4" },
-  { "CPU_XOP_FLAGS",
-    "CPU_SSE4A_FLAGS|CPU_FMA4_FLAGS|CpuXOP" },
-  { "CPU_LWP_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuLWP" },
-  { "CPU_BMI_FLAGS",
-    "CpuBMI" },
-  { "CPU_TBM_FLAGS",
-    "CpuTBM" },
-  { "CPU_MOVBE_FLAGS",
-    "CpuMovbe" },
-  { "CPU_CX16_FLAGS",
-    "CpuCX16" },
-  { "CPU_RDTSCP_FLAGS",
-    "CpuRdtscp" },
-  { "CPU_EPT_FLAGS",
-    "CpuEPT" },
-  { "CPU_FSGSBASE_FLAGS",
-    "CpuFSGSBase" },
-  { "CPU_RDRND_FLAGS",
-    "CpuRdRnd" },
-  { "CPU_F16C_FLAGS",
-    "CPU_AVX_FLAGS|CpuF16C" },
-  { "CPU_BMI2_FLAGS",
-    "CpuBMI2" },
-  { "CPU_LZCNT_FLAGS",
-    "CpuLZCNT" },
-  { "CPU_POPCNT_FLAGS",
-    "CpuPOPCNT" },
-  { "CPU_HLE_FLAGS",
-    "CpuHLE" },
-  { "CPU_RTM_FLAGS",
-    "CpuRTM" },
-  { "CPU_INVPCID_FLAGS",
-    "CpuINVPCID" },
-  { "CPU_VMFUNC_FLAGS",
-    "CpuVMFUNC" },
-  { "CPU_3DNOW_FLAGS",
-    "CPU_MMX_FLAGS|Cpu3dnow" },
-  { "CPU_3DNOWA_FLAGS",
-    "CPU_3DNOW_FLAGS|Cpu3dnowA" },
-  { "CPU_PADLOCK_FLAGS",
-    "CpuPadLock" },
-  { "CPU_SVME_FLAGS",
-    "CpuSVME" },
-  { "CPU_SSE4A_FLAGS",
-    "CPU_SSE3_FLAGS|CpuSSE4a" },
-  { "CPU_ABM_FLAGS",
-    "CpuLZCNT|CpuPOPCNT" },
-  { "CPU_AVX_FLAGS",
-    "CPU_SSE4_2_FLAGS|CPU_XSAVE_FLAGS|CpuAVX" },
-  { "CPU_AVX2_FLAGS",
-    "CPU_AVX_FLAGS|CpuAVX2" },
-  { "CPU_AVX512F_FLAGS",
-    "CPU_AVX2_FLAGS|CpuAVX512F" },
-  { "CPU_AVX512CD_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512CD" },
-  { "CPU_AVX512ER_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512ER" },
-  { "CPU_AVX512PF_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512PF" },
-  { "CPU_AVX512DQ_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512DQ" },
-  { "CPU_AVX512BW_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512BW" },
-  { "CPU_AVX512VL_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512VL" },
-  { "CPU_AVX512IFMA_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512IFMA" },
-  { "CPU_AVX512VBMI_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512VBMI" },
-  { "CPU_AVX512_4FMAPS_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_4FMAPS" },
-  { "CPU_AVX512_4VNNIW_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_4VNNIW" },
-  { "CPU_AVX512_VPOPCNTDQ_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_VPOPCNTDQ" },
-  { "CPU_AVX512_VBMI2_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_VBMI2" },
-  { "CPU_AVX512_VNNI_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_VNNI" },
-  { "CPU_AVX512_BITALG_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_BITALG" },
-  { "CPU_AVX512_BF16_FLAGS",
-    "CPU_AVX512F_FLAGS|CpuAVX512_BF16" },
-  { "CPU_L1OM_FLAGS",
-    "unknown" },
-  { "CPU_K1OM_FLAGS",
-    "unknown" },
-  { "CPU_IAMCU_FLAGS",
-    "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586" },
-  { "CPU_ADX_FLAGS",
-    "CpuADX" },
-  { "CPU_RDSEED_FLAGS",
-    "CpuRdSeed" },
-  { "CPU_PRFCHW_FLAGS",
-    "CpuPRFCHW" },
-  { "CPU_SMAP_FLAGS",
-    "CpuSMAP" },
-  { "CPU_MPX_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuMPX" },
-  { "CPU_SHA_FLAGS",
-    "CPU_SSE2_FLAGS|CpuSHA" },
-  { "CPU_CLFLUSHOPT_FLAGS",
-    "CpuClflushOpt" },
-  { "CPU_XSAVES_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuXSAVES" },
-  { "CPU_XSAVEC_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuXSAVEC" },
-  { "CPU_PREFETCHWT1_FLAGS",
-    "CpuPREFETCHWT1" },
-  { "CPU_SE1_FLAGS",
-    "CpuSE1" },
-  { "CPU_CLWB_FLAGS",
-    "CpuCLWB" },
-  { "CPU_CLZERO_FLAGS",
-    "CpuCLZERO" },
-  { "CPU_MWAITX_FLAGS",
-    "CpuMWAITX" },
-  { "CPU_OSPKE_FLAGS",
-    "CPU_XSAVE_FLAGS|CpuOSPKE" },
-  { "CPU_RDPID_FLAGS",
-    "CpuRDPID" },
-  { "CPU_PTWRITE_FLAGS",
-    "CpuPTWRITE" },
-  { "CPU_IBT_FLAGS",
-    "CpuIBT" },
-  { "CPU_SHSTK_FLAGS",
-    "CpuSHSTK" },
-  { "CPU_GFNI_FLAGS",
-    "CpuGFNI" },
-  { "CPU_VAES_FLAGS",
-    "CpuVAES" },
-  { "CPU_VPCLMULQDQ_FLAGS",
-    "CpuVPCLMULQDQ" },
-  { "CPU_WBNOINVD_FLAGS",
-    "CpuWBNOINVD" },
-  { "CPU_PCONFIG_FLAGS",
-    "CpuPCONFIG" },
-  { "CPU_WAITPKG_FLAGS",
-    "CpuWAITPKG" },
-  { "CPU_CLDEMOTE_FLAGS",
-    "CpuCLDEMOTE" },
-  { "CPU_AMX_INT8_FLAGS",
-    "CpuAMX_INT8" },
-  { "CPU_AMX_BF16_FLAGS",
-    "CpuAMX_BF16" },
-  { "CPU_AMX_TILE_FLAGS",
-    "CpuAMX_TILE" },
-  { "CPU_MOVDIRI_FLAGS",
-    "CpuMOVDIRI" },
-  { "CPU_MOVDIR64B_FLAGS",
-    "CpuMOVDIR64B" },
-  { "CPU_ENQCMD_FLAGS",
-    "CpuENQCMD" },
-  { "CPU_SERIALIZE_FLAGS",
-    "CpuSERIALIZE" },
-  { "CPU_AVX512_VP2INTERSECT_FLAGS",
-    "CpuAVX512_VP2INTERSECT" },
-  { "CPU_TDX_FLAGS",
-    "CpuTDX" },
-  { "CPU_RDPRU_FLAGS",
-    "CpuRDPRU" },
-  { "CPU_MCOMMIT_FLAGS",
-    "CpuMCOMMIT" },
-  { "CPU_SEV_ES_FLAGS",
-    "CpuSEV_ES" },
-  { "CPU_TSXLDTRK_FLAGS",
-    "CpuTSXLDTRK"},
-  { "CPU_KL_FLAGS",
-    "CpuKL" },
-  { "CPU_WIDEKL_FLAGS",
-    "CpuWideKL" },
-  { "CPU_ANY_X87_FLAGS",
-    "CPU_ANY_287_FLAGS|Cpu8087" },
-  { "CPU_ANY_287_FLAGS",
-    "CPU_ANY_387_FLAGS|Cpu287" },
-  { "CPU_ANY_387_FLAGS",
-    "CPU_ANY_687_FLAGS|Cpu387" },
-  { "CPU_ANY_687_FLAGS",
-    "Cpu687|CpuFISTTP" },
-  { "CPU_ANY_CMOV_FLAGS",
-    "CpuCMOV" },
-  { "CPU_ANY_FXSR_FLAGS",
-    "CpuFXSR" },
-  { "CPU_ANY_MMX_FLAGS",
-    "CPU_3DNOWA_FLAGS" },
-  { "CPU_ANY_SSE_FLAGS",
-    "CPU_ANY_SSE2_FLAGS|CpuSSE" },
-  { "CPU_ANY_SSE2_FLAGS",
-    "CPU_ANY_SSE3_FLAGS|CpuSSE2" },
-  { "CPU_ANY_SSE3_FLAGS",
-    "CPU_ANY_SSSE3_FLAGS|CpuSSE3|CpuSSE4a" },
-  { "CPU_ANY_SSSE3_FLAGS",
-    "CPU_ANY_SSE4_1_FLAGS|CpuSSSE3" },
-  { "CPU_ANY_SSE4_1_FLAGS",
-    "CPU_ANY_SSE4_2_FLAGS|CpuSSE4_1" },
-  { "CPU_ANY_SSE4_2_FLAGS",
-    "CpuSSE4_2" },
-  { "CPU_ANY_SSE4A_FLAGS",
-    "CpuSSE4a" },
-  { "CPU_ANY_AVX_FLAGS",
-    "CPU_ANY_AVX2_FLAGS|CpuF16C|CpuFMA|CpuFMA4|CpuXOP|CpuAVX" },
-  { "CPU_ANY_AVX2_FLAGS",
-    "CPU_ANY_AVX512F_FLAGS|CpuAVX2" },
-  { "CPU_ANY_AVX512F_FLAGS",
-    "CpuAVX512F|CpuAVX512CD|CpuAVX512ER|CpuAVX512PF|CpuAVX512DQ|CpuAVX512BW|CpuAVX512VL|CpuAVX512IFMA|CpuAVX512VBMI|CpuAVX512_4FMAPS|CpuAVX512_4VNNIW|CpuAVX512_VPOPCNTDQ|CpuAVX512_VBMI2|CpuAVX512_VNNI|CpuAVX512_BITALG|CpuAVX512_BF16|CpuAVX512_VP2INTERSECT" },
-  { "CPU_ANY_AVX512CD_FLAGS",
-    "CpuAVX512CD" },
-  { "CPU_ANY_AVX512ER_FLAGS",
-    "CpuAVX512ER" },
-  { "CPU_ANY_AVX512PF_FLAGS",
-    "CpuAVX512PF" },
-  { "CPU_ANY_AVX512DQ_FLAGS",
-    "CpuAVX512DQ" },
-  { "CPU_ANY_AVX512BW_FLAGS",
-    "CpuAVX512BW" },
-  { "CPU_ANY_AVX512VL_FLAGS",
-    "CpuAVX512VL" },
-  { "CPU_ANY_AVX512IFMA_FLAGS",
-    "CpuAVX512IFMA" },
-  { "CPU_ANY_AVX512VBMI_FLAGS",
-    "CpuAVX512VBMI" },
-  { "CPU_ANY_AVX512_4FMAPS_FLAGS",
-    "CpuAVX512_4FMAPS" },
-  { "CPU_ANY_AVX512_4VNNIW_FLAGS",
-    "CpuAVX512_4VNNIW" },
-  { "CPU_ANY_AVX512_VPOPCNTDQ_FLAGS",
-    "CpuAVX512_VPOPCNTDQ" },
-  { "CPU_ANY_IBT_FLAGS",
-    "CpuIBT" },
-  { "CPU_ANY_SHSTK_FLAGS",
-    "CpuSHSTK" },
-  { "CPU_ANY_AVX512_VBMI2_FLAGS",
-    "CpuAVX512_VBMI2" },
-  { "CPU_ANY_AVX512_VNNI_FLAGS",
-    "CpuAVX512_VNNI" },
-  { "CPU_ANY_AVX512_BITALG_FLAGS",
-    "CpuAVX512_BITALG" },
-  { "CPU_ANY_AVX512_BF16_FLAGS",
-    "CpuAVX512_BF16" },
-  { "CPU_ANY_AMX_INT8_FLAGS",
-    "CpuAMX_INT8" },
-  { "CPU_ANY_AMX_BF16_FLAGS",
-    "CpuAMX_BF16" },
-  { "CPU_ANY_AMX_TILE_FLAGS",
-    "CpuAMX_TILE|CpuAMX_INT8|CpuAMX_BF16" },
-  { "CPU_ANY_MOVDIRI_FLAGS",
-    "CpuMOVDIRI" },
-  { "CPU_ANY_MOVDIR64B_FLAGS",
-    "CpuMOVDIR64B" },
-  { "CPU_ANY_ENQCMD_FLAGS",
-    "CpuENQCMD" },
-  { "CPU_ANY_SERIALIZE_FLAGS",
-    "CpuSERIALIZE" },
-  { "CPU_ANY_AVX512_VP2INTERSECT_FLAGS",
-    "CpuAVX512_VP2INTERSECT" },
-  { "CPU_ANY_TDX_FLAGS",
-    "CpuTDX" },
-  { "CPU_ANY_TSXLDTRK_FLAGS",
-    "CpuTSXLDTRK" },
-  { "CPU_ANY_KL_FLAGS",
-    "CpuKL|CpuWideKL" },
-  { "CPU_ANY_WIDEKL_FLAGS",
-    "CpuWideKL" },
-};
+  /* Note: Only direct dependencies should be enumerated.  */
+  const char *deps;
+} dependency;
 
-static initializer operand_type_init[] =
+static const dependency isa_dependencies[] =
 {
-  { "OPERAND_TYPE_NONE",
+  { "UNKNOWN",
+    "~IAMCU" },
+  { "GENERIC32",
+    "386" },
+  { "GENERIC64",
+    "PENTIUMPRO|Clflush|SYSCALL|MMX|SSE2|LM" },
+  { "NONE",
     "0" },
-  { "OPERAND_TYPE_REG8",
-    "Class=Reg|Byte" },
-  { "OPERAND_TYPE_REG16",
-    "Class=Reg|Word" },
-  { "OPERAND_TYPE_REG32",
-    "Class=Reg|Dword" },
-  { "OPERAND_TYPE_REG64",
-    "Class=Reg|Qword" },
-  { "OPERAND_TYPE_IMM1",
-    "Imm1" },
-  { "OPERAND_TYPE_IMM8",
-    "Imm8" },
-  { "OPERAND_TYPE_IMM8S",
-    "Imm8S" },
-  { "OPERAND_TYPE_IMM16",
-    "Imm16" },
-  { "OPERAND_TYPE_IMM32",
-    "Imm32" },
-  { "OPERAND_TYPE_IMM32S",
-    "Imm32S" },
-  { "OPERAND_TYPE_IMM64",
-    "Imm64" },
-  { "OPERAND_TYPE_BASEINDEX",
-    "BaseIndex" },
-  { "OPERAND_TYPE_DISP8",
-    "Disp8" },
-  { "OPERAND_TYPE_DISP16",
-    "Disp16" },
-  { "OPERAND_TYPE_DISP32",
-    "Disp32" },
-  { "OPERAND_TYPE_DISP32S",
-    "Disp32S" },
-  { "OPERAND_TYPE_DISP64",
-    "Disp64" },
-  { "OPERAND_TYPE_INOUTPORTREG",
-    "Instance=RegD|Word" },
-  { "OPERAND_TYPE_SHIFTCOUNT",
-    "Instance=RegC|Byte" },
-  { "OPERAND_TYPE_CONTROL",
-    "Class=RegCR" },
-  { "OPERAND_TYPE_TEST",
-    "Class=RegTR" },
-  { "OPERAND_TYPE_DEBUG",
-    "Class=RegDR" },
-  { "OPERAND_TYPE_FLOATREG",
-    "Class=Reg|Tbyte" },
-  { "OPERAND_TYPE_FLOATACC",
-    "Instance=Accum|Tbyte" },
-  { "OPERAND_TYPE_SREG",
-    "Class=SReg" },
-  { "OPERAND_TYPE_REGMMX",
-    "Class=RegMMX" },
-  { "OPERAND_TYPE_REGXMM",
-    "Class=RegSIMD|Xmmword" },
-  { "OPERAND_TYPE_REGYMM",
-    "Class=RegSIMD|Ymmword" },
-  { "OPERAND_TYPE_REGZMM",
-    "Class=RegSIMD|Zmmword" },
-  { "OPERAND_TYPE_REGTMM",
-    "Class=RegSIMD|Tmmword" },
-  { "OPERAND_TYPE_REGMASK",
-    "Class=RegMask" },
-  { "OPERAND_TYPE_REGBND",
-    "Class=RegBND" },
-  { "OPERAND_TYPE_ACC8",
-    "Instance=Accum|Byte" },
-  { "OPERAND_TYPE_ACC16",
-    "Instance=Accum|Word" },
-  { "OPERAND_TYPE_ACC32",
-    "Instance=Accum|Dword" },
-  { "OPERAND_TYPE_ACC64",
-    "Instance=Accum|Qword" },
-  { "OPERAND_TYPE_DISP16_32",
-    "Disp16|Disp32" },
-  { "OPERAND_TYPE_ANYDISP",
-    "Disp8|Disp16|Disp32|Disp32S|Disp64" },
-  { "OPERAND_TYPE_IMM16_32",
-    "Imm16|Imm32" },
-  { "OPERAND_TYPE_IMM16_32S",
-    "Imm16|Imm32S" },
-  { "OPERAND_TYPE_IMM16_32_32S",
-    "Imm16|Imm32|Imm32S" },
-  { "OPERAND_TYPE_IMM32_64",
-    "Imm32|Imm64" },
-  { "OPERAND_TYPE_IMM32_32S_DISP32",
-    "Imm32|Imm32S|Disp32" },
-  { "OPERAND_TYPE_IMM64_DISP64",
-    "Imm64|Disp64" },
-  { "OPERAND_TYPE_IMM32_32S_64_DISP32",
-    "Imm32|Imm32S|Imm64|Disp32" },
-  { "OPERAND_TYPE_IMM32_32S_64_DISP32_64",
-    "Imm32|Imm32S|Imm64|Disp32|Disp64" },
-  { "OPERAND_TYPE_ANYIMM",
-    "Imm1|Imm8|Imm8S|Imm16|Imm32|Imm32S|Imm64" },
+  { "PENTIUMPRO",
+    "686|Nop" },
+  { "P2",
+    "PENTIUMPRO|MMX" },
+  { "P3",
+    "P2|SSE" },
+  { "P4",
+    "P3|Clflush|SSE2" },
+  { "NOCONA",
+    "GENERIC64|FISTTP|SSE3|MONITOR|CX16" },
+  { "CORE",
+    "P4|FISTTP|SSE3|MONITOR|CX16" },
+  { "CORE2",
+    "NOCONA|SSSE3" },
+  { "COREI7",
+    "CORE2|SSE4_2|Rdtscp|LAHF_SAHF" },
+  { "K6",
+    "186|286|386|486|586|SYSCALL|387|MMX" },
+  { "K6_2",
+    "K6|3dnow" },
+  { "ATHLON",
+    "K6_2|686:min|687|Nop|3dnowA" },
+  { "K8",
+    "ATHLON|Rdtscp|SSE2|LM" },
+  { "AMDFAM10",
+    "K8|FISTTP|SSE4A|ABM|MONITOR" },
+  { "BDVER1",
+    "GENERIC64|FISTTP|Rdtscp|MONITOR|CX16|LAHF_SAHF|XOP|ABM|LWP|SVME|AES|PCLMUL|PRFCHW" },
+  { "BDVER2",
+    "BDVER1|FMA|BMI|TBM|F16C" },
+  { "BDVER3",
+    "BDVER2|Xsaveopt|FSGSBase" },
+  { "BDVER4",
+    "BDVER3|AVX2|Movbe|BMI2|RdRnd|MWAITX" },
+  { "ZNVER1",
+    "GENERIC64|FISTTP|Rdtscp|MONITOR|CX16|LAHF_SAHF|AVX2|SSE4A|ABM|SVME|AES|PCLMUL|PRFCHW|FMA|BMI|F16C|Xsaveopt|FSGSBase|Movbe|BMI2|RdRnd|ADX|RdSeed|SMAP|SHA|XSAVEC|XSAVES|ClflushOpt|CLZERO|MWAITX" },
+  { "ZNVER2",
+    "ZNVER1|CLWB|RDPID|RDPRU|MCOMMIT|WBNOINVD" },
+  { "ZNVER3",
+    "ZNVER2|INVLPGB|TLBSYNC|VAES|VPCLMULQDQ|INVPCID|SNP|OSPKE" },
+  { "ZNVER4",
+    "ZNVER3|AVX512F|AVX512DQ|AVX512IFMA|AVX512CD|AVX512BW|AVX512VL|AVX512_BF16|AVX512VBMI|AVX512_VBMI2|AVX512_VNNI|AVX512_BITALG|AVX512_VPOPCNTDQ|GFNI|RMPQUERY" },
+  { "BTVER1",
+    "GENERIC64|FISTTP|MONITOR|CX16|LAHF_SAHF|Rdtscp|SSSE3|SSE4A|ABM|PRFCHW|Clflush|FISTTP|SVME" },
+  { "BTVER2",
+    "BTVER1|AVX|BMI|F16C|AES|PCLMUL|Movbe|Xsaveopt|PRFCHW" },
+  { "286",
+    "186" },
+  { "386",
+    "286" },
+  { "486",
+    "386" },
+  { "586",
+    "486|387" },
+  { "586:nofpu",
+    "486" },
+  { "686",
+    "586|687|CMOV|FXSR" },
+  { "686:min",
+    "586|687" },
+  { "687",
+    "387" },
+  { "FISTTP",
+    "687" },
+  { "SSE",
+    "FXSR" },
+  { "SSE2",
+    "SSE" },
+  { "SSE3",
+    "SSE2" },
+  { "SSSE3",
+    "SSE3" },
+  { "SSE4_1",
+    "SSSE3" },
+  { "SSE4_2",
+    "SSE4_1|POPCNT" },
+  { "Xsaveopt",
+    "XSAVE" },
+  { "AES",
+    "SSE2" },
+  { "PCLMUL",
+    "SSE2" },
+  { "FMA",
+    "AVX" },
+  { "FMA4",
+    "AVX" },
+  { "XOP",
+    "SSE4A|FMA4" },
+  { "LWP",
+    "XSAVE" },
+  { "F16C",
+    "AVX" },
+  { "3dnow",
+    "MMX" },
+  { "3dnowA",
+    "3dnow" },
+  { "SSE4a",
+    "SSE3" },
+  { "ABM",
+    "LZCNT|POPCNT" },
+  { "AVX",
+    "SSE4_2|XSAVE" },
+  { "AVX2",
+    "AVX" },
+  { "AVX_VNNI",
+    "AVX2" },
+  { "AVX_IFMA",
+    "AVX2" },
+  { "AVX_VNNI_INT8",
+    "AVX2" },
+  { "AVX_NE_CONVERT",
+    "AVX2" },
+  { "FRED",
+    "LKGS" },
+  { "AVX512F",
+    "AVX2" },
+  { "AVX512CD",
+    "AVX512F" },
+  { "AVX512ER",
+    "AVX512F" },
+  { "AVX512PF",
+    "AVX512F" },
+  { "AVX512DQ",
+    "AVX512F" },
+  { "AVX512BW",
+    "AVX512F" },
+  { "AVX512VL",
+    "AVX512F" },
+  { "AVX512IFMA",
+    "AVX512F" },
+  { "AVX512VBMI",
+    "AVX512BW" },
+  { "AVX512_4FMAPS",
+    "AVX512F" },
+  { "AVX512_4VNNIW",
+    "AVX512F" },
+  { "AVX512_VPOPCNTDQ",
+    "AVX512F" },
+  { "AVX512_VBMI2",
+    "AVX512BW" },
+  { "AVX512_VNNI",
+    "AVX512F" },
+  { "AVX512_BITALG",
+    "AVX512BW" },
+  { "AVX512_VP2INTERSECT",
+    "AVX512F" },
+  { "AVX512_BF16",
+    "AVX512BW" },
+  { "AVX512_FP16",
+    "AVX512BW" },
+  { "IAMCU",
+    "586:nofpu" },
+  { "EPT",
+    "VMX" },
+  { "VMFUNC",
+    "VMX" },
+  { "MPX",
+    "XSAVE" },
+  { "SHA",
+    "SSE2" },
+  { "XSAVES",
+    "XSAVEC" },
+  { "XSAVEC",
+    "XSAVE" },
+  { "OSPKE",
+    "XSAVE" },
+  { "GFNI",
+    "SSE2" },
+  { "VAES",
+    "AVX2" },
+  { "VPCLMULQDQ",
+    "AVX2" },
+  { "SEV_ES",
+    "SVME" },
+  { "SNP",
+    "SEV_ES" },
+  { "RMPQUERY",
+    "SNP" },
+  { "TSX",
+    "RTM|HLE" },
+  { "TSXLDTRK",
+    "RTM" },
+  { "AMX_TILE",
+    "XSAVE" },
+  { "AMX_INT8",
+    "AMX_TILE" },
+  { "AMX_BF16",
+    "AMX_TILE" },
+  { "AMX_FP16",
+    "AMX_TILE" },
+  { "AMX_COMPLEX",
+    "AMX_TILE" },
+  { "KL",
+    "SSE2" },
+  { "WIDEKL",
+    "KL" },
 };
 
+/* This array is populated as process_i386_initializers() walks cpu_flags[].  */
+static unsigned char isa_reverse_deps[Cpu64][Cpu64];
+
 typedef struct bitfield
 {
   int position;
@@ -528,134 +260,157 @@ typedef struct bitfield
   const char *name;
 } bitfield;
 
-#define BITFIELD(n) { n, 0, #n }
+#define BITFIELD(n) { Cpu##n, 0, #n }
 
 static bitfield cpu_flags[] =
 {
-  BITFIELD (Cpu186),
-  BITFIELD (Cpu286),
-  BITFIELD (Cpu386),
-  BITFIELD (Cpu486),
-  BITFIELD (Cpu586),
-  BITFIELD (Cpu686),
-  BITFIELD (CpuCMOV),
-  BITFIELD (CpuFXSR),
-  BITFIELD (CpuClflush),
-  BITFIELD (CpuNop),
-  BITFIELD (CpuSYSCALL),
-  BITFIELD (Cpu8087),
-  BITFIELD (Cpu287),
-  BITFIELD (Cpu387),
-  BITFIELD (Cpu687),
-  BITFIELD (CpuFISTTP),
-  BITFIELD (CpuMMX),
-  BITFIELD (CpuSSE),
-  BITFIELD (CpuSSE2),
-  BITFIELD (CpuSSE3),
-  BITFIELD (CpuSSSE3),
-  BITFIELD (CpuSSE4_1),
-  BITFIELD (CpuSSE4_2),
-  BITFIELD (CpuAVX),
-  BITFIELD (CpuAVX2),
-  BITFIELD (CpuAVX512F),
-  BITFIELD (CpuAVX512CD),
-  BITFIELD (CpuAVX512ER),
-  BITFIELD (CpuAVX512PF),
-  BITFIELD (CpuAVX512VL),
-  BITFIELD (CpuAVX512DQ),
-  BITFIELD (CpuAVX512BW),
-  BITFIELD (CpuL1OM),
-  BITFIELD (CpuK1OM),
-  BITFIELD (CpuIAMCU),
-  BITFIELD (CpuSSE4a),
-  BITFIELD (Cpu3dnow),
-  BITFIELD (Cpu3dnowA),
-  BITFIELD (CpuPadLock),
-  BITFIELD (CpuSVME),
-  BITFIELD (CpuVMX),
-  BITFIELD (CpuSMX),
-  BITFIELD (CpuXsave),
-  BITFIELD (CpuXsaveopt),
-  BITFIELD (CpuAES),
-  BITFIELD (CpuPCLMUL),
-  BITFIELD (CpuFMA),
-  BITFIELD (CpuFMA4),
-  BITFIELD (CpuXOP),
-  BITFIELD (CpuLWP),
-  BITFIELD (CpuBMI),
-  BITFIELD (CpuTBM),
-  BITFIELD (CpuLM),
-  BITFIELD (CpuMovbe),
-  BITFIELD (CpuCX16),
-  BITFIELD (CpuEPT),
-  BITFIELD (CpuRdtscp),
-  BITFIELD (CpuFSGSBase),
-  BITFIELD (CpuRdRnd),
-  BITFIELD (CpuF16C),
-  BITFIELD (CpuBMI2),
-  BITFIELD (CpuLZCNT),
-  BITFIELD (CpuPOPCNT),
-  BITFIELD (CpuHLE),
-  BITFIELD (CpuRTM),
-  BITFIELD (CpuINVPCID),
-  BITFIELD (CpuVMFUNC),
-  BITFIELD (CpuRDSEED),
-  BITFIELD (CpuADX),
-  BITFIELD (CpuPRFCHW),
-  BITFIELD (CpuSMAP),
-  BITFIELD (CpuSHA),
-  BITFIELD (CpuClflushOpt),
-  BITFIELD (CpuXSAVES),
-  BITFIELD (CpuXSAVEC),
-  BITFIELD (CpuPREFETCHWT1),
-  BITFIELD (CpuSE1),
-  BITFIELD (CpuCLWB),
-  BITFIELD (Cpu64),
-  BITFIELD (CpuNo64),
-  BITFIELD (CpuMPX),
-  BITFIELD (CpuAVX512IFMA),
-  BITFIELD (CpuAVX512VBMI),
-  BITFIELD (CpuAVX512_4FMAPS),
-  BITFIELD (CpuAVX512_4VNNIW),
-  BITFIELD (CpuAVX512_VPOPCNTDQ),
-  BITFIELD (CpuAVX512_VBMI2),
-  BITFIELD (CpuAVX512_VNNI),
-  BITFIELD (CpuAVX512_BITALG),
-  BITFIELD (CpuAVX512_BF16),
-  BITFIELD (CpuAVX512_VP2INTERSECT),
-  BITFIELD (CpuTDX),
-  BITFIELD (CpuMWAITX),
-  BITFIELD (CpuCLZERO),
-  BITFIELD (CpuOSPKE),
-  BITFIELD (CpuRDPID),
-  BITFIELD (CpuPTWRITE),
-  BITFIELD (CpuIBT),
-  BITFIELD (CpuSHSTK),
-  BITFIELD (CpuGFNI),
-  BITFIELD (CpuVAES),
-  BITFIELD (CpuVPCLMULQDQ),
-  BITFIELD (CpuWBNOINVD),
-  BITFIELD (CpuPCONFIG),
-  BITFIELD (CpuWAITPKG),
-  BITFIELD (CpuCLDEMOTE),
-  BITFIELD (CpuAMX_INT8),
-  BITFIELD (CpuAMX_BF16),
-  BITFIELD (CpuAMX_TILE),
-  BITFIELD (CpuMOVDIRI),
-  BITFIELD (CpuMOVDIR64B),
-  BITFIELD (CpuENQCMD),
-  BITFIELD (CpuSERIALIZE),
-  BITFIELD (CpuRDPRU),
-  BITFIELD (CpuMCOMMIT),
-  BITFIELD (CpuSEV_ES),
-  BITFIELD (CpuTSXLDTRK),
-  BITFIELD (CpuKL),
-  BITFIELD (CpuWideKL),
+  BITFIELD (186),
+  BITFIELD (286),
+  BITFIELD (386),
+  BITFIELD (486),
+  BITFIELD (586),
+  BITFIELD (686),
+  BITFIELD (CMOV),
+  BITFIELD (FXSR),
+  BITFIELD (Clflush),
+  BITFIELD (Nop),
+  BITFIELD (SYSCALL),
+  BITFIELD (8087),
+  BITFIELD (287),
+  BITFIELD (387),
+  BITFIELD (687),
+  BITFIELD (FISTTP),
+  BITFIELD (MMX),
+  BITFIELD (SSE),
+  BITFIELD (SSE2),
+  BITFIELD (SSE3),
+  BITFIELD (SSSE3),
+  BITFIELD (SSE4_1),
+  BITFIELD (SSE4_2),
+  BITFIELD (AVX),
+  BITFIELD (AVX2),
+  BITFIELD (AVX512F),
+  BITFIELD (AVX512CD),
+  BITFIELD (AVX512ER),
+  BITFIELD (AVX512PF),
+  BITFIELD (AVX512VL),
+  BITFIELD (AVX512DQ),
+  BITFIELD (AVX512BW),
+  BITFIELD (IAMCU),
+  BITFIELD (SSE4a),
+  BITFIELD (3dnow),
+  BITFIELD (3dnowA),
+  BITFIELD (PadLock),
+  BITFIELD (SVME),
+  BITFIELD (VMX),
+  BITFIELD (SMX),
+  BITFIELD (Xsave),
+  BITFIELD (Xsaveopt),
+  BITFIELD (AES),
+  BITFIELD (PCLMUL),
+  BITFIELD (FMA),
+  BITFIELD (FMA4),
+  BITFIELD (XOP),
+  BITFIELD (LWP),
+  BITFIELD (BMI),
+  BITFIELD (TBM),
+  BITFIELD (LM),
+  BITFIELD (Movbe),
+  BITFIELD (CX16),
+  BITFIELD (LAHF_SAHF),
+  BITFIELD (EPT),
+  BITFIELD (Rdtscp),
+  BITFIELD (FSGSBase),
+  BITFIELD (RdRnd),
+  BITFIELD (F16C),
+  BITFIELD (BMI2),
+  BITFIELD (LZCNT),
+  BITFIELD (POPCNT),
+  BITFIELD (MONITOR),
+  BITFIELD (HLE),
+  BITFIELD (RTM),
+  BITFIELD (INVPCID),
+  BITFIELD (VMFUNC),
+  BITFIELD (RDSEED),
+  BITFIELD (ADX),
+  BITFIELD (PRFCHW),
+  BITFIELD (SMAP),
+  BITFIELD (SHA),
+  BITFIELD (ClflushOpt),
+  BITFIELD (XSAVES),
+  BITFIELD (XSAVEC),
+  BITFIELD (PREFETCHWT1),
+  BITFIELD (SE1),
+  BITFIELD (CLWB),
+  BITFIELD (MPX),
+  BITFIELD (AVX512IFMA),
+  BITFIELD (AVX512VBMI),
+  BITFIELD (AVX512_4FMAPS),
+  BITFIELD (AVX512_4VNNIW),
+  BITFIELD (AVX512_VPOPCNTDQ),
+  BITFIELD (AVX512_VBMI2),
+  BITFIELD (AVX512_VNNI),
+  BITFIELD (AVX512_BITALG),
+  BITFIELD (AVX512_BF16),
+  BITFIELD (AVX512_VP2INTERSECT),
+  BITFIELD (TDX),
+  BITFIELD (AVX_VNNI),
+  BITFIELD (AVX512_FP16),
+  BITFIELD (PREFETCHI),
+  BITFIELD (AVX_IFMA),
+  BITFIELD (AVX_VNNI_INT8),
+  BITFIELD (CMPCCXADD),
+  BITFIELD (WRMSRNS),
+  BITFIELD (MSRLIST),
+  BITFIELD (AVX_NE_CONVERT),
+  BITFIELD (RAO_INT),
+  BITFIELD (FRED),
+  BITFIELD (LKGS),
+  BITFIELD (MWAITX),
+  BITFIELD (CLZERO),
+  BITFIELD (OSPKE),
+  BITFIELD (RDPID),
+  BITFIELD (PTWRITE),
+  BITFIELD (IBT),
+  BITFIELD (SHSTK),
+  BITFIELD (GFNI),
+  BITFIELD (VAES),
+  BITFIELD (VPCLMULQDQ),
+  BITFIELD (WBNOINVD),
+  BITFIELD (PCONFIG),
+  BITFIELD (WAITPKG),
+  BITFIELD (UINTR),
+  BITFIELD (CLDEMOTE),
+  BITFIELD (AMX_INT8),
+  BITFIELD (AMX_BF16),
+  BITFIELD (AMX_FP16),
+  BITFIELD (AMX_COMPLEX),
+  BITFIELD (AMX_TILE),
+  BITFIELD (MOVDIRI),
+  BITFIELD (MOVDIR64B),
+  BITFIELD (ENQCMD),
+  BITFIELD (SERIALIZE),
+  BITFIELD (RDPRU),
+  BITFIELD (MCOMMIT),
+  BITFIELD (SEV_ES),
+  BITFIELD (TSXLDTRK),
+  BITFIELD (KL),
+  BITFIELD (WideKL),
+  BITFIELD (HRESET),
+  BITFIELD (INVLPGB),
+  BITFIELD (TLBSYNC),
+  BITFIELD (SNP),
+  BITFIELD (RMPQUERY),
+  BITFIELD (64),
+  BITFIELD (No64),
 #ifdef CpuUnused
-  BITFIELD (CpuUnused),
+  BITFIELD (Unused),
 #endif
 };
 
+#undef BITFIELD
+#define BITFIELD(n) { n, 0, #n }
+
 static bitfield opcode_modifiers[] =
 {
   BITFIELD (D),
@@ -664,51 +419,35 @@ static bitfield opcode_modifiers[] =
   BITFIELD (Modrm),
   BITFIELD (Jump),
   BITFIELD (FloatMF),
-  BITFIELD (FloatR),
   BITFIELD (Size),
-  BITFIELD (CheckRegSize),
+  BITFIELD (CheckOperandSize),
+  BITFIELD (OperandConstraint),
   BITFIELD (MnemonicSize),
-  BITFIELD (Anysize),
   BITFIELD (No_bSuf),
   BITFIELD (No_wSuf),
   BITFIELD (No_lSuf),
   BITFIELD (No_sSuf),
   BITFIELD (No_qSuf),
-  BITFIELD (No_ldSuf),
   BITFIELD (FWait),
   BITFIELD (IsString),
   BITFIELD (RegMem),
   BITFIELD (BNDPrefixOk),
-  BITFIELD (NoTrackPrefixOk),
-  BITFIELD (IsLockable),
-  BITFIELD (RegKludge),
-  BITFIELD (Implicit1stXmm0),
-  BITFIELD (RepPrefixOk),
-  BITFIELD (HLEPrefixOk),
-  BITFIELD (ToDword),
-  BITFIELD (ToQword),
-  BITFIELD (AddrPrefixOpReg),
+  BITFIELD (PrefixOk),
   BITFIELD (IsPrefix),
   BITFIELD (ImmExt),
   BITFIELD (NoRex64),
-  BITFIELD (Ugh),
   BITFIELD (Vex),
   BITFIELD (VexVVVV),
   BITFIELD (VexW),
   BITFIELD (OpcodePrefix),
-  BITFIELD (VexSources),
   BITFIELD (SIB),
   BITFIELD (SSE2AVX),
-  BITFIELD (NoAVX),
   BITFIELD (EVex),
   BITFIELD (Masking),
   BITFIELD (Broadcast),
   BITFIELD (StaticRounding),
   BITFIELD (SAE),
   BITFIELD (Disp8MemShift),
-  BITFIELD (NoDefMask),
-  BITFIELD (ImplicitQuadGroup),
-  BITFIELD (SwapSources),
   BITFIELD (Optimize),
   BITFIELD (ATTMnemonic),
   BITFIELD (ATTSyntax),
@@ -762,7 +501,6 @@ static bitfield operand_types[] =
   BITFIELD (Disp8),
   BITFIELD (Disp16),
   BITFIELD (Disp32),
-  BITFIELD (Disp32S),
   BITFIELD (Disp64),
   BITFIELD (Byte),
   BITFIELD (Word),
@@ -801,13 +539,13 @@ struct template_param {
 };
 
 struct template {
-  const struct template *next;
+  struct template *next;
   const char *name;
   const struct template_instance *instances;
   const struct template_param *params;
 };
 
-static const struct template *templates;
+static struct template *templates;
 
 static int
 compare (const void *x, const void *y)
@@ -823,7 +561,7 @@ fail (const char *message, ...)
   va_list args;
 
   va_start (args, message);
-  fprintf (stderr, _("%s: error: "), program_name);
+  fprintf (stderr, "%s: error: ", program_name);
   vfprintf (stderr, message, args);
   va_end (args);
   xexit (1);
@@ -833,7 +571,7 @@ static void
 process_copyright (FILE *fp)
 {
   fprintf (fp, "/* This file is automatically generated by i386-gen.  Do not edit!  */\n\
-/* Copyright (C) 2007-2020 Free Software Foundation, Inc.\n\
+/* Copyright (C) 2007-2023 Free Software Foundation, Inc.\n\
 \n\
    This file is part of the GNU opcodes library.\n\
 \n\
@@ -908,32 +646,6 @@ next_field (char *str, char sep, char **next, char *last)
 
 static void set_bitfield (char *, bitfield *, int, unsigned int, int);
 
-static int
-set_bitfield_from_cpu_flag_init (char *f, bitfield *array, unsigned int size,
-                                int lineno)
-{
-  char *str, *next, *last;
-  unsigned int i;
-
-  for (i = 0; i < ARRAY_SIZE (cpu_flag_init); i++)
-    if (strcmp (cpu_flag_init[i].name, f) == 0)
-      {
-       /* Turn on selective bits.  */
-       char *init = xstrdup (cpu_flag_init[i].init);
-       last = init + strlen (init);
-       for (next = init; next && next < last; )
-         {
-           str = next_field (next, '|', &next, last);
-           if (str)
-             set_bitfield (str, array, 1, size, lineno);
-         }
-       free (init);
-       return 0;
-      }
-
-  return -1;
-}
-
 static void
 set_bitfield (char *f, bitfield *array, int value,
              unsigned int size, int lineno)
@@ -944,17 +656,6 @@ set_bitfield (char *f, bitfield *array, int value,
   if (*f == '\0')
     return;
 
-  if (strcmp (f, "CpuFP") == 0)
-    {
-      set_bitfield("Cpu387", array, value, size, lineno);
-      set_bitfield("Cpu287", array, value, size, lineno);
-      f = "Cpu8087";
-    }
-  else if (strcmp (f, "Mmword") == 0)
-    f= "Qword";
-  else if (strcmp (f, "Oword") == 0)
-    f= "Xmmword";
-
   for (i = 0; i < size; i++)
     if (strcasecmp (array[i].name, f) == 0)
       {
@@ -985,14 +686,77 @@ set_bitfield (char *f, bitfield *array, int value,
        }
     }
 
-  /* Handle CPU_XXX_FLAGS.  */
-  if (value == 1 && !set_bitfield_from_cpu_flag_init (f, array, size, lineno))
-    return;
-
   if (lineno != -1)
-    fail (_("%s: %d: unknown bitfield: %s\n"), filename, lineno, f);
+    fail ("%s: %d: unknown bitfield: %s\n", filename, lineno, f);
   else
-    fail (_("unknown bitfield: %s\n"), f);
+    fail ("unknown bitfield: %s\n", f);
+}
+
+static void
+add_isa_dependencies (bitfield *flags, const char *f, int value,
+                     unsigned int reverse)
+{
+  unsigned int i;
+  char *str = NULL;
+  const char *isa = f;
+  bool is_isa = false, is_avx = false;
+
+  /* Need to find base entry for references to auxiliary ones.  */
+  if (strchr (f, ':'))
+    {
+      str = xstrdup (f);
+      *strchr (str, ':') = '\0';
+      isa = str;
+    }
+  for (i = 0; i < Cpu64; ++i)
+    if (strcasecmp (flags[i].name, isa) == 0)
+      {
+       flags[i].value = value;
+       if (reverse < ARRAY_SIZE (isa_reverse_deps[0])
+           /* Don't record the feature itself here.  */
+           && reverse != i
+           /* Don't record base architectures.  */
+           && reverse > Cpu686)
+         isa_reverse_deps[i][reverse] = 1;
+       is_isa = true;
+       if (i == CpuAVX || i == CpuXOP)
+         is_avx = true;
+       break;
+      }
+  free (str);
+
+  /* Do not turn off dependencies.  */
+  if (is_isa && !value)
+    return;
+
+  for (i = 0; i < ARRAY_SIZE (isa_dependencies); ++i)
+    if (strcasecmp (isa_dependencies[i].name, f) == 0)
+      {
+       char *deps = xstrdup (isa_dependencies[i].deps);
+       char *next = deps;
+       char *last = deps + strlen (deps);
+
+       for (; next && next < last; )
+         {
+           char *str = next_field (next, '|', &next, last);
+
+           /* No AVX/XOP -> SSE reverse dependencies.  */
+           if (is_avx && strncmp (str, "SSE", 3) == 0)
+             add_isa_dependencies (flags, str, value, CpuMax);
+           else
+             add_isa_dependencies (flags, str, value, reverse);
+         }
+       free (deps);
+
+       /* ISA extensions with dependencies need CPU_ANY_*_FLAGS emitted.  */
+       if (reverse < ARRAY_SIZE (isa_reverse_deps[0]))
+         isa_reverse_deps[reverse][reverse] = 1;
+
+       return;
+      }
+
+  if (!is_isa)
+    fail ("unknown bitfield: %s\n", f);
 }
 
 static void
@@ -1027,26 +791,28 @@ output_cpu_flags (FILE *table, bitfield *flags, unsigned int size,
 }
 
 static void
-process_i386_cpu_flag (FILE *table, char *flag, int macro,
+process_i386_cpu_flag (FILE *table, char *flag,
+                      const char *name,
                       const char *comma, const char *indent,
-                      int lineno)
+                      int lineno, unsigned int reverse)
 {
-  char *str, *next, *last;
+  char *str, *next = flag, *last;
   unsigned int i;
+  int value = 1;
+  bool is_isa = false;
   bitfield flags [ARRAY_SIZE (cpu_flags)];
 
   /* Copy the default cpu flags.  */
   memcpy (flags, cpu_flags, sizeof (cpu_flags));
 
-  if (strcasecmp (flag, "unknown") == 0)
+  if (flag == NULL)
     {
-      /* We turn on everything except for cpu64 in case of
-        CPU_UNKNOWN_FLAGS.  */
-      for (i = 0; i < ARRAY_SIZE (flags); i++)
-       if (flags[i].position != Cpu64)
-         flags[i].value = 1;
+      for (i = 0; i < ARRAY_SIZE (isa_reverse_deps[0]); ++i)
+       flags[i].value = isa_reverse_deps[reverse][i];
+      goto output;
     }
-  else if (flag[0] == '~')
+
+  if (flag[0] == '~')
     {
       last = flag + strlen (flag);
 
@@ -1055,39 +821,71 @@ process_i386_cpu_flag (FILE *table, char *flag, int macro,
          last -= 1;
          next = flag + 2;
          if (*last != ')')
-           fail (_("%s: %d: missing `)' in bitfield: %s\n"), filename,
+           fail ("%s: %d: missing `)' in bitfield: %s\n", filename,
                  lineno, flag);
          *last = '\0';
        }
       else
        next = flag + 1;
 
-      /* First we turn on everything except for cpu64.  */
+      /* First we turn on everything except for cpu64, cpuno64, and - if
+         present - the padding field.  */
       for (i = 0; i < ARRAY_SIZE (flags); i++)
-       if (flags[i].position != Cpu64)
+       if (flags[i].position < Cpu64)
          flags[i].value = 1;
 
       /* Turn off selective bits.  */
+      value = 0;
+    }
+
+  if (name != NULL && value != 0)
+    {
+      for (i = 0; i < ARRAY_SIZE (flags); i++)
+       if (strcasecmp (flags[i].name, name) == 0)
+         {
+           add_isa_dependencies (flags, name, 1, reverse);
+           is_isa = true;
+           break;
+         }
+    }
+
+  if (strcmp (flag, "0"))
+    {
+      if (is_isa)
+       return;
+
+      /* Turn on/off selective bits.  */
+      last = flag + strlen (flag);
       for (; next && next < last; )
        {
          str = next_field (next, '|', &next, last);
-         if (str)
-           set_bitfield (str, flags, 0, ARRAY_SIZE (flags), lineno);
+         if (name == NULL)
+           set_bitfield (str, flags, value, ARRAY_SIZE (flags), lineno);
+         else
+           add_isa_dependencies (flags, str, value, reverse);
        }
     }
-  else if (strcmp (flag, "0"))
+
+ output:
+  if (name != NULL)
     {
-      /* Turn on selective bits.  */
-      last = flag + strlen (flag);
-      for (next = flag; next && next < last; )
+      size_t len = strlen (name);
+      char *upper = xmalloc (len + 1);
+
+      for (i = 0; i < len; ++i)
        {
-         str = next_field (next, '|', &next, last);
-         if (str)
-           set_bitfield (str, flags, 1, ARRAY_SIZE (flags), lineno);
+         /* Don't emit #define-s for auxiliary entries.  */
+         if (name[i] == ':')
+           return;
+         upper[i] = TOUPPER (name[i]);
        }
+      upper[i] = '\0';
+      fprintf (table, "\n#define CPU_%s%s_FLAGS \\\n",
+              flag != NULL ? "": "ANY_", upper);
+      free (upper);
     }
 
-  output_cpu_flags (table, flags, ARRAY_SIZE (flags), macro,
+  output_cpu_flags (table, flags, ARRAY_SIZE (flags), name != NULL,
                    comma, indent);
 }
 
@@ -1111,18 +909,21 @@ output_opcode_modifier (FILE *table, bitfield *modifier, unsigned int size)
   fprintf (table, "%d },\n", modifier[i].value);
 }
 
+/* Returns LOG2 of element size.  */
 static int
-adjust_broadcast_modifier (char **opnd)
+get_element_size (char **opnd, int lineno)
 {
   char *str, *next, *last, *op;
-  int bcst_type = INT_MAX;
+  const char *full = opnd[0];
+  int elem_size = INT_MAX;
 
-  /* Skip the immediate operand.  */
-  op = opnd[0];
-  if (strcasecmp(op, "Imm8") == 0)
-    op = opnd[1];
+  /* Find the memory operand.  */
+  while (full != NULL && strstr(full, "BaseIndex") == NULL)
+    full = *++opnd;
+  if (full == NULL)
+    fail ("%s: %d: no memory operand\n", filename, lineno);
 
-  op = xstrdup (op);
+  op = xstrdup (full);
   last = op + strlen (op);
   for (next = op; next && next < last; )
     {
@@ -1131,42 +932,56 @@ adjust_broadcast_modifier (char **opnd)
        {
          if (strcasecmp(str, "Byte") == 0)
            {
-             /* The smalest broadcast type, no need to check
+             /* The smallest element size, no need to check
                 further.  */
-             bcst_type = BYTE_BROADCAST;
+             elem_size = 0;
              break;
            }
          else if (strcasecmp(str, "Word") == 0)
            {
-             if (bcst_type > WORD_BROADCAST)
-               bcst_type = WORD_BROADCAST;
+             if (elem_size > 1)
+               elem_size = 1;
            }
          else if (strcasecmp(str, "Dword") == 0)
            {
-             if (bcst_type > DWORD_BROADCAST)
-               bcst_type = DWORD_BROADCAST;
+             if (elem_size > 2)
+               elem_size = 2;
            }
          else if (strcasecmp(str, "Qword") == 0)
            {
-             if (bcst_type > QWORD_BROADCAST)
-               bcst_type = QWORD_BROADCAST;
+             if (elem_size > 3)
+               elem_size = 3;
            }
        }
     }
   free (op);
 
-  if (bcst_type == INT_MAX)
-    fail (_("unknown broadcast operand: %s\n"), op);
+  if (elem_size == INT_MAX)
+    fail ("%s: %d: unknown element size: %s\n", filename, lineno, full);
 
-  return bcst_type;
+  return elem_size;
 }
 
-static int
-process_i386_opcode_modifier (FILE *table, char *mod, char **opnd, int lineno)
+static void
+process_i386_opcode_modifier (FILE *table, char *mod, unsigned int space,
+                             unsigned int prefix, const char *extension_opcode,
+                             char **opnd, int lineno)
 {
   char *str, *next, *last;
   bitfield modifiers [ARRAY_SIZE (opcode_modifiers)];
-  unsigned int regular_encoding = 1;
+  static const char *const spaces[] = {
+#define SPACE(n) [SPACE_##n] = #n
+    SPACE(BASE),
+    SPACE(0F),
+    SPACE(0F38),
+    SPACE(0F3A),
+    SPACE(EVEXMAP5),
+    SPACE(EVEXMAP6),
+    SPACE(XOP08),
+    SPACE(XOP09),
+    SPACE(XOP0A),
+#undef SPACE
+  };
 
   active_isstring = 0;
 
@@ -1184,20 +999,38 @@ process_i386_opcode_modifier (FILE *table, char *mod, char **opnd, int lineno)
          if (str)
            {
              int val = 1;
-             if (strcasecmp(str, "Broadcast") == 0)
+
+             if (strncmp(str, "OpcodeSpace", 11) == 0)
                {
-                 val = adjust_broadcast_modifier (opnd);
-                 regular_encoding = 0;
+                 char *end;
+
+                 if (str[11] != '=')
+                   fail ("%s:%d: Missing value for `OpcodeSpace'\n",
+                         filename, lineno);
+
+                 val = strtol (str + 12, &end, 0);
+                 if (*end)
+                   fail ("%s:%d: Bogus value `%s' for `OpcodeSpace'\n",
+                         filename, lineno, end);
+
+                 if (space)
+                   {
+                     if (val != space)
+                       fail ("%s:%d: Conflicting opcode space specifications\n",
+                             filename, lineno);
+                     fprintf (stderr,
+                              "%s:%d: Warning: redundant opcode space specification\n",
+                              filename, lineno);
+                   }
+
+                 space = val;
+                 continue;
                }
-             else if (strcasecmp(str, "Vex") == 0
-                      || strncasecmp(str, "Vex=", 4) == 0
-                      || strcasecmp(str, "EVex") == 0
-                      || strncasecmp(str, "EVex=", 5) == 0
-                      || strncasecmp(str, "Disp8MemShift=", 14) == 0
-                      || strncasecmp(str, "Masking=", 8) == 0
-                      || strcasecmp(str, "SAE") == 0
-                      || strcasecmp(str, "IsPrefix") == 0)
-               regular_encoding = 0;
+
+             if (strcasecmp(str, "Broadcast") == 0)
+               val = get_element_size (opnd, lineno) + BYTE_BROADCAST;
+             else if (strcasecmp(str, "Disp8MemShift") == 0)
+               val = get_element_size (opnd, lineno);
 
              set_bitfield (str, modifiers, val, ARRAY_SIZE (modifiers),
                            lineno);
@@ -1218,6 +1051,19 @@ process_i386_opcode_modifier (FILE *table, char *mod, char **opnd, int lineno)
            }
        }
 
+      if (prefix)
+       {
+         if (!modifiers[OpcodePrefix].value)
+           modifiers[OpcodePrefix].value = prefix;
+         else if (modifiers[OpcodePrefix].value != prefix)
+           fail ("%s:%d: Conflicting prefix specifications\n",
+                 filename, lineno);
+         else
+           fprintf (stderr,
+                    "%s:%d: Warning: redundant prefix specification\n",
+                    filename, lineno);
+       }
+
       if (have_w && !bwlq_suf)
        fail ("%s: %d: stray W modifier\n", filename, lineno);
       if (have_w && !(bwlq_suf & 1))
@@ -1228,9 +1074,14 @@ process_i386_opcode_modifier (FILE *table, char *mod, char **opnd, int lineno)
                 "%s: %d: W modifier without Word/Dword/Qword operand(s)\n",
                 filename, lineno);
     }
-  output_opcode_modifier (table, modifiers, ARRAY_SIZE (modifiers));
 
-  return regular_encoding;
+  if (space >= ARRAY_SIZE (spaces) || !spaces[space])
+    fail ("%s:%d: Unknown opcode space %u\n", filename, lineno, space);
+
+  fprintf (table, " SPACE_%s, %s,\n",
+          spaces[space], extension_opcode ? extension_opcode : "None");
+
+  output_opcode_modifier (table, modifiers, ARRAY_SIZE (modifiers));
 }
 
 enum stage {
@@ -1328,35 +1179,43 @@ process_i386_operand_type (FILE *table, char *op, enum stage stage,
          if (!active_cpu_flags.bitfield.cpu64
              && !active_cpu_flags.bitfield.cpumpx)
            set_bitfield("Disp16", types, 1, ARRAY_SIZE (types), lineno);
-         if (!active_cpu_flags.bitfield.cpu64)
-           set_bitfield("Disp32", types, 1, ARRAY_SIZE (types), lineno);
-         if (!active_cpu_flags.bitfield.cpuno64)
-           set_bitfield("Disp32S", types, 1, ARRAY_SIZE (types), lineno);
+         set_bitfield("Disp32", types, 1, ARRAY_SIZE (types), lineno);
        }
     }
   output_operand_type (table, class, instance, types, ARRAY_SIZE (types),
                       stage, indent);
 }
 
+static char *mkident (const char *mnem)
+{
+  char *ident = xstrdup (mnem), *p = ident;
+
+  do
+    {
+      if (!ISALNUM (*p))
+       *p = '_';
+    }
+  while (*++p);
+
+  return ident;
+}
+
 static void
 output_i386_opcode (FILE *table, const char *name, char *str,
                    char *last, int lineno)
 {
-  unsigned int i;
-  char *operands, *base_opcode, *extension_opcode, *opcode_length;
+  unsigned int i, length, prefix = 0, space = 0;
+  char *base_opcode, *extension_opcode, *end, *ident;
   char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
-
-  /* Find number of operands.  */
-  operands = next_field (str, ',', &str, last);
+  unsigned long long opcode;
 
   /* Find base_opcode.  */
   base_opcode = next_field (str, ',', &str, last);
 
-  /* Find extension_opcode.  */
-  extension_opcode = next_field (str, ',', &str, last);
-
-  /* Find opcode_length.  */
-  opcode_length = next_field (str, ',', &str, last);
+  /* Find extension_opcode, if any.  */
+  extension_opcode = strchr (base_opcode, '/');
+  if (extension_opcode)
+    *extension_opcode++ = '\0';
 
   /* Find cpu_flags.  */
   cpu_flags = next_field (str, ',', &str, last);
@@ -1369,89 +1228,92 @@ output_i386_opcode (FILE *table, const char *name, char *str,
   if (*str != '{')
     abort ();
   str = remove_leading_whitespaces (str + 1);
+  remove_trailing_whitespaces (str);
 
+  /* Remove } and trailing white space. */
   i = strlen (str);
-
-  /* There are at least "X}".  */
-  if (i < 2)
+  if (!i || str[i - 1] != '}')
     abort ();
+  str[--i] = '\0';
+  remove_trailing_whitespaces (str);
 
-  /* Remove trailing white spaces and }. */
-  do
+  if (!*str)
+    operand_types [i = 0] = NULL;
+  else
     {
-      i--;
-      if (ISSPACE (str[i]) || str[i] == '}')
-       str[i] = '\0';
-      else
-       break;
+      last = str + strlen (str);
+
+      /* Find operand_types.  */
+      for (i = 0; i < ARRAY_SIZE (operand_types); i++)
+       {
+         if (str >= last)
+           {
+             operand_types [i] = NULL;
+             break;
+           }
+
+         operand_types [i] = next_field (str, ',', &str, last);
+       }
     }
-  while (i != 0);
 
-  last = str + i;
+  opcode = strtoull (base_opcode, &end, 0);
 
-  /* Find operand_types.  */
-  for (i = 0; i < ARRAY_SIZE (operand_types); i++)
+  /* Determine opcode length.  */
+  for (length = 1; length < 8; ++length)
+    if (!(opcode >> (8 * length)))
+       break;
+
+  /* Transform prefixes encoded in the opcode into opcode modifier
+     representation.  */
+  if (length > 1)
     {
-      if (str >= last)
+      switch (opcode >> (8 * length - 8))
        {
-         operand_types [i] = NULL;
-         break;
+       case 0x66: prefix = PREFIX_0X66; break;
+       case 0xF3: prefix = PREFIX_0XF3; break;
+       case 0xF2: prefix = PREFIX_0XF2; break;
        }
 
-      operand_types [i] = next_field (str, ',', &str, last);
-      if (*operand_types[i] == '0')
-       {
-         if (i != 0)
-           operand_types[i] = NULL;
-         break;
-       }
+      if (prefix)
+       opcode &= (1ULL << (8 * --length)) - 1;
     }
 
-  fprintf (table, "  { \"%s\", %s, %s, %s, %s,\n",
-          name, base_opcode, extension_opcode, opcode_length, operands);
-
-  process_i386_cpu_flag (table, cpu_flags, 0, ",", "    ", lineno);
-
-  if (process_i386_opcode_modifier (table, opcode_modifier,
-                                   operand_types, lineno))
+  /* Transform opcode space encoded in the opcode into opcode modifier
+     representation.  */
+  if (length > 1 && (opcode >> (8 * length - 8)) == 0xf)
     {
-      char *end;
-      unsigned long int length = strtoul (opcode_length, &end, 0);
-      unsigned long int opcode = strtoul (base_opcode, &end, 0);
-      switch (length)
+      switch ((opcode >> (8 * length - 16)) & 0xff)
        {
-       case 3:
-         if ((opcode >> 24) != 0)
-           fail (_("%s: %s: (base_opcode >> 24) != 0: %s\n"),
-                 filename, name, base_opcode);
-         break;
-       case 2:
-         if ((opcode >> 16) != 0)
-           fail (_("%s: %s: (base_opcode >> 16) != 0: %s\n"),
-                 filename, name, base_opcode);
-         break;
-       case 1:
-         if ((opcode >> 8) != 0)
-           fail (_("%s: %s: (base_opcode >> 8) != 0: %s\n"),
-                 filename, name, base_opcode);
-         break;
-       case 0:
-         if (opcode != 0)
-           fail (_("%s: %s: base_opcode != 0: %s\n"),
-                 filename, name, base_opcode);
-         break;
-       default:
-         fail (_("%s: %s: invalid opcode length: %s\n"),
-               filename, name, opcode_length);
-         break;
+       default:   space = SPACE_0F;   break;
+       case 0x38: space = SPACE_0F38; break;
+       case 0x3A: space = SPACE_0F3A; break;
        }
+
+      if (space != SPACE_0F && --length == 1)
+       fail ("%s:%d: %s: unrecognized opcode encoding space\n",
+             filename, lineno, name);
+      opcode &= (1ULL << (8 * --length)) - 1;
     }
 
+  if (length > 2)
+    fail ("%s:%d: %s: residual opcode (0x%0*llx) too large\n",
+         filename, lineno, name, 2 * length, opcode);
+
+  ident = mkident (name);
+  fprintf (table, "  { MN_%s, 0x%0*llx%s, %u,",
+          ident, 2 * (int)length, opcode, end, i);
+  free (ident);
+
+  process_i386_opcode_modifier (table, opcode_modifier, space, prefix,
+                               extension_opcode, operand_types, lineno);
+
+  process_i386_cpu_flag (table, cpu_flags, NULL, ",", "    ", lineno, CpuMax);
+
   fprintf (table, "    { ");
 
   for (i = 0; i < ARRAY_SIZE (operand_types); i++)
     {
-      if (operand_types[i] == NULL || *operand_types[i] == '0')
+      if (!operand_types[i])
        {
          if (i == 0)
            process_i386_operand_type (table, "0", stage_opcodes, "\t  ",
@@ -1470,10 +1332,13 @@ output_i386_opcode (FILE *table, const char *name, char *str,
 
 struct opcode_hash_entry
 {
-  struct opcode_hash_entry *next;
-  char *name;
-  char *opcode;
-  int lineno;
+  const char *name;
+  struct opcode_entry
+  {
+    struct opcode_entry *next;
+    char *opcode;
+    int lineno;
+  } entry;
 };
 
 /* Calculate the hash value of an opcode hash entry P.  */
@@ -1499,18 +1364,40 @@ static void
 parse_template (char *buf, int lineno)
 {
   char sep, *end, *name;
-  struct template *tmpl = xmalloc (sizeof (*tmpl));
+  struct template *tmpl;
   struct template_instance *last_inst = NULL;
 
   buf = remove_leading_whitespaces (buf + 1);
   end = strchr (buf, ':');
   if (end == NULL)
-    fail ("%s: %d: missing ':'\n", filename, lineno);
+    {
+      struct template *prev = NULL;
+
+      end = strchr (buf, '>');
+      if (end == NULL)
+       fail ("%s: %d: missing ':' or '>'\n", filename, lineno);
+      if (*remove_leading_whitespaces (end + 1))
+       fail ("%s: %d: malformed template purge\n", filename, lineno);
+      *end = '\0';
+      remove_trailing_whitespaces (buf);
+      /* Don't bother freeing the various structures.  */
+      for (tmpl = templates; tmpl != NULL; tmpl = (prev = tmpl)->next)
+       if (!strcmp (buf, tmpl->name))
+         break;
+      if (tmpl == NULL)
+       fail ("%s: %d: no template '%s'\n", filename, lineno, buf);
+      if (prev)
+       prev->next = tmpl->next;
+      else
+       templates = tmpl->next;
+      return;
+    }
   *end++ = '\0';
   remove_trailing_whitespaces (buf);
 
   if (*buf == '\0')
     fail ("%s: %d: missing template identifier\n", filename, lineno);
+  tmpl = xmalloc (sizeof (*tmpl));
   tmpl->name = xstrdup (buf);
 
   tmpl->params = NULL;
@@ -1547,9 +1434,11 @@ parse_template (char *buf, int lineno)
       *end++ = '\0';
 
       inst = xmalloc (sizeof (*inst));
+      inst->next = NULL;
+      inst->args = NULL;
 
       cur = next_field (buf, ':', &next, end);
-      inst->name = xstrdup (cur);
+      inst->name = *cur != '$' ? xstrdup (cur) : "";
 
       for (param = tmpl->params; param; param = param->next)
        {
@@ -1585,7 +1474,8 @@ expand_templates (char *name, const char *str, htab_t opcode_hash_table,
 {
   static unsigned int idx, opcode_array_size;
   struct opcode_hash_entry **opcode_array = *opcode_array_p;
-  struct opcode_hash_entry **hash_slot, **entry;
+  struct opcode_hash_entry **hash_slot;
+  struct opcode_entry *entry;
   char *ptr1 = strchr(name, '<'), *ptr2;
 
   if (ptr1 == NULL)
@@ -1611,26 +1501,25 @@ expand_templates (char *name, const char *str, htab_t opcode_hash_table,
 
          opcode_array[idx] = (struct opcode_hash_entry *)
            xmalloc (sizeof (struct opcode_hash_entry));
-         opcode_array[idx]->next = NULL;
          opcode_array[idx]->name = xstrdup (name);
-         opcode_array[idx]->opcode = xstrdup (str);
-         opcode_array[idx]->lineno = lineno;
          *hash_slot = opcode_array[idx];
+         entry = &opcode_array[idx]->entry;
          idx++;
        }
       else
        {
          /* Append it to the existing one.  */
-         entry = hash_slot;
-         while ((*entry) != NULL)
-           entry = &(*entry)->next;
-         *entry = (struct opcode_hash_entry *)
-           xmalloc (sizeof (struct opcode_hash_entry));
-         (*entry)->next = NULL;
-         (*entry)->name = (*hash_slot)->name;
-         (*entry)->opcode = xstrdup (str);
-         (*entry)->lineno = lineno;
+         struct opcode_entry **entryp = &(*hash_slot)->entry.next;
+
+         while (*entryp != NULL)
+           entryp = &(*entryp)->next;
+         entry = (struct opcode_entry *)xmalloc (sizeof (struct opcode_entry));
+         *entryp = entry;
        }
+
+      entry->next = NULL;
+      entry->opcode = xstrdup (str);
+      entry->lineno = lineno;
     }
   else if ((ptr2 = strchr(ptr1 + 1, '>')) == NULL)
     fail ("%s: %d: missing '>'\n", filename, lineno);
@@ -1729,13 +1618,30 @@ expand_templates (char *name, const char *str, htab_t opcode_hash_table,
   return idx;
 }
 
+static int mnemonic_cmp(const void *p1, const void *p2)
+{
+  const struct opcode_hash_entry *const *e1 = p1, *const *e2 = p2;
+  const char *s1 = (*e1)->name, *s2 = (*e2)->name;
+  unsigned int i;
+  size_t l1 = strlen (s1), l2 = strlen (s2);
+
+  for (i = 1; i <= l1 && i <= l2; ++i)
+    {
+      if (s1[l1 - i] != s2[l2 - i])
+       return (unsigned char)s1[l1 - i] - (unsigned char)s2[l2 - i];
+    }
+
+  return (int)(l1 - l2);
+}
+
 static void
 process_i386_opcodes (FILE *table)
 {
   FILE *fp;
   char buf[2048];
-  unsigned int i, j;
-  char *str, *p, *last, *name;
+  unsigned int i, j, nr, offs;
+  size_t l;
+  char *str, *p, *last;
   htab_t opcode_hash_table;
   struct opcode_hash_entry **opcode_array = NULL;
   int lineno = 0, marker = 0;
@@ -1748,26 +1654,48 @@ process_i386_opcodes (FILE *table)
                                         opcode_hash_eq, NULL,
                                         xcalloc, free);
 
+  fprintf (table, "\n#include \"i386-mnem.h\"\n");
   fprintf (table, "\n/* i386 opcode table.  */\n\n");
-  fprintf (table, "const insn_template i386_optab[] =\n{\n");
+  fprintf (table, "static const insn_template i386_optab[] =\n{\n");
 
   /* Put everything on opcode array.  */
   while (!feof (fp))
     {
+      char *name;
+
       if (fgets (buf, sizeof (buf), fp) == NULL)
        break;
 
-      lineno++;
-
       p = remove_leading_whitespaces (buf);
 
-      /* Skip comments.  */
-      str = strstr (p, "//");
-      if (str != NULL)
-       str[0] = '\0';
+      for ( ; ; )
+       {
+         lineno++;
 
-      /* Remove trailing white spaces.  */
-      remove_trailing_whitespaces (p);
+         /* Skip comments.  */
+         str = strstr (p, "//");
+         if (str != NULL)
+           {
+             str[0] = '\0';
+             remove_trailing_whitespaces (p);
+             break;
+           }
+
+         /* Look for line continuation character.  */
+         remove_trailing_whitespaces (p);
+         j = strlen (buf);
+         if (!j || buf[j - 1] != '+')
+           break;
+         if (j >= sizeof (buf) - 1)
+           fail ("%s: %d: (continued) line too long\n", filename, lineno);
+
+         if (fgets (buf + j - 1, sizeof (buf) - j + 1, fp) == NULL)
+           {
+             fprintf (stderr, "%s: Line continuation on last line?\n",
+                      filename);
+             break;
+           }
+       }
 
       switch (p[0])
        {
@@ -1816,11 +1744,11 @@ process_i386_opcodes (FILE *table)
   /* Process opcode array.  */
   for (j = 0; j < i; j++)
     {
-      struct opcode_hash_entry *next;
+      const char *name = opcode_array[j]->name;
+      struct opcode_entry *next;
 
-      for (next = opcode_array[j]; next; next = next->next)
+      for (next = &opcode_array[j]->entry; next; next = next->next)
        {
-         name = next->name;
          str = next->opcode;
          lineno = next->lineno;
          last = str + strlen (str);
@@ -1830,17 +1758,75 @@ process_i386_opcodes (FILE *table)
 
   fclose (fp);
 
-  fprintf (table, "  { NULL, 0, 0, 0, 0,\n");
+  fprintf (table, "};\n");
 
-  process_i386_cpu_flag (table, "0", 0, ",", "    ", -1);
+  /* Generate opcode sets array.  */
+  fprintf (table, "\n/* i386 opcode sets table.  */\n\n");
+  fprintf (table, "static const insn_template *const i386_op_sets[] =\n{\n");
+  fprintf (table, "  i386_optab,\n");
 
-  process_i386_opcode_modifier (table, "0", NULL, -1);
+  for (nr = j = 0; j < i; j++)
+    {
+      struct opcode_entry *next = &opcode_array[j]->entry;
 
-  fprintf (table, "    { ");
-  process_i386_operand_type (table, "0", stage_opcodes, "\t  ", -1);
-  fprintf (table, " } }\n");
+      do
+       {
+         ++nr;
+         next = next->next;
+       }
+      while (next);
+      fprintf (table, "  i386_optab + %u,\n", nr);
+    }
 
   fprintf (table, "};\n");
+
+  /* Emit mnemonics and associated #define-s.  */
+  qsort (opcode_array, i, sizeof (*opcode_array), mnemonic_cmp);
+
+  fp = fopen ("i386-mnem.h", "w");
+  if (fp == NULL)
+    fail ("can't create i386-mnem.h, errno = %s\n",
+         xstrerror (errno));
+
+  process_copyright (fp);
+
+  fprintf (table, "\n/* i386 mnemonics table.  */\n\n");
+  fprintf (table, "const char i386_mnemonics[] =\n");
+  fprintf (fp, "\nextern const char i386_mnemonics[];\n\n");
+
+  str = NULL;
+  for (l = strlen (opcode_array[offs = j = 0]->name); j < i; j++)
+    {
+      const char *name = opcode_array[j]->name;
+      const char *next = NULL;
+      size_t l1 = j + 1 < i ? strlen(next = opcode_array[j + 1]->name) : 0;
+
+      if (str == NULL)
+       str = mkident (name);
+      if (l < l1 && !strcmp(name, next + l1 - l))
+       {
+         fprintf (fp, "#define MN_%s ", str);
+         free (str);
+         str = mkident (next);
+         fprintf (fp, "(MN_%s + %u)\n", str, l1 - l);
+       }
+      else
+       {
+         fprintf (table, "  \"\\0\"\"%s\"\n", name);
+         fprintf (fp, "#define MN_%s %#x\n", str, offs + 1);
+         offs += strlen (name) + 1;
+         free (str);
+         str = NULL;
+       }
+      l = l1;
+    }
+
+  fprintf (table, "  \"\\0\"\".insn\"\n");
+  fprintf (fp, "#define MN__insn %#x\n", offs + 1);
+
+  fprintf (table, ";\n");
+
+  fclose (fp);
 }
 
 static void
@@ -1856,11 +1842,11 @@ process_i386_registers (FILE *table)
   filename = "i386-reg.tbl";
   fp = fopen (filename, "r");
   if (fp == NULL)
-    fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
+    fail ("can't find i386-reg.tbl for reading, errno = %s\n",
          xstrerror (errno));
 
   fprintf (table, "\n/* i386 register table.  */\n\n");
-  fprintf (table, "const reg_entry i386_regtab[] =\n{\n");
+  fprintf (table, "static const reg_entry i386_regtab[] =\n{\n");
 
   while (!feof (fp))
     {
@@ -1923,7 +1909,7 @@ process_i386_registers (FILE *table)
 
   fprintf (table, "};\n");
 
-  fprintf (table, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
+  fprintf (table, "\nstatic const unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
 }
 
 static void
@@ -1931,29 +1917,53 @@ process_i386_initializers (void)
 {
   unsigned int i;
   FILE *fp = fopen ("i386-init.h", "w");
-  char *init;
 
   if (fp == NULL)
-    fail (_("can't create i386-init.h, errno = %s\n"),
+    fail ("can't create i386-init.h, errno = %s\n",
          xstrerror (errno));
 
   process_copyright (fp);
 
-  for (i = 0; i < ARRAY_SIZE (cpu_flag_init); i++)
+  for (i = 0; i < Cpu64; i++)
+    process_i386_cpu_flag (fp, "0", cpu_flags[i].name, "", "  ", -1, i);
+
+  for (i = 0; i < ARRAY_SIZE (isa_dependencies); i++)
     {
-      fprintf (fp, "\n#define %s \\\n", cpu_flag_init[i].name);
-      init = xstrdup (cpu_flag_init[i].init);
-      process_i386_cpu_flag (fp, init, 1, "", "  ", -1);
-      free (init);
+      char *deps = xstrdup (isa_dependencies[i].deps);
+
+      process_i386_cpu_flag (fp, deps, isa_dependencies[i].name,
+                            "", "  ", -1, CpuMax);
+      free (deps);
     }
 
-  for (i = 0; i < ARRAY_SIZE (operand_type_init); i++)
+  /* Early x87 is somewhat special: Both 287 and 387 not only add new insns
+     but also remove some.  Hence 8087 isn't a prereq to 287, and 287 isn't
+     one to 387.  We want the reverse to be true though: Disabling 8087 also
+     is to disable 287+ and later; disabling 287 also means disabling 387+.  */
+  memcpy (isa_reverse_deps[Cpu287], isa_reverse_deps[Cpu387],
+          sizeof (isa_reverse_deps[0]));
+  isa_reverse_deps[Cpu287][Cpu387] = 1;
+  memcpy (isa_reverse_deps[Cpu8087], isa_reverse_deps[Cpu287],
+          sizeof (isa_reverse_deps[0]));
+  isa_reverse_deps[Cpu8087][Cpu287] = 1;
+
+  /* While we treat POPCNT as a prereq to SSE4.2, its disabling should not
+     lead to disabling of anything else.  */
+  memset (isa_reverse_deps[CpuPOPCNT], 0, sizeof (isa_reverse_deps[0]));
+
+  for (i = Cpu686 + 1; i < ARRAY_SIZE (isa_reverse_deps); i++)
     {
-      fprintf (fp, "\n\n#define %s \\\n  ", operand_type_init[i].name);
-      init = xstrdup (operand_type_init[i].init);
-      process_i386_operand_type (fp, init, stage_macros, "      ", -1);
-      free (init);
+      size_t len;
+      char *upper;
+
+      if (memchr(isa_reverse_deps[i], 1,
+         ARRAY_SIZE (isa_reverse_deps[0])) == NULL)
+       continue;
+
+      isa_reverse_deps[i][i] = 1;
+      process_i386_cpu_flag (fp, NULL, cpu_flags[i].name, "", "  ", -1, i);
     }
+
   fprintf (fp, "\n");
 
   fclose (fp);
@@ -2024,7 +2034,7 @@ main (int argc, char **argv)
 
   if (srcdir != NULL)
     if (chdir (srcdir) != 0)
-      fail (_("unable to change directory to \"%s\", errno = %s\n"),
+      fail ("unable to change directory to \"%s\", errno = %s\n",
            srcdir, xstrerror (errno));
 
   /* cpu_flags isn't sorted by position.  */
@@ -2038,16 +2048,16 @@ main (int argc, char **argv)
   static_assert (ARRAY_SIZE (cpu_flags) == CpuMax + 2);
 
   if ((cpumax - 1) != CpuMax)
-    fail (_("CpuMax != %d!\n"), cpumax);
+    fail ("CpuMax != %d!\n", cpumax);
 #else
   static_assert (ARRAY_SIZE (cpu_flags) == CpuMax + 1);
 
   if (cpumax != CpuMax)
-    fail (_("CpuMax != %d!\n"), cpumax);
+    fail ("CpuMax != %d!\n", cpumax);
 
   c = CpuNumOfBits - CpuMax - 1;
   if (c)
-    fail (_("%d unused bits in i386_cpu_flags.\n"), c);
+    fail ("%d unused bits in i386_cpu_flags.\n", c);
 #endif
 
   static_assert (ARRAY_SIZE (opcode_modifiers) == Opcode_Modifier_Num);
@@ -2062,7 +2072,7 @@ main (int argc, char **argv)
 
   c = OTNumOfBits - OTNum;
   if (c)
-    fail (_("%d unused bits in i386_operand_type.\n"), c);
+    fail ("%d unused bits in i386_operand_type.\n", c);
 #endif
 
   qsort (cpu_flags, ARRAY_SIZE (cpu_flags), sizeof (cpu_flags [0]),
@@ -2076,7 +2086,7 @@ main (int argc, char **argv)
 
   table = fopen ("i386-tbl.h", "w");
   if (table == NULL)
-    fail (_("can't create i386-tbl.h, errno = %s\n"),
+    fail ("can't create i386-tbl.h, errno = %s\n",
          xstrerror (errno));
 
   process_copyright (table);