aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2023-11-24 09:55:51 +0100
committerJan Beulich <jbeulich@suse.com>2023-11-24 09:55:51 +0100
commitd3b01414b935be5c5d5f37e5df6b6767e9c68d25 (patch)
treee1fd63e5d0edd4a97cb6f61fadbdcaf2d8bcd8f8 /gas/config/tc-i386.c
parent39bb3ade816faf42ec34cc7ca962ad350cb4d16a (diff)
downloadgdb-d3b01414b935be5c5d5f37e5df6b6767e9c68d25.zip
gdb-d3b01414b935be5c5d5f37e5df6b6767e9c68d25.tar.gz
gdb-d3b01414b935be5c5d5f37e5df6b6767e9c68d25.tar.bz2
x86: shrink opcode sets table
Have i386-gen produce merely the offsets into i386_optab[]. Besides allowing to shrink the table even on 32-bit builds, this results in removing a level of indirection from the frequently accessed current_templates, in return for adding a level of indirection when looking up mnemonics (commonly happening just once per insn). Plus for PIE builds of gas it also reduces the number of relocations by about two thousand. Finally a somewhat ugly static variable can also be eliminated from i386_displacement().
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c192
1 files changed, 96 insertions, 96 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 71e0c4d..b1cd0e4 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -569,7 +569,7 @@ static char *save_stack_p;
static i386_insn i;
/* Possible templates for current insn. */
-static const templates *current_templates;
+static templates current_templates;
/* Per instruction expressionS buffers: max displacements & immediates. */
static expressionS disp_expressions[MAX_MEMORY_OPERANDS];
@@ -3101,6 +3101,20 @@ i386_mach (void)
#include "opcodes/i386-tbl.h"
+static void
+op_lookup (const char *mnemonic)
+{
+ i386_op_off_t *pos = str_hash_find (op_hash, mnemonic);
+
+ if (pos != NULL)
+ {
+ current_templates.start = &i386_optab[pos[0]];
+ current_templates.end = &i386_optab[pos[1]];
+ }
+ else
+ current_templates.end = current_templates.start = NULL;
+}
+
void
md_begin (void)
{
@@ -3111,16 +3125,12 @@ md_begin (void)
op_hash = str_htab_create ();
{
- const insn_template *const *sets = i386_op_sets;
- const insn_template *const *end = sets + ARRAY_SIZE (i386_op_sets) - 1;
-
- /* Type checks to compensate for the conversion through void * which
- occurs during hash table insertion / lookup. */
- (void) sizeof (sets == &current_templates->start);
- (void) sizeof (end == &current_templates->end);
- for (; sets < end; ++sets)
- if (str_hash_insert (op_hash, insn_name (*sets), sets, 0))
- as_fatal (_("duplicate %s"), insn_name (*sets));
+ const i386_op_off_t *cur = i386_op_sets;
+ const i386_op_off_t *end = cur + ARRAY_SIZE (i386_op_sets) - 1;
+
+ for (; cur < end; ++cur)
+ if (str_hash_insert (op_hash, insn_name (&i386_optab[*cur]), cur, 0))
+ as_fatal (_("duplicate %s"), insn_name (&i386_optab[*cur]));
}
/* Initialize reg_hash hash table. */
@@ -5121,7 +5131,7 @@ md_assemble (char *line)
const insn_template *t;
/* Initialize globals. */
- current_templates = NULL;
+ current_templates.end = current_templates.start = NULL;
retry:
init_globals ();
@@ -5136,8 +5146,8 @@ md_assemble (char *line)
goto match_error;
if (i.error != no_error)
{
- gas_assert (current_templates != NULL);
- if (may_need_pass2 (current_templates->start) && !i.suffix)
+ gas_assert (current_templates.start != NULL);
+ if (may_need_pass2 (current_templates.start) && !i.suffix)
goto no_match;
/* No point in trying a 2nd pass - it'll only find the same suffix
again. */
@@ -5146,7 +5156,7 @@ md_assemble (char *line)
}
return;
}
- t = current_templates->start;
+ t = current_templates.start;
if (may_need_pass2 (t))
{
/* Make a copy of the full line in case we need to retry. */
@@ -5204,7 +5214,7 @@ md_assemble (char *line)
32-bit immediate and 64-bit operand size use sign-extended
immediates (imm32s). Therefore these insns are special-cased, bypassing
the normal handling of immediates here. */
- if (is_cpu(current_templates->start, CpuUSER_MSR))
+ if (is_cpu(current_templates.start, CpuUSER_MSR))
{
for (j = 0; j < i.operands; j++)
{
@@ -5233,7 +5243,7 @@ md_assemble (char *line)
copy = NULL;
no_match:
pass1_err = i.error;
- pass1_mnem = insn_name (current_templates->start);
+ pass1_mnem = insn_name (current_templates.start);
goto retry;
}
@@ -5276,11 +5286,11 @@ md_assemble (char *line)
break;
case unsupported:
as_bad (_("unsupported instruction `%s'"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
return;
case unsupported_on_arch:
as_bad (_("`%s' is not supported on `%s%s'"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start),
cpu_arch_name ? cpu_arch_name : default_arch,
cpu_sub_arch_name ? cpu_sub_arch_name : "");
return;
@@ -5289,21 +5299,21 @@ md_assemble (char *line)
{
if (flag_code == CODE_64BIT)
as_bad (_("`%s%c' is not supported in 64-bit mode"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start),
mnem_suffix);
else
as_bad (_("`%s%c' is only supported in 64-bit mode"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start),
mnem_suffix);
}
else
{
if (flag_code == CODE_64BIT)
as_bad (_("`%s' is not supported in 64-bit mode"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
else
as_bad (_("`%s' is only supported in 64-bit mode"),
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
}
return;
case no_vex_encoding:
@@ -5350,14 +5360,14 @@ md_assemble (char *line)
break;
case unsupported_vector_size:
as_bad (_("vector size above %u required for `%s'"), 128u << vector_size,
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
return;
case internal_error:
err_msg = _("internal error");
break;
}
as_bad (_("%s for `%s'"), err_msg,
- pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+ pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
return;
}
@@ -5710,7 +5720,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
{
const char *l = line, *token_start = l;
char *mnem_p;
- bool pass1 = !current_templates;
+ bool pass1 = !current_templates.start;
int supported;
const insn_template *t;
char *dot_p = NULL;
@@ -5771,47 +5781,47 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
}
/* Look up instruction (or prefix) via hash table. */
- current_templates = (const templates *) str_hash_find (op_hash, mnemonic);
+ op_lookup (mnemonic);
if (*l != END_OF_INSN
&& (!is_space_char (*l) || l[1] != END_OF_INSN)
- && current_templates
- && current_templates->start->opcode_modifier.isprefix)
+ && current_templates.start
+ && current_templates.start->opcode_modifier.isprefix)
{
- supported = cpu_flags_match (current_templates->start);
+ supported = cpu_flags_match (current_templates.start);
if (!(supported & CPU_FLAGS_64BIT_MATCH))
{
as_bad ((flag_code != CODE_64BIT
? _("`%s' is only supported in 64-bit mode")
: _("`%s' is not supported in 64-bit mode")),
- insn_name (current_templates->start));
+ insn_name (current_templates.start));
return NULL;
}
if (supported != CPU_FLAGS_PERFECT_MATCH)
{
as_bad (_("`%s' is not supported on `%s%s'"),
- insn_name (current_templates->start),
+ insn_name (current_templates.start),
cpu_arch_name ? cpu_arch_name : default_arch,
cpu_sub_arch_name ? cpu_sub_arch_name : "");
return NULL;
}
/* If we are in 16-bit mode, do not allow addr16 or data16.
Similarly, in 32-bit mode, do not allow addr32 or data32. */
- if ((current_templates->start->opcode_modifier.size == SIZE16
- || current_templates->start->opcode_modifier.size == SIZE32)
+ if ((current_templates.start->opcode_modifier.size == SIZE16
+ || current_templates.start->opcode_modifier.size == SIZE32)
&& flag_code != CODE_64BIT
- && ((current_templates->start->opcode_modifier.size == SIZE32)
+ && ((current_templates.start->opcode_modifier.size == SIZE32)
^ (flag_code == CODE_16BIT)))
{
as_bad (_("redundant %s prefix"),
- insn_name (current_templates->start));
+ insn_name (current_templates.start));
return NULL;
}
- if (current_templates->start->base_opcode == PSEUDO_PREFIX)
+ if (current_templates.start->base_opcode == PSEUDO_PREFIX)
{
/* Handle pseudo prefixes. */
- switch (current_templates->start->extension_opcode)
+ switch (current_templates.start->extension_opcode)
{
case Prefix_Disp8:
/* {disp8} */
@@ -5860,21 +5870,21 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
else
{
/* Add prefix, checking for repeated prefixes. */
- switch (add_prefix (current_templates->start->base_opcode))
+ switch (add_prefix (current_templates.start->base_opcode))
{
case PREFIX_EXIST:
return NULL;
case PREFIX_DS:
- if (is_cpu (current_templates->start, CpuIBT))
- i.notrack_prefix = insn_name (current_templates->start);
+ if (is_cpu (current_templates.start, CpuIBT))
+ i.notrack_prefix = insn_name (current_templates.start);
break;
case PREFIX_REP:
- if (is_cpu (current_templates->start, CpuHLE))
- i.hle_prefix = insn_name (current_templates->start);
- else if (is_cpu (current_templates->start, CpuMPX))
- i.bnd_prefix = insn_name (current_templates->start);
+ if (is_cpu (current_templates.start, CpuHLE))
+ i.hle_prefix = insn_name (current_templates.start);
+ else if (is_cpu (current_templates.start, CpuMPX))
+ i.bnd_prefix = insn_name (current_templates.start);
else
- i.rep_prefix = insn_name (current_templates->start);
+ i.rep_prefix = insn_name (current_templates.start);
break;
default:
break;
@@ -5890,7 +5900,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
if (prefix_only)
return token_start;
- if (!current_templates)
+ if (!current_templates.start)
{
/* Deprecated functionality (new code should use pseudo-prefixes instead):
Check if we should swap operand or force 32bit displacement in
@@ -5926,12 +5936,12 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
goto check_suffix;
mnem_p = dot_p;
*dot_p = '\0';
- current_templates = (const templates *) str_hash_find (op_hash, mnemonic);
+ op_lookup (mnemonic);
}
- if (!current_templates || !pass1)
+ if (!current_templates.start || !pass1)
{
- current_templates = NULL;
+ current_templates.start = NULL;
check_suffix:
if (mnem_p > mnemonic)
@@ -5948,8 +5958,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
case QWORD_MNEM_SUFFIX:
i.suffix = mnem_p[-1];
mnem_p[-1] = '\0';
- current_templates
- = (const templates *) str_hash_find (op_hash, mnemonic);
+ op_lookup (mnemonic);
break;
case SHORT_MNEM_SUFFIX:
case LONG_MNEM_SUFFIX:
@@ -5957,8 +5966,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
{
i.suffix = mnem_p[-1];
mnem_p[-1] = '\0';
- current_templates
- = (const templates *) str_hash_find (op_hash, mnemonic);
+ op_lookup (mnemonic);
}
break;
@@ -5971,8 +5979,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
else
i.suffix = LONG_MNEM_SUFFIX;
mnem_p[-1] = '\0';
- current_templates
- = (const templates *) str_hash_find (op_hash, mnemonic);
+ op_lookup (mnemonic);
}
/* For compatibility reasons accept MOVSD and CMPSD without
operands even in AT&T mode. */
@@ -5980,12 +5987,11 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
|| (is_space_char (*l) && l[1] == END_OF_INSN))
{
mnem_p[-1] = '\0';
- current_templates
- = (const templates *) str_hash_find (op_hash, mnemonic);
- if (current_templates != NULL
+ op_lookup (mnemonic);
+ if (current_templates.start != NULL
/* MOVS or CMPS */
- && (current_templates->start->base_opcode | 2) == 0xa6
- && current_templates->start->opcode_space
+ && (current_templates.start->base_opcode | 2) == 0xa6
+ && current_templates.start->opcode_space
== SPACE_BASE
&& mnem_p[-2] == 's')
{
@@ -5995,7 +6001,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
}
else
{
- current_templates = NULL;
+ current_templates.start = NULL;
mnem_p[-1] = 'd';
}
}
@@ -6003,7 +6009,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
}
}
- if (!current_templates)
+ if (!current_templates.start)
{
if (pass1)
as_bad (_("no such instruction: `%s'"), token_start);
@@ -6011,8 +6017,8 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
}
}
- if (current_templates->start->opcode_modifier.jump == JUMP
- || current_templates->start->opcode_modifier.jump == JUMP_BYTE)
+ if (current_templates.start->opcode_modifier.jump == JUMP
+ || current_templates.start->opcode_modifier.jump == JUMP_BYTE)
{
/* Check for a branch hint. We allow ",pt" and ",pn" for
predict taken and predict not taken respectively.
@@ -6046,7 +6052,7 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
/* Check if instruction is supported on specified architecture. */
supported = 0;
- for (t = current_templates->start; t < current_templates->end; ++t)
+ for (t = current_templates.start; t < current_templates.end; ++t)
{
supported |= cpu_flags_match (t);
@@ -6313,7 +6319,7 @@ optimize_imm (void)
/* A more generic (but also more involved) way of dealing
with the special case(s) would be to go look for
DefaultSize attributes on any of the templates. */
- && current_templates->start->mnem_off != MN_push))
+ && current_templates.start->mnem_off != MN_push))
guess_suffix = LONG_MNEM_SUFFIX;
for (op = i.operands; --op >= 0;)
@@ -6387,7 +6393,7 @@ optimize_imm (void)
than those matching the insn suffix. */
{
i386_operand_type mask, allowed;
- const insn_template *t = current_templates->start;
+ const insn_template *t = current_templates.start;
operand_type_set (&mask, 0);
switch (guess_suffix)
@@ -6410,7 +6416,7 @@ optimize_imm (void)
}
allowed = operand_type_and (t->operand_types[op], mask);
- while (++t < current_templates->end)
+ while (++t < current_templates.end)
{
allowed = operand_type_or (allowed, t->operand_types[op]);
allowed = operand_type_and (allowed, mask);
@@ -7034,7 +7040,7 @@ match_template (char mnem_suffix)
found_reverse_match = 0;
addr_prefix_disp = -1;
- for (t = current_templates->start; t < current_templates->end; t++)
+ for (t = current_templates.start; t < current_templates.end; t++)
{
addr_prefix_disp = -1;
found_reverse_match = 0;
@@ -7483,11 +7489,11 @@ match_template (char mnem_suffix)
Vxy / Exy constructs: There are 3 suffix-less EVEX forms, the latter
two of which may fall back to their two corresponding VEX forms. */
j = t->mnem_off != MN_vcvtneps2bf16 ? 1 : 2;
- if ((t == current_templates->start || j > 1)
+ if ((t == current_templates.start || j > 1)
&& t->opcode_modifier.disp8memshift
&& !t->opcode_modifier.vex
&& !need_evex_encoding ()
- && t + j < current_templates->end
+ && t + j < current_templates.end
&& t[j].opcode_modifier.vex)
{
i386_cpu_flags cpu;
@@ -7515,7 +7521,7 @@ match_template (char mnem_suffix)
#undef progress
- if (t == current_templates->end)
+ if (t == current_templates.end)
{
/* We found no match. */
i.error = specific_error;
@@ -10942,7 +10948,6 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
unsigned int j;
valueT val;
bool vex = false, xop = false, evex = false;
- static const templates tt = { &i.tm, &i.tm + 1 };
init_globals ();
@@ -10960,7 +10965,8 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
}
line += end - line;
- current_templates = &tt;
+ current_templates.start = &i.tm;
+ current_templates.end = &i.tm + 1;
i.tm.mnem_off = MN__insn;
i.tm.extension_opcode = None;
@@ -12177,8 +12183,8 @@ i386_displacement (char *disp_start, char *disp_end)
operand_type_set (&bigdisp, 0);
if (i.jumpabsolute
|| i.types[this_operand].bitfield.baseindex
- || (current_templates->start->opcode_modifier.jump != JUMP
- && current_templates->start->opcode_modifier.jump != JUMP_DWORD))
+ || (current_templates.start->opcode_modifier.jump != JUMP
+ && current_templates.start->opcode_modifier.jump != JUMP_DWORD))
{
i386_addressing_mode ();
override = (i.prefix[ADDR_PREFIX] != 0);
@@ -12199,24 +12205,18 @@ i386_displacement (char *disp_start, char *disp_end)
dependent upon data size, but is never dependent upon address size.
Also make sure to not unintentionally match against a non-PC-relative
branch template. */
- static templates aux_templates;
- const insn_template *t = current_templates->start;
+ const insn_template *t = current_templates.start;
bool has_intel64 = false;
- aux_templates.start = t;
- while (++t < current_templates->end)
+ while (++t < current_templates.end)
{
if (t->opcode_modifier.jump
- != current_templates->start->opcode_modifier.jump)
+ != current_templates.start->opcode_modifier.jump)
break;
if ((t->opcode_modifier.isa64 >= INTEL64))
has_intel64 = true;
}
- if (t < current_templates->end)
- {
- aux_templates.end = t;
- current_templates = &aux_templates;
- }
+ current_templates.end = t;
override = (i.prefix[DATA_PREFIX] != 0);
if (flag_code == CODE_64BIT)
@@ -12389,7 +12389,7 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
}
#endif
- else if (current_templates->start->opcode_modifier.jump == JUMP_BYTE)
+ else if (current_templates.start->opcode_modifier.jump == JUMP_BYTE)
i.types[this_operand].bitfield.disp8 = 1;
/* Check if this is a displacement only operand. */
@@ -12413,7 +12413,7 @@ i386_addressing_mode (void)
if (i.prefix[ADDR_PREFIX])
addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
else if (flag_code == CODE_16BIT
- && is_cpu (current_templates->start, CpuMPX)
+ && is_cpu (current_templates.start, CpuMPX)
/* Avoid replacing the "16-bit addressing not allowed" diagnostic
from md_assemble() by "is not a valid base/index expression"
when there is a base and/or index. */
@@ -12486,7 +12486,7 @@ i386_index_check (const char *operand_string)
{
const char *kind = "base/index";
enum flag_code addr_mode = i386_addressing_mode ();
- const insn_template *t = current_templates->end - 1;
+ const insn_template *t = current_templates.end - 1;
if (t->opcode_modifier.isstring)
{
@@ -12553,7 +12553,7 @@ i386_index_check (const char *operand_string)
}
else
{
- t = current_templates->start;
+ t = current_templates.start;
if (addr_mode != CODE_16BIT)
{
@@ -12678,7 +12678,7 @@ i386_att_operand (char *operand_string)
/* We check for an absolute prefix (differentiating,
for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
if (*op_string == ABSOLUTE_PREFIX
- && current_templates->start->opcode_modifier.jump)
+ && current_templates.start->opcode_modifier.jump)
{
++op_string;
if (is_space_char (*op_string))
@@ -12710,7 +12710,7 @@ i386_att_operand (char *operand_string)
/* Handle case of %es:*foo. */
if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX
- && current_templates->start->opcode_modifier.jump)
+ && current_templates.start->opcode_modifier.jump)
{
++op_string;
if (is_space_char (*op_string))
@@ -12767,7 +12767,7 @@ i386_att_operand (char *operand_string)
if (i.rounding.type == RC_NamesTable[j].type)
break;
as_bad (_("`%s': misplaced `{%s}'"),
- insn_name (current_templates->start), RC_NamesTable[j].name);
+ insn_name (current_templates.start), RC_NamesTable[j].name);
return 0;
}
}
@@ -12789,7 +12789,7 @@ i386_att_operand (char *operand_string)
if (i.rounding.type != rc_none)
{
as_bad (_("`%s': RC/SAE operand must follow immediate operands"),
- insn_name (current_templates->start));
+ insn_name (current_templates.start));
return 0;
}
}
@@ -12802,7 +12802,7 @@ i386_att_operand (char *operand_string)
&& i.op[0].regs->reg_type.bitfield.class != Reg))
{
as_bad (_("`%s': misplaced `%s'"),
- insn_name (current_templates->start), operand_string);
+ insn_name (current_templates.start), operand_string);
return 0;
}
}