X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Fi386-gen.c;h=6e33fc56df2287ca97213b0979741b40688138c6;hb=e409955ddcc33743044f217a3cc0541e0e6211b7;hp=1c5082ea0dcededd03a07f4624629090f63e0f65;hpb=507916b8551f6227da9fe8071267c164a3014b79;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/i386-gen.c b/opcodes/i386-gen.c index 1c5082ea0d..6e33fc56df 100644 --- a/opcodes/i386-gen.c +++ b/opcodes/i386-gen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2019 Free Software Foundation, Inc. +/* Copyright (C) 2007-2020 Free Software Foundation, Inc. This file is part of the GNU opcodes library. @@ -90,9 +90,9 @@ static initializer cpu_flag_init[] = { "CPU_K8_FLAGS", "CPU_ATHLON_FLAGS|CpuRdtscp|CPU_SSE2_FLAGS|CpuLM" }, { "CPU_AMDFAM10_FLAGS", - "CPU_K8_FLAGS|CpuFISTTP|CPU_SSE4A_FLAGS|CpuABM" }, + "CPU_K8_FLAGS|CpuFISTTP|CPU_SSE4A_FLAGS|CpuLZCNT|CpuPOPCNT" }, { "CPU_BDVER1_FLAGS", - "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuRdtscp|CpuCX16|CPU_XOP_FLAGS|CpuABM|CpuLWP|CpuSVME|CpuAES|CpuPCLMUL|CpuLZCNT|CpuPRFCHW" }, + "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", @@ -100,11 +100,11 @@ static initializer cpu_flag_init[] = { "CPU_BDVER4_FLAGS", "CPU_BDVER3_FLAGS|CpuAVX2|CpuMovbe|CpuBMI2|CpuRdRnd|CpuMWAITX" }, { "CPU_ZNVER1_FLAGS", - "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuRdtscp|CpuCX16|CPU_AVX2_FLAGS|CpuSSE4A|CpuABM|CpuSVME|CpuAES|CpuPCLMUL|CpuLZCNT|CpuPRFCHW|CpuFMA|CpuBMI|CpuF16C|CpuXsaveopt|CpuFSGSBase|CpuMovbe|CpuBMI2|CpuRdRnd|CpuADX|CpuRdSeed|CpuSMAP|CpuSHA|CpuXSAVEC|CpuXSAVES|CpuClflushOpt|CpuCLZERO|CpuMWAITX" }, + "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|CpuRDPID|CpuWBNOINVD|CpuCLWB" }, + "CPU_ZNVER1_FLAGS|CpuCLWB|CpuRDPID|CpuRDPRU|CpuMCOMMIT|CpuWBNOINVD" }, { "CPU_BTVER1_FLAGS", - "CPU_GENERIC64_FLAGS|CpuFISTTP|CpuCX16|CpuRdtscp|CPU_SSSE3_FLAGS|CpuSSE4A|CpuABM|CpuPRFCHW|CpuCX16|CpuClflush|CpuFISTTP|CpuSVME|CpuLZCNT" }, + "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", @@ -138,7 +138,7 @@ static initializer cpu_flag_init[] = { "CPU_SSE4_1_FLAGS", "CPU_SSSE3_FLAGS|CpuSSE4_1" }, { "CPU_SSE4_2_FLAGS", - "CPU_SSE4_1_FLAGS|CpuSSE4_2" }, + "CPU_SSE4_1_FLAGS|CpuSSE4_2|CpuPOPCNT" }, { "CPU_VMX_FLAGS", "CpuVMX" }, { "CPU_SMX_FLAGS", @@ -181,6 +181,8 @@ static initializer cpu_flag_init[] = "CpuBMI2" }, { "CPU_LZCNT_FLAGS", "CpuLZCNT" }, + { "CPU_POPCNT_FLAGS", + "CpuPOPCNT" }, { "CPU_HLE_FLAGS", "CpuHLE" }, { "CPU_RTM_FLAGS", @@ -200,7 +202,7 @@ static initializer cpu_flag_init[] = { "CPU_SSE4A_FLAGS", "CPU_SSE3_FLAGS|CpuSSE4a" }, { "CPU_ABM_FLAGS", - "CpuABM" }, + "CpuLZCNT|CpuPOPCNT" }, { "CPU_AVX_FLAGS", "CPU_SSE4_2_FLAGS|CPU_XSAVE_FLAGS|CpuAVX" }, { "CPU_AVX2_FLAGS", @@ -301,8 +303,18 @@ static initializer cpu_flag_init[] = "CpuMOVDIR64B" }, { "CPU_ENQCMD_FLAGS", "CpuENQCMD" }, + { "CPU_SERIALIZE_FLAGS", + "CpuSERIALIZE" }, { "CPU_AVX512_VP2INTERSECT_FLAGS", "CpuAVX512_VP2INTERSECT" }, + { "CPU_RDPRU_FLAGS", + "CpuRDPRU" }, + { "CPU_MCOMMIT_FLAGS", + "CpuMCOMMIT" }, + { "CPU_SEV_ES_FLAGS", + "CpuSEV_ES" }, + { "CPU_TSXLDTRK_FLAGS", + "CpuTSXLDTRK"}, { "CPU_ANY_X87_FLAGS", "CPU_ANY_287_FLAGS|Cpu8087" }, { "CPU_ANY_287_FLAGS", @@ -318,17 +330,19 @@ static initializer cpu_flag_init[] = { "CPU_ANY_MMX_FLAGS", "CPU_3DNOWA_FLAGS" }, { "CPU_ANY_SSE_FLAGS", - "CPU_ANY_SSE2_FLAGS|CpuSSE|CpuSSE4a" }, + "CPU_ANY_SSE2_FLAGS|CpuSSE" }, { "CPU_ANY_SSE2_FLAGS", "CPU_ANY_SSE3_FLAGS|CpuSSE2" }, { "CPU_ANY_SSE3_FLAGS", - "CPU_ANY_SSSE3_FLAGS|CpuSSE3" }, + "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", @@ -375,21 +389,12 @@ static initializer cpu_flag_init[] = "CpuMOVDIR64B" }, { "CPU_ANY_ENQCMD_FLAGS", "CpuENQCMD" }, + { "CPU_ANY_SERIALIZE_FLAGS", + "CpuSERIALIZE" }, { "CPU_ANY_AVX512_VP2INTERSECT_FLAGS", "CpuAVX512_VP2INTERSECT" }, -}; - -static const initializer operand_type_shorthands[] = -{ - { "Reg8", "Reg|Byte" }, - { "Reg16", "Reg|Word" }, - { "Reg32", "Reg|Dword" }, - { "Reg64", "Reg|Qword" }, - { "FloatAcc", "Acc|Tbyte" }, - { "FloatReg", "Reg|Tbyte" }, - { "RegXMM", "RegSIMD|Xmmword" }, - { "RegYMM", "RegSIMD|Ymmword" }, - { "RegZMM", "RegSIMD|Zmmword" }, + { "CPU_ANY_TSXLDTRK_FLAGS", + "CpuTSXLDTRK" }, }; static initializer operand_type_init[] = @@ -397,13 +402,13 @@ static initializer operand_type_init[] = { "OPERAND_TYPE_NONE", "0" }, { "OPERAND_TYPE_REG8", - "Reg8" }, + "Class=Reg|Byte" }, { "OPERAND_TYPE_REG16", - "Reg16" }, + "Class=Reg|Word" }, { "OPERAND_TYPE_REG32", - "Reg32" }, + "Class=Reg|Dword" }, { "OPERAND_TYPE_REG64", - "Reg64" }, + "Class=Reg|Qword" }, { "OPERAND_TYPE_IMM1", "Imm1" }, { "OPERAND_TYPE_IMM8", @@ -431,43 +436,41 @@ static initializer operand_type_init[] = { "OPERAND_TYPE_DISP64", "Disp64" }, { "OPERAND_TYPE_INOUTPORTREG", - "InOutPortReg" }, + "Instance=RegD|Word" }, { "OPERAND_TYPE_SHIFTCOUNT", - "ShiftCount" }, + "Instance=RegC|Byte" }, { "OPERAND_TYPE_CONTROL", - "Control" }, + "Class=RegCR" }, { "OPERAND_TYPE_TEST", - "Test" }, + "Class=RegTR" }, { "OPERAND_TYPE_DEBUG", - "Debug" }, + "Class=RegDR" }, { "OPERAND_TYPE_FLOATREG", - "FloatReg" }, + "Class=Reg|Tbyte" }, { "OPERAND_TYPE_FLOATACC", - "FloatAcc" }, + "Instance=Accum|Tbyte" }, { "OPERAND_TYPE_SREG", - "SReg" }, - { "OPERAND_TYPE_JUMPABSOLUTE", - "JumpAbsolute" }, + "Class=SReg" }, { "OPERAND_TYPE_REGMMX", - "RegMMX" }, + "Class=RegMMX" }, { "OPERAND_TYPE_REGXMM", - "RegXMM" }, + "Class=RegSIMD|Xmmword" }, { "OPERAND_TYPE_REGYMM", - "RegYMM" }, + "Class=RegSIMD|Ymmword" }, { "OPERAND_TYPE_REGZMM", - "RegZMM" }, + "Class=RegSIMD|Zmmword" }, { "OPERAND_TYPE_REGMASK", - "RegMask" }, - { "OPERAND_TYPE_ESSEG", - "EsSeg" }, + "Class=RegMask" }, + { "OPERAND_TYPE_REGBND", + "Class=RegBND" }, { "OPERAND_TYPE_ACC8", - "Acc|Byte" }, + "Instance=Accum|Byte" }, { "OPERAND_TYPE_ACC16", - "Acc|Word" }, + "Instance=Accum|Word" }, { "OPERAND_TYPE_ACC32", - "Acc|Dword" }, + "Instance=Accum|Dword" }, { "OPERAND_TYPE_ACC64", - "Acc|Qword" }, + "Instance=Accum|Qword" }, { "OPERAND_TYPE_DISP16_32", "Disp16|Disp32" }, { "OPERAND_TYPE_ANYDISP", @@ -488,8 +491,8 @@ static initializer operand_type_init[] = "Imm32|Imm32S|Imm64|Disp32" }, { "OPERAND_TYPE_IMM32_32S_64_DISP32_64", "Imm32|Imm32S|Imm64|Disp32|Disp64" }, - { "OPERAND_TYPE_REGBND", - "RegBND" }, + { "OPERAND_TYPE_ANYIMM", + "Imm1|Imm8|Imm8S|Imm16|Imm32|Imm32S|Imm64" }, }; typedef struct bitfield @@ -545,7 +548,6 @@ static bitfield cpu_flags[] = BITFIELD (CpuSVME), BITFIELD (CpuVMX), BITFIELD (CpuSMX), - BITFIELD (CpuABM), BITFIELD (CpuXsave), BITFIELD (CpuXsaveopt), BITFIELD (CpuAES), @@ -566,6 +568,7 @@ static bitfield cpu_flags[] = BITFIELD (CpuF16C), BITFIELD (CpuBMI2), BITFIELD (CpuLZCNT), + BITFIELD (CpuPOPCNT), BITFIELD (CpuHLE), BITFIELD (CpuRTM), BITFIELD (CpuINVPCID), @@ -611,6 +614,11 @@ static bitfield cpu_flags[] = BITFIELD (CpuMOVDIRI), BITFIELD (CpuMOVDIR64B), BITFIELD (CpuENQCMD), + BITFIELD (CpuSERIALIZE), + BITFIELD (CpuRDPRU), + BITFIELD (CpuMCOMMIT), + BITFIELD (CpuSEV_ES), + BITFIELD (CpuTSXLDTRK), #ifdef CpuUnused BITFIELD (CpuUnused), #endif @@ -622,17 +630,13 @@ static bitfield opcode_modifiers[] = BITFIELD (W), BITFIELD (Load), BITFIELD (Modrm), - BITFIELD (ShortForm), BITFIELD (Jump), - BITFIELD (JumpDword), - BITFIELD (JumpByte), - BITFIELD (JumpInterSegment), BITFIELD (FloatMF), BITFIELD (FloatR), BITFIELD (Size), BITFIELD (CheckRegSize), - BITFIELD (IgnoreSize), - BITFIELD (DefaultSize), + BITFIELD (MnemonicSize), + BITFIELD (Anysize), BITFIELD (No_bSuf), BITFIELD (No_wSuf), BITFIELD (No_lSuf), @@ -655,7 +659,6 @@ static bitfield opcode_modifiers[] = BITFIELD (IsPrefix), BITFIELD (ImmExt), BITFIELD (NoRex64), - BITFIELD (Rex64), BITFIELD (Ugh), BITFIELD (Vex), BITFIELD (VexVVVV), @@ -677,16 +680,44 @@ static bitfield opcode_modifiers[] = BITFIELD (ATTMnemonic), BITFIELD (ATTSyntax), BITFIELD (IntelSyntax), - BITFIELD (AMD64), - BITFIELD (Intel64), + BITFIELD (ISA64), +}; + +#define CLASS(n) #n, n + +static const struct { + const char *name; + enum operand_class value; +} operand_classes[] = { + CLASS (Reg), + CLASS (SReg), + CLASS (RegCR), + CLASS (RegDR), + CLASS (RegTR), + CLASS (RegMMX), + CLASS (RegSIMD), + CLASS (RegMask), + CLASS (RegBND), }; +#undef CLASS + +#define INSTANCE(n) #n, n + +static const struct { + const char *name; + enum operand_instance value; +} operand_instances[] = { + INSTANCE (Accum), + INSTANCE (RegC), + INSTANCE (RegD), + INSTANCE (RegB), +}; + +#undef INSTANCE + static bitfield operand_types[] = { - BITFIELD (Reg), - BITFIELD (RegMMX), - BITFIELD (RegSIMD), - BITFIELD (RegMask), BITFIELD (Imm1), BITFIELD (Imm8), BITFIELD (Imm8S), @@ -700,15 +731,6 @@ static bitfield operand_types[] = BITFIELD (Disp32), BITFIELD (Disp32S), BITFIELD (Disp64), - BITFIELD (InOutPortReg), - BITFIELD (ShiftCount), - BITFIELD (Control), - BITFIELD (Debug), - BITFIELD (Test), - BITFIELD (SReg), - BITFIELD (Acc), - BITFIELD (JumpAbsolute), - BITFIELD (EsSeg), BITFIELD (Byte), BITFIELD (Word), BITFIELD (Dword), @@ -719,8 +741,6 @@ static bitfield operand_types[] = BITFIELD (Ymmword), BITFIELD (Zmmword), BITFIELD (Unspecified), - BITFIELD (Anysize), - BITFIELD (RegBND), #ifdef OTUnused BITFIELD (OTUnused), #endif @@ -730,6 +750,31 @@ static const char *filename; static i386_cpu_flags active_cpu_flags; static int active_isstring; +struct template_arg { + const struct template_arg *next; + const char *val; +}; + +struct template_instance { + const struct template_instance *next; + const char *name; + const struct template_arg *args; +}; + +struct template_param { + const struct template_param *next; + const char *name; +}; + +struct template { + const struct template *next; + const char *name; + const struct template_instance *instances; + const struct template_param *params; +}; + +static const struct template *templates; + static int compare (const void *x, const void *y) { @@ -754,7 +799,7 @@ static void process_copyright (FILE *fp) { fprintf (fp, "/* This file is automatically generated by i386-gen. Do not edit! */\n\ -/* Copyright (C) 2007-2019 Free Software Foundation, Inc.\n\ +/* Copyright (C) 2007-2020 Free Software Foundation, Inc.\n\ \n\ This file is part of the GNU opcodes library.\n\ \n\ @@ -830,8 +875,8 @@ 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_shorthand (char *f, bitfield *array, unsigned int size, - int lineno) +set_bitfield_from_cpu_flag_init (char *f, bitfield *array, unsigned int size, + int lineno) { char *str, *next, *last; unsigned int i; @@ -852,22 +897,6 @@ set_bitfield_from_shorthand (char *f, bitfield *array, unsigned int size, return 0; } - for (i = 0; i < ARRAY_SIZE (operand_type_shorthands); i++) - if (strcmp (operand_type_shorthands[i].name, f) == 0) - { - /* Turn on selective bits. */ - char *init = xstrdup (operand_type_shorthands[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; } @@ -877,6 +906,10 @@ set_bitfield (char *f, bitfield *array, int value, { unsigned int i; + /* Ignore empty fields; they may result from template expansions. */ + if (*f == '\0') + return; + if (strcmp (f, "CpuFP") == 0) { set_bitfield("Cpu387", array, value, size, lineno); @@ -918,8 +951,8 @@ set_bitfield (char *f, bitfield *array, int value, } } - /* Handle shorthands. */ - if (value == 1 && !set_bitfield_from_shorthand (f, array, size, lineno)) + /* Handle CPU_XXX_FLAGS. */ + if (value == 1 && !set_bitfield_from_cpu_flag_init (f, array, size, lineno)) return; if (lineno != -1) @@ -1157,20 +1190,22 @@ enum stage { }; static void -output_operand_type (FILE *table, bitfield *types, unsigned int size, +output_operand_type (FILE *table, enum operand_class class, + enum operand_instance instance, + const bitfield *types, unsigned int size, enum stage stage, const char *indent) { unsigned int i; - fprintf (table, "{ { "); + fprintf (table, "{ { %d, %d, ", class, instance); for (i = 0; i < size - 1; i++) { - if (((i + 1) % 20) != 0) + if (((i + 3) % 20) != 0) fprintf (table, "%d, ", types[i].value); else fprintf (table, "%d,", types[i].value); - if (((i + 1) % 20) == 0) + if (((i + 3) % 20) == 0) { /* We need \\ for macro. */ if (stage == stage_macros) @@ -1188,6 +1223,8 @@ process_i386_operand_type (FILE *table, char *op, enum stage stage, const char *indent, int lineno) { char *str, *next, *last; + enum operand_class class = ClassNone; + enum operand_instance instance = InstanceNone; bitfield types [ARRAY_SIZE (operand_types)]; /* Copy the default operand type. */ @@ -1201,6 +1238,32 @@ process_i386_operand_type (FILE *table, char *op, enum stage stage, for (next = op; next && next < last; ) { str = next_field (next, '|', &next, last); + if (str) + { + unsigned int i; + + if (!strncmp(str, "Class=", 6)) + { + for (i = 0; i < ARRAY_SIZE(operand_classes); ++i) + if (!strcmp(str + 6, operand_classes[i].name)) + { + class = operand_classes[i].value; + str = NULL; + break; + } + } + + if (str && !strncmp(str, "Instance=", 9)) + { + for (i = 0; i < ARRAY_SIZE(operand_instances); ++i) + if (!strcmp(str + 9, operand_instances[i].name)) + { + instance = operand_instances[i].value; + str = NULL; + break; + } + } + } if (str) { set_bitfield (str, types, 1, ARRAY_SIZE (types), lineno); @@ -1215,13 +1278,14 @@ 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); - set_bitfield("Disp32", 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); } } - output_operand_type (table, types, ARRAY_SIZE (types), stage, - indent); + output_operand_type (table, class, instance, types, ARRAY_SIZE (types), + stage, indent); } static void @@ -1294,8 +1358,7 @@ output_i386_opcode (FILE *table, const char *name, char *str, } fprintf (table, " { \"%s\", %s, %s, %s, %s,\n", - name, operands, base_opcode, extension_opcode, - opcode_length); + name, base_opcode, extension_opcode, opcode_length, operands); process_i386_cpu_flag (table, cpu_flags, 0, ",", " ", lineno); @@ -1349,6 +1412,240 @@ opcode_hash_eq (const void *p, const void *q) return strcmp (name, entry->name) == 0; } +static void +parse_template (char *buf, int lineno) +{ + char sep, *end, *name; + struct template *tmpl = xmalloc (sizeof (*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); + *end++ = '\0'; + remove_trailing_whitespaces (buf); + + if (*buf == '\0') + fail ("%s: %d: missing template identifier\n", filename, lineno); + tmpl->name = xstrdup (buf); + + tmpl->params = NULL; + do { + struct template_param *param; + + buf = remove_leading_whitespaces (end); + end = strpbrk (buf, ":,"); + if (end == NULL) + fail ("%s: %d: missing ':' or ','\n", filename, lineno); + + sep = *end; + *end++ = '\0'; + remove_trailing_whitespaces (buf); + + param = xmalloc (sizeof (*param)); + param->name = xstrdup (buf); + param->next = tmpl->params; + tmpl->params = param; + } while (sep == ':'); + + tmpl->instances = NULL; + do { + struct template_instance *inst; + char *cur, *next; + const struct template_param *param; + + buf = remove_leading_whitespaces (end); + end = strpbrk (buf, ",>"); + if (end == NULL) + fail ("%s: %d: missing ',' or '>'\n", filename, lineno); + + sep = *end; + *end++ = '\0'; + + inst = xmalloc (sizeof (*inst)); + + cur = next_field (buf, ':', &next, end); + inst->name = xstrdup (cur); + + for (param = tmpl->params; param; param = param->next) + { + struct template_arg *arg = xmalloc (sizeof (*arg)); + + cur = next_field (next, ':', &next, end); + if (next > end) + fail ("%s: %d: missing argument for '%s'\n", filename, lineno, param->name); + arg->val = xstrdup (cur); + arg->next = inst->args; + inst->args = arg; + } + + if (tmpl->instances) + last_inst->next = inst; + else + tmpl->instances = inst; + last_inst = inst; + } while (sep == ','); + + buf = remove_leading_whitespaces (end); + if (*buf) + fprintf(stderr, "%s: %d: excess characters '%s'\n", + filename, lineno, buf); + + tmpl->next = templates; + templates = tmpl; +} + +static unsigned int +expand_templates (char *name, const char *str, htab_t opcode_hash_table, + struct opcode_hash_entry ***opcode_array_p, int lineno) +{ + static unsigned int idx, opcode_array_size; + struct opcode_hash_entry **opcode_array = *opcode_array_p; + struct opcode_hash_entry **hash_slot, **entry; + char *ptr1 = strchr(name, '<'), *ptr2; + + if (ptr1 == NULL) + { + /* Get the slot in hash table. */ + hash_slot = (struct opcode_hash_entry **) + htab_find_slot_with_hash (opcode_hash_table, name, + htab_hash_string (name), + INSERT); + + if (*hash_slot == NULL) + { + /* It is the new one. Put it on opcode array. */ + if (idx >= opcode_array_size) + { + /* Grow the opcode array when needed. */ + opcode_array_size += 1024; + opcode_array = (struct opcode_hash_entry **) + xrealloc (opcode_array, + sizeof (*opcode_array) * opcode_array_size); + *opcode_array_p = opcode_array; + } + + 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]; + 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; + } + } + else if ((ptr2 = strchr(ptr1 + 1, '>')) == NULL) + fail ("%s: %d: missing '>'\n", filename, lineno); + else + { + const struct template *tmpl; + const struct template_instance *inst; + + *ptr1 = '\0'; + ptr1 = remove_leading_whitespaces (ptr1 + 1); + remove_trailing_whitespaces (ptr1); + + *ptr2++ = '\0'; + + for ( tmpl = templates; tmpl; tmpl = tmpl->next ) + if (!strcmp(ptr1, tmpl->name)) + break; + if (!tmpl) + fail ("reference to unknown template '%s'\n", ptr1); + + for (inst = tmpl->instances; inst; inst = inst->next) + { + char *name2 = xmalloc(strlen(name) + strlen(inst->name) + strlen(ptr2) + 1); + char *str2 = xmalloc(2 * strlen(str)); + const char *src; + + strcpy (name2, name); + strcat (name2, inst->name); + strcat (name2, ptr2); + + for (ptr1 = str2, src = str; *src; ) + { + const char *ident = tmpl->name, *end; + const struct template_param *param; + const struct template_arg *arg; + + if ((*ptr1 = *src++) != '<') + { + ++ptr1; + continue; + } + while (ISSPACE(*src)) + ++src; + while (*ident && *src == *ident) + ++src, ++ident; + while (ISSPACE(*src)) + ++src; + if (*src != ':' || *ident != '\0') + { + memcpy (++ptr1, tmpl->name, ident - tmpl->name); + ptr1 += ident - tmpl->name; + continue; + } + while (ISSPACE(*++src)) + ; + + end = src; + while (*end != '\0' && !ISSPACE(*end) && *end != '>') + ++end; + + for (param = tmpl->params, arg = inst->args; param; + param = param->next, arg = arg->next) + { + if (end - src == strlen (param->name) + && !memcmp (src, param->name, end - src)) + { + src = end; + break; + } + } + + if (param == NULL) + fail ("template '%s' has no parameter '%.*s'\n", + tmpl->name, (int)(end - src), src); + + while (ISSPACE(*src)) + ++src; + if (*src != '>') + fail ("%s: %d: missing '>'\n", filename, lineno); + + memcpy(ptr1, arg->val, strlen(arg->val)); + ptr1 += strlen(arg->val); + ++src; + } + + *ptr1 = '\0'; + + expand_templates (name2, str2, opcode_hash_table, opcode_array_p, + lineno); + + free (str2); + free (name2); + } + } + + return idx; +} + static void process_i386_opcodes (FILE *table) { @@ -1356,19 +1653,14 @@ process_i386_opcodes (FILE *table) char buf[2048]; unsigned int i, j; char *str, *p, *last, *name; - struct opcode_hash_entry **hash_slot, **entry, *next; htab_t opcode_hash_table; - struct opcode_hash_entry **opcode_array; - unsigned int opcode_array_size = 1024; + struct opcode_hash_entry **opcode_array = NULL; int lineno = 0, marker = 0; filename = "i386-opc.tbl"; fp = stdin; i = 0; - opcode_array = (struct opcode_hash_entry **) - xmalloc (sizeof (*opcode_array) * opcode_array_size); - opcode_hash_table = htab_create_alloc (16, opcode_hash_hash, opcode_hash_eq, NULL, xcalloc, free); @@ -1420,6 +1712,9 @@ process_i386_opcodes (FILE *table) case '\0': continue; break; + case '<': + parse_template (p, lineno); + continue; default: if (!marker) continue; @@ -1431,51 +1726,15 @@ process_i386_opcodes (FILE *table) /* Find name. */ name = next_field (p, ',', &str, last); - /* Get the slot in hash table. */ - hash_slot = (struct opcode_hash_entry **) - htab_find_slot_with_hash (opcode_hash_table, name, - htab_hash_string (name), - INSERT); - - if (*hash_slot == NULL) - { - /* It is the new one. Put it on opcode array. */ - if (i >= opcode_array_size) - { - /* Grow the opcode array when needed. */ - opcode_array_size += 1024; - opcode_array = (struct opcode_hash_entry **) - xrealloc (opcode_array, - sizeof (*opcode_array) * opcode_array_size); - } - - opcode_array[i] = (struct opcode_hash_entry *) - xmalloc (sizeof (struct opcode_hash_entry)); - opcode_array[i]->next = NULL; - opcode_array[i]->name = xstrdup (name); - opcode_array[i]->opcode = xstrdup (str); - opcode_array[i]->lineno = lineno; - *hash_slot = opcode_array[i]; - i++; - } - 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; - } + i = expand_templates (name, str, opcode_hash_table, &opcode_array, + lineno); } /* Process opcode array. */ for (j = 0; j < i; j++) { + struct opcode_hash_entry *next; + for (next = opcode_array[j]; next; next = next->next) { name = next->name; @@ -1712,11 +1971,13 @@ main (int argc, char **argv) /* Check the unused bitfield in i386_operand_type. */ #ifdef OTUnused - static_assert (ARRAY_SIZE (operand_types) == OTNum + 1); + static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH + INSTANCE_WIDTH + == OTNum + 1); #else - static_assert (ARRAY_SIZE (operand_types) == OTNum); + static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH + INSTANCE_WIDTH + == OTNum); - c = OTNumOfBits - OTMax - 1; + c = OTNumOfBits - OTNum; if (c) fail (_("%d unused bits in i386_operand_type.\n"), c); #endif