diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2017-03-09 09:58:46 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2017-03-09 09:59:00 -0800 |
commit | 86fa6981e7487e2c2df4337aa75ed2d93c32eaf2 (patch) | |
tree | 3a2c124ce66bd4de896bcd0fca29dcb3f4f8f094 /gas/config | |
parent | f03265d9cda1f5f8df238efa9b7a20330e5711f1 (diff) | |
download | gdb-86fa6981e7487e2c2df4337aa75ed2d93c32eaf2.zip gdb-86fa6981e7487e2c2df4337aa75ed2d93c32eaf2.tar.gz gdb-86fa6981e7487e2c2df4337aa75ed2d93c32eaf2.tar.bz2 |
X86: Add pseudo prefixes to control encoding
Many x86 instructions have more than one encodings. Assembler picks
the default one, usually the shortest one. Although the ".s", ".d8"
and ".d32" suffixes can be used to swap register operands or specify
displacement size, they aren't very flexible. This patch adds pseudo
prefixes, {xxx}, to control instruction encoding. The available
pseudo prefixes are {disp8}, {disp32}, {load}, {store}, {vex2}, {vex3}
and {evex}. Pseudo prefixes are preferred over the ".s", ".d8" and
".d32" suffixes, which are deprecated.
gas/
* config/tc-i386.c (_i386_insn): Add dir_encoding and
vec_encoding. Remove swap_operand and need_vrex.
(extra_symbol_chars): Add '}'.
(md_begin): Mark '}' with LEX_BEGIN_NAME. Allow '}' in
mnemonic.
(build_vex_prefix): Don't use 2-byte VEX encoding with
{vex3}. Check dir_encoding and load.
(parse_insn): Check pseudo prefixes. Set dir_encoding.
(VEX_check_operands): Likewise.
(match_template): Check dir_encoding and load.
(parse_real_register): Set vec_encoding instead of need_vrex.
(parse_register): Likewise.
* doc/c-i386.texi: Document {disp8}, {disp32}, {load}, {store},
{vex2}, {vex3} and {evex}. Remove ".s", ".d8" and ".d32"
* testsuite/gas/i386/i386.exp: Run pseudos and x86-64-pseudos.
* testsuite/gas/i386/pseudos.d: New file.
* testsuite/gas/i386/pseudos.s: Likewise.
* testsuite/gas/i386/x86-64-pseudos.d: Likewise.
* testsuite/gas/i386/x86-64-pseudos.s: Likewise.
opcodes/
* i386-gen.c (opcode_modifiers): Replace S with Load.
* i386-opc.h (S): Removed.
(Load): New.
(i386_opcode_modifier): Replace s with load.
* i386-opc.tbl: Add {disp8}, {disp32}, {swap}, {vex2}, {vex3}
and {evex}. Replace S with Load.
* i386-tbl.h: Regenerated.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-i386.c | 158 |
1 files changed, 114 insertions, 44 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 7deacad..6250793 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -354,8 +354,13 @@ struct _i386_insn /* Compressed disp8*N attribute. */ unsigned int memshift; - /* Swap operand in encoding. */ - unsigned int swap_operand; + /* Prefer load or store in encoding. */ + enum + { + dir_encoding_default = 0, + dir_encoding_load, + dir_encoding_store + } dir_encoding; /* Prefer 8bit or 32bit displacement in encoding. */ enum @@ -365,6 +370,15 @@ struct _i386_insn disp_encoding_32bit } disp_encoding; + /* How to encode vector instructions. */ + enum + { + vex_encoding_default = 0, + vex_encoding_vex2, + vex_encoding_vex3, + vex_encoding_evex + } vec_encoding; + /* REP prefix. */ const char *rep_prefix; @@ -374,9 +388,6 @@ struct _i386_insn /* Have BND prefix. */ const char *bnd_prefix; - /* Need VREX to support upper 16 registers. */ - int need_vrex; - /* Error message. */ enum i386_error error; }; @@ -403,7 +414,7 @@ static const struct RC_name RC_NamesTable[] = /* List of chars besides those in app.c:symbol_chars that can start an operand. Used to prevent the scrubber eating vital white-space. */ -const char extra_symbol_chars[] = "*%-([{" +const char extra_symbol_chars[] = "*%-([{}" #ifdef LEX_AT "@" #endif @@ -2597,6 +2608,9 @@ md_begin (void) { const char *hash_err; + /* Support pseudo prefixes like {disp32}. */ + lex_type ['{'] = LEX_BEGIN_NAME; + /* Initialize op_hash hash table. */ op_hash = hash_new (); @@ -2678,7 +2692,10 @@ md_begin (void) operand_chars[c] = c; } else if (c == '{' || c == '}') - operand_chars[c] = c; + { + mnemonic_chars[c] = c; + operand_chars[c] = c; + } if (ISALPHA (c) || ISDIGIT (c)) identifier_chars[c] = c; @@ -3144,10 +3161,11 @@ build_vex_prefix (const insn_template *t) /* Use 2-byte VEX prefix by swapping destination and source operand. */ - if (!i.swap_operand + if (i.vec_encoding != vex_encoding_vex3 + && i.dir_encoding == dir_encoding_default && i.operands == i.reg_operands && i.tm.opcode_modifier.vexopcode == VEX0F - && i.tm.opcode_modifier.s + && i.tm.opcode_modifier.load && i.rex == REX_B) { unsigned int xchg = i.operands - 1; @@ -3196,7 +3214,8 @@ build_vex_prefix (const insn_template *t) } /* Use 2-byte VEX prefix if possible. */ - if (i.tm.opcode_modifier.vexopcode == VEX0F + if (i.vec_encoding != vex_encoding_vex3 + && i.tm.opcode_modifier.vexopcode == VEX0F && i.tm.opcode_modifier.vexw != VEXW1 && (i.rex & (REX_W | REX_X | REX_B)) == 0) { @@ -3905,21 +3924,61 @@ parse_insn (char *line, char *mnemonic) current_templates->start->name); return NULL; } - /* Add prefix, checking for repeated prefixes. */ - switch (add_prefix (current_templates->start->base_opcode)) + if (current_templates->start->opcode_length == 0) { - case PREFIX_EXIST: - return NULL; - case PREFIX_REP: - if (current_templates->start->cpu_flags.bitfield.cpuhle) - i.hle_prefix = current_templates->start->name; - else if (current_templates->start->cpu_flags.bitfield.cpumpx) - i.bnd_prefix = current_templates->start->name; - else - i.rep_prefix = current_templates->start->name; - break; - default: - break; + /* Handle pseudo prefixes. */ + switch (current_templates->start->base_opcode) + { + case 0x0: + /* {disp8} */ + i.disp_encoding = disp_encoding_8bit; + break; + case 0x1: + /* {disp32} */ + i.disp_encoding = disp_encoding_32bit; + break; + case 0x2: + /* {load} */ + i.dir_encoding = dir_encoding_load; + break; + case 0x3: + /* {store} */ + i.dir_encoding = dir_encoding_store; + break; + case 0x4: + /* {vex2} */ + i.vec_encoding = vex_encoding_vex2; + break; + case 0x5: + /* {vex3} */ + i.vec_encoding = vex_encoding_vex3; + break; + case 0x6: + /* {evex} */ + i.vec_encoding = vex_encoding_evex; + break; + default: + abort (); + } + } + else + { + /* Add prefix, checking for repeated prefixes. */ + switch (add_prefix (current_templates->start->base_opcode)) + { + case PREFIX_EXIST: + return NULL; + case PREFIX_REP: + if (current_templates->start->cpu_flags.bitfield.cpuhle) + i.hle_prefix = current_templates->start->name; + else if (current_templates->start->cpu_flags.bitfield.cpumpx) + i.bnd_prefix = current_templates->start->name; + else + i.rep_prefix = current_templates->start->name; + break; + default: + break; + } } /* Skip past PREFIX_SEPARATOR and reset token_start. */ token_start = ++l; @@ -3933,7 +3992,7 @@ parse_insn (char *line, char *mnemonic) /* Check if we should swap operand or force 32bit displacement in encoding. */ if (mnem_p - 2 == dot_p && dot_p[1] == 's') - i.swap_operand = 1; + i.dir_encoding = dir_encoding_store; else if (mnem_p - 3 == dot_p && dot_p[1] == 'd' && dot_p[2] == '8') @@ -4721,15 +4780,27 @@ check_VecOperands (const insn_template *t) static int VEX_check_operands (const insn_template *t) { - /* VREX is only valid with EVEX prefix. */ - if (i.need_vrex && !t->opcode_modifier.evex) + if (i.vec_encoding == vex_encoding_evex) { - i.error = invalid_register_operand; - return 1; + /* This instruction must be encoded with EVEX prefix. */ + if (!t->opcode_modifier.evex) + { + i.error = unsupported; + return 1; + } + return 0; } if (!t->opcode_modifier.vex) - return 0; + { + /* This instruction template doesn't have VEX prefix. */ + if (i.vec_encoding != vex_encoding_default) + { + i.error = unsupported; + return 1; + } + return 0; + } /* Only check VEX_Imm4, which must be the first operand. */ if (t->operand_types[0].bitfield.vec_imm4) @@ -4967,20 +5038,17 @@ match_template (char mnem_suffix) && operand_type_equal (&i.types [0], &acc32) && operand_type_equal (&i.types [1], &acc32)) continue; - if (i.swap_operand) - { - /* If we swap operand in encoding, we either match - the next one or reverse direction of operands. */ - if (t->opcode_modifier.s) - continue; - else if (t->opcode_modifier.d) - goto check_reverse; - } + /* If we want store form, we reverse direction of operands. */ + if (i.dir_encoding == dir_encoding_store + && t->opcode_modifier.d) + goto check_reverse; /* Fall through. */ case 3: - /* If we swap operand in encoding, we match the next one. */ - if (i.swap_operand && t->opcode_modifier.s) + /* If we want store form, we skip the current load. */ + if (i.dir_encoding == dir_encoding_store + && i.mem_operands == 0 + && t->opcode_modifier.load) continue; /* Fall through. */ case 4: @@ -9725,11 +9793,13 @@ parse_real_register (char *reg_string, char **end_op) mode. */ if ((r->reg_flags & RegVRex)) { + if (i.vec_encoding == vex_encoding_default) + i.vec_encoding = vex_encoding_evex; + if (!cpu_arch_flags.bitfield.cpuvrex + || i.vec_encoding != vex_encoding_evex || flag_code != CODE_64BIT) return (const reg_entry *) NULL; - - i.need_vrex = 1; } if (((r->reg_flags & (RegRex64 | RegRex)) @@ -9774,7 +9844,7 @@ parse_register (char *reg_string, char **end_op) && (valueT) e->X_add_number < i386_regtab_size); r = i386_regtab + e->X_add_number; if ((r->reg_flags & RegVRex)) - i.need_vrex = 1; + i.vec_encoding = vex_encoding_evex; *end_op = input_line_pointer; } *input_line_pointer = c; |