x86: derive opcode length from opcode value
In the majority of cases we can easily determine the length from the encoding, irrespective of whether a prefix is specified there as well. We further don't even need to record the value in the table entries, as it's easy enough to determine it (without any guesswork, unless an insn with major opcode 00 appeared that requires a 2nd opcode byte to be specified explicitly) when installing the chosen template for further processing. Should an encoding appear which - has a major opcode byte of 66, F3, or F2, - requires a 2nd opcode byte to be specified explicitly, - doesn't have a mandatory prefix we'd need to convert all templates presently encoding a mandatory prefix this way to the Prefix_0X<nn> model to eliminate the respective guessing i386-gen does.
This commit is contained in:
parent
3564871692
commit
9a182d0461
@ -1,3 +1,15 @@
|
||||
2021-03-24 Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
* config/tc-i386.c (struct _i386_insn): New field
|
||||
opcode_length.
|
||||
(md_begin): Drop assertion.
|
||||
(install_template): New.
|
||||
(build_vex_prefix): Call install_template.
|
||||
(match_template): Likewise.
|
||||
(process_operands): Use new opcode_length field.
|
||||
(output_jump): Likewise.
|
||||
(output_insn): Likewise. Adjust psedo prefix check.
|
||||
|
||||
2021-03-24 Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
* config/tc-i386.c (md_begin): Add assertion.
|
||||
|
@ -314,6 +314,9 @@ struct _i386_insn
|
||||
or qword, if given. */
|
||||
char suffix;
|
||||
|
||||
/* OPCODE_LENGTH holds the number of base opcode bytes. */
|
||||
unsigned char opcode_length;
|
||||
|
||||
/* OPERANDS gives the number of given operands. */
|
||||
unsigned int operands;
|
||||
|
||||
@ -3065,8 +3068,6 @@ md_begin (void)
|
||||
|
||||
while (1)
|
||||
{
|
||||
gas_assert (optab->opcode_length == 4
|
||||
|| !(optab->base_opcode >> (8 * optab->opcode_length)));
|
||||
++optab;
|
||||
if (optab->name == NULL
|
||||
|| strcmp (optab->name, (optab - 1)->name) != 0)
|
||||
@ -3584,6 +3585,22 @@ intel_float_operand (const char *mnemonic)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
install_template (const insn_template *t)
|
||||
{
|
||||
unsigned int l;
|
||||
|
||||
i.tm = *t;
|
||||
|
||||
/* Note that for pseudo prefixes this produces a length of 1. But for them
|
||||
the length isn't interesting at all. */
|
||||
for (l = 1; l < 4; ++l)
|
||||
if (!(t->base_opcode >> (8 * l)))
|
||||
break;
|
||||
|
||||
i.opcode_length = l;
|
||||
}
|
||||
|
||||
/* Build the VEX prefix. */
|
||||
|
||||
static void
|
||||
@ -3636,7 +3653,7 @@ build_vex_prefix (const insn_template *t)
|
||||
i.tm.base_opcode ^= (i.tm.base_opcode & 0xee) != 0x6e
|
||||
? Opcode_SIMD_FloatD : Opcode_SIMD_IntD;
|
||||
else /* Use the next insn. */
|
||||
i.tm = t[1];
|
||||
install_template (&t[1]);
|
||||
}
|
||||
|
||||
/* Use 2-byte VEX prefix by swapping commutative source operands if there
|
||||
@ -6665,7 +6682,7 @@ match_template (char mnem_suffix)
|
||||
}
|
||||
|
||||
/* Copy the template we found. */
|
||||
i.tm = *t;
|
||||
install_template (t);
|
||||
|
||||
if (addr_prefix_disp != -1)
|
||||
i.tm.operand_types[addr_prefix_disp]
|
||||
@ -7661,10 +7678,10 @@ process_operands (void)
|
||||
i.tm.name, register_prefix, i.op[0].regs->reg_name);
|
||||
return 0;
|
||||
}
|
||||
if ( i.op[0].regs->reg_num > 3 && i.tm.opcode_length == 1 )
|
||||
if ( i.op[0].regs->reg_num > 3 && i.opcode_length == 1 )
|
||||
{
|
||||
i.tm.base_opcode ^= POP_SEG_SHORT ^ POP_SEG386_SHORT;
|
||||
i.tm.opcode_length = 2;
|
||||
i.opcode_length = 2;
|
||||
}
|
||||
i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
|
||||
}
|
||||
@ -8657,12 +8674,12 @@ output_jump (void)
|
||||
|
||||
if (now_seg == absolute_section)
|
||||
{
|
||||
abs_section_offset += i.tm.opcode_length + size;
|
||||
abs_section_offset += i.opcode_length + size;
|
||||
return;
|
||||
}
|
||||
|
||||
p = frag_more (i.tm.opcode_length + size);
|
||||
switch (i.tm.opcode_length)
|
||||
p = frag_more (i.opcode_length + size);
|
||||
switch (i.opcode_length)
|
||||
{
|
||||
case 2:
|
||||
*p++ = i.tm.base_opcode >> 8;
|
||||
@ -9385,14 +9402,15 @@ output_insn (void)
|
||||
add_prefix (0xf3);
|
||||
break;
|
||||
case PREFIX_NONE:
|
||||
switch (i.tm.opcode_length)
|
||||
switch (i.opcode_length)
|
||||
{
|
||||
case 3:
|
||||
case 2:
|
||||
case 1:
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
/* Check for pseudo prefixes. */
|
||||
if (!i.tm.opcode_modifier.isprefix || i.tm.base_opcode)
|
||||
break;
|
||||
as_bad_where (insn_start_frag->fr_file,
|
||||
insn_start_frag->fr_line,
|
||||
_("pseudo prefix without instruction"));
|
||||
@ -9458,14 +9476,14 @@ output_insn (void)
|
||||
|
||||
/* Now the opcode; be careful about word order here! */
|
||||
if (now_seg == absolute_section)
|
||||
abs_section_offset += i.tm.opcode_length;
|
||||
else if (i.tm.opcode_length == 1)
|
||||
abs_section_offset += i.opcode_length;
|
||||
else if (i.opcode_length == 1)
|
||||
{
|
||||
FRAG_APPEND_1_CHAR (i.tm.base_opcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (i.tm.opcode_length)
|
||||
switch (i.opcode_length)
|
||||
{
|
||||
case 4:
|
||||
p = frag_more (4);
|
||||
@ -9541,7 +9559,7 @@ output_insn (void)
|
||||
|
||||
/* Count prefixes for extended opcode maps. */
|
||||
if (!i.vex.length)
|
||||
switch (i.tm.opcode_length)
|
||||
switch (i.opcode_length)
|
||||
{
|
||||
case 3:
|
||||
if (((i.tm.base_opcode >> 16) & 0xff) == 0xf)
|
||||
|
@ -1,3 +1,13 @@
|
||||
2021-03-24 Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
* i386-gen.c (output_i386_opcode): Drop processing of
|
||||
opcode_length. Calculate length from base_opcode. Adjust prefix
|
||||
encoding determination.
|
||||
(process_i386_opcodes): Drop output of fake opcode_length.
|
||||
* i386-opc.h (struct insn_template): Drop opcode_length field.
|
||||
* i386-opc.tbl: Drop opcode length field from all templates.
|
||||
* i386-tbl.h: Re-generate.
|
||||
|
||||
2021-03-24 Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
* i386-gen.c (process_i386_opcode_modifier): Return void. New
|
||||
|
@ -1355,10 +1355,10 @@ static void
|
||||
output_i386_opcode (FILE *table, const char *name, char *str,
|
||||
char *last, int lineno)
|
||||
{
|
||||
unsigned int i, prefix = 0;
|
||||
char *base_opcode, *extension_opcode, *opcode_length, *end;
|
||||
unsigned int i, length, prefix = 0;
|
||||
char *base_opcode, *extension_opcode, *end;
|
||||
char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
|
||||
unsigned long int opcode, length;
|
||||
unsigned long int opcode;
|
||||
|
||||
/* Find base_opcode. */
|
||||
base_opcode = next_field (str, ',', &str, last);
|
||||
@ -1366,9 +1366,6 @@ output_i386_opcode (FILE *table, const char *name, char *str,
|
||||
/* Find extension_opcode. */
|
||||
extension_opcode = next_field (str, ',', &str, last);
|
||||
|
||||
/* Find opcode_length. */
|
||||
opcode_length = next_field (str, ',', &str, last);
|
||||
|
||||
/* Find cpu_flags. */
|
||||
cpu_flags = next_field (str, ',', &str, last);
|
||||
|
||||
@ -1408,29 +1405,30 @@ output_i386_opcode (FILE *table, const char *name, char *str,
|
||||
}
|
||||
}
|
||||
|
||||
length = strtoul (opcode_length, &end, 0);
|
||||
opcode = strtoul (base_opcode, &end, 0);
|
||||
|
||||
/* Determine opcode length. */
|
||||
for (length = 1; length < 4; ++length)
|
||||
if (!(opcode >> (8 * length)))
|
||||
break;
|
||||
|
||||
/* Transform prefixes encoded in the opcode into opcode modifier
|
||||
representation. */
|
||||
if (length < 4)
|
||||
if (length > 1)
|
||||
{
|
||||
switch (opcode >> (8 * length))
|
||||
switch (opcode >> (8 * length - 8))
|
||||
{
|
||||
case 0: break;
|
||||
case 0x66: prefix = PREFIX_0X66; break;
|
||||
case 0xF3: prefix = PREFIX_0XF3; break;
|
||||
case 0xF2: prefix = PREFIX_0XF2; break;
|
||||
default:
|
||||
fail (_("%s:%d: %s: Unexpected opcode prefix %02lx\n"),
|
||||
filename, lineno, name, opcode >> (8 * length));
|
||||
}
|
||||
|
||||
opcode &= (1UL << (8 * length)) - 1;
|
||||
if (prefix)
|
||||
opcode &= (1UL << (8 * --length)) - 1;
|
||||
}
|
||||
|
||||
fprintf (table, " { \"%s\", 0x%0*lx%s, %s, %lu, %u,\n",
|
||||
name, 2 * (int)length, opcode, end, extension_opcode, length, i);
|
||||
fprintf (table, " { \"%s\", 0x%0*lx%s, %s, %lu,\n",
|
||||
name, 2 * (int)length, opcode, end, extension_opcode, i);
|
||||
|
||||
process_i386_opcode_modifier (table, opcode_modifier, prefix,
|
||||
operand_types, lineno);
|
||||
@ -1822,7 +1820,7 @@ process_i386_opcodes (FILE *table)
|
||||
|
||||
fclose (fp);
|
||||
|
||||
fprintf (table, " { NULL, 0, 0, 0, 0,\n");
|
||||
fprintf (table, " { NULL, 0, 0, 0,\n");
|
||||
|
||||
process_i386_opcode_modifier (table, "0", 0, NULL, -1);
|
||||
|
||||
|
@ -949,9 +949,6 @@ typedef struct insn_template
|
||||
#define Prefix_REX 8 /* {rex} */
|
||||
#define Prefix_NoOptimize 9 /* {nooptimize} */
|
||||
|
||||
/* Opcode length. */
|
||||
unsigned char opcode_length;
|
||||
|
||||
/* how many operands */
|
||||
unsigned char operands;
|
||||
|
||||
|
6598
opcodes/i386-opc.tbl
6598
opcodes/i386-opc.tbl
File diff suppressed because it is too large
Load Diff
8068
opcodes/i386-tbl.h
8068
opcodes/i386-tbl.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user