[PATCH 3/4] x86: helper function + variables for templates' ->operand_types[] accesses
Jan Beulich <[email protected]> Fri, 24 Jul 2026 12:14:49 +0200
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
This again is to reduce the churn by a subsequent change, where
.operand_types[] is to no longer be directly embedded in the templates. A
few instances cannot sensibly changed following the pattern used.
In match_template() one use to be replaced is covered by slightly re-ordering
code there, to then use an existing local variable.
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2548,6 +2548,12 @@ operand_type_check (i386_operand_type t,
return 0;
}
+static INLINE const i386_operand_type *
+get_operand_types (const insn_template *t)
+{
+ return t->operand_types;
+}
+
/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit size
between operand GIVEN and operand WANTED for instruction template T. */
@@ -2555,20 +2561,22 @@ static INLINE int
match_operand_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
+ const i386_operand_type *t_types = get_operand_types (t);
+
return !((i.types[given].bitfield.byte
- && !t->operand_types[wanted].bitfield.byte)
+ && !t_types[wanted].bitfield.byte)
|| (i.types[given].bitfield.word
- && !t->operand_types[wanted].bitfield.word)
+ && !t_types[wanted].bitfield.word)
|| (i.types[given].bitfield.dword
- && !t->operand_types[wanted].bitfield.dword)
+ && !t_types[wanted].bitfield.dword)
|| (i.types[given].bitfield.qword
- && (!t->operand_types[wanted].bitfield.qword
+ && (!t_types[wanted].bitfield.qword
/* Don't allow 64-bit (memory) operands outside of 64-bit
mode, when they're used where a 64-bit GPR could also
be used. Checking is needed for Intel Syntax only. */
|| (intel_syntax
&& flag_code != CODE_64BIT
- && (t->operand_types[wanted].bitfield.class == Reg
+ && (t_types[wanted].bitfield.class == Reg
|| t->opcode_modifier.isstring)))));
}
@@ -2576,28 +2584,28 @@ match_operand_size (const insn_template
between operand GIVEN and operand WANTED for instruction template T. */
static INLINE int
-match_fp_size (const insn_template *t, unsigned int wanted,
+match_fp_size (const i386_operand_type *t_types, unsigned int wanted,
unsigned int given)
{
return !i.types[given].bitfield.tbyte
- || t->operand_types[wanted].bitfield.tbyte;
+ || t_types[wanted].bitfield.tbyte;
}
/* Return 1 if there is no conflict in SIMD register between operand
GIVEN and operand WANTED for instruction template T. */
static INLINE int
-match_simd_size (const insn_template *t, unsigned int wanted,
+match_simd_size (const i386_operand_type *t_types, unsigned int wanted,
unsigned int given)
{
return !((i.types[given].bitfield.xmmword
- && !t->operand_types[wanted].bitfield.xmmword)
+ && !t_types[wanted].bitfield.xmmword)
|| (i.types[given].bitfield.ymmword
- && !t->operand_types[wanted].bitfield.ymmword)
+ && !t_types[wanted].bitfield.ymmword)
|| (i.types[given].bitfield.zmmword
- && !t->operand_types[wanted].bitfield.zmmword)
+ && !t_types[wanted].bitfield.zmmword)
|| (i.types[given].bitfield.tmmword
- && !t->operand_types[wanted].bitfield.tmmword));
+ && !t_types[wanted].bitfield.tmmword));
}
/* Return 1 if there is no conflict in any size between operand GIVEN
@@ -2607,29 +2615,31 @@ static INLINE int
match_mem_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
+ const i386_operand_type *t_types = get_operand_types (t);
+
return (match_operand_size (t, wanted, given)
&& (!i.types[given].bitfield.tbyte
- || t->operand_types[wanted].bitfield.tbyte)
+ || t_types[wanted].bitfield.tbyte)
&& !((i.types[given].bitfield.unspecified
&& !i.broadcast.type
&& !i.broadcast.bytes
- && !t->operand_types[wanted].bitfield.unspecified)
+ && !t_types[wanted].bitfield.unspecified)
|| (i.types[given].bitfield.fword
- && !t->operand_types[wanted].bitfield.fword)
+ && !t_types[wanted].bitfield.fword)
/* For scalar opcode templates to allow register and memory
operands at the same time, some special casing is needed
here. Also for v{,p}broadcast*, {,v}pmov{s,z}*, and
down-conversion vpmov*. */
- || ((t->operand_types[wanted].bitfield.class == RegSIMD
- && t->operand_types[wanted].bitfield.byte
- + t->operand_types[wanted].bitfield.word
- + t->operand_types[wanted].bitfield.dword
- + t->operand_types[wanted].bitfield.qword
+ || ((t_types[wanted].bitfield.class == RegSIMD
+ && t_types[wanted].bitfield.byte
+ + t_types[wanted].bitfield.word
+ + t_types[wanted].bitfield.dword
+ + t_types[wanted].bitfield.qword
> !!t->opcode_modifier.broadcast)
? (i.types[given].bitfield.xmmword
|| i.types[given].bitfield.ymmword
|| i.types[given].bitfield.zmmword)
- : !match_simd_size(t, wanted, given))));
+ : !match_simd_size(t_types, wanted, given))));
}
/* Return value has MATCH_STRAIGHT set if there is no size conflict on any
@@ -2643,6 +2653,7 @@ match_mem_size (const insn_template *t,
static INLINE unsigned int
operand_size_match (const insn_template *t)
{
+ const i386_operand_type *t_types = get_operand_types (t);
unsigned int j, match = MATCH_STRAIGHT;
/* Don't check non-absolute jump instructions. */
@@ -2657,8 +2668,8 @@ operand_size_match (const insn_template
first template if sign-extended 8-bit immediate operand should
be excluded. */
if (pp.no_imm8s
- && !t->operand_types[j].bitfield.imm8
- && t->operand_types[j].bitfield.imm8s)
+ && !t_types[j].bitfield.imm8
+ && t_types[j].bitfield.imm8s)
{
gas_assert (!t->opcode_modifier.d);
return 0;
@@ -2668,12 +2679,12 @@ operand_size_match (const insn_template
for (; j < i.operands; j++)
{
if (i.types[j].bitfield.class == Reg
- && (t->operand_types[j].bitfield.class == Reg
- || (t->operand_types[j].bitfield.instance == Accum
- && (t->operand_types[j].bitfield.byte
- || t->operand_types[j].bitfield.word
- || t->operand_types[j].bitfield.dword
- || t->operand_types[j].bitfield.qword)))
+ && (t_types[j].bitfield.class == Reg
+ || (t_types[j].bitfield.instance == Accum
+ && (t_types[j].bitfield.byte
+ || t_types[j].bitfield.word
+ || t_types[j].bitfield.dword
+ || t_types[j].bitfield.qword)))
&& !match_operand_size (t, j, j))
{
match = 0;
@@ -2681,28 +2692,28 @@ operand_size_match (const insn_template
}
if (i.types[j].bitfield.class == RegFP
- && (t->operand_types[j].bitfield.class == RegFP
- || (t->operand_types[j].bitfield.instance == Accum
- && t->operand_types[j].bitfield.tbyte))
- && !match_fp_size (t, j, j))
+ && (t_types[j].bitfield.class == RegFP
+ || (t_types[j].bitfield.instance == Accum
+ && t_types[j].bitfield.tbyte))
+ && !match_fp_size (t_types, j, j))
{
match = 0;
break;
}
if (i.types[j].bitfield.class == RegSIMD
- && (t->operand_types[j].bitfield.class == RegSIMD
- || (t->operand_types[j].bitfield.instance == Accum
+ && (t_types[j].bitfield.class == RegSIMD
+ || (t_types[j].bitfield.instance == Accum
/* Note: %ymm0, %zmm0, and %tmm0 aren't marked Accum. */
- && t->operand_types[j].bitfield.xmmword))
- && !match_simd_size (t, j, j))
+ && t_types[j].bitfield.xmmword))
+ && !match_simd_size (t_types, j, j))
{
match = 0;
break;
}
if ((i.flags[j] & Operand_Mem)
- && operand_type_check (t->operand_types[j], anymem)
+ && operand_type_check (t_types[j], anymem)
&& t->opcode_modifier.operandconstraint != ANY_SIZE
&& !match_mem_size (t, j, j))
{
@@ -2729,32 +2740,32 @@ operand_size_match (const insn_template
given = j < 2 ? 1 - j : j;
if (i.types[given].bitfield.class == Reg
- && (t->operand_types[j].bitfield.class == Reg
- || (t->operand_types[j].bitfield.instance == Accum
- && (t->operand_types[j].bitfield.byte
- || t->operand_types[j].bitfield.word
- || t->operand_types[j].bitfield.dword
- || t->operand_types[j].bitfield.qword
- || t->operand_types[j].bitfield.tbyte)))
+ && (t_types[j].bitfield.class == Reg
+ || (t_types[j].bitfield.instance == Accum
+ && (t_types[j].bitfield.byte
+ || t_types[j].bitfield.word
+ || t_types[j].bitfield.dword
+ || t_types[j].bitfield.qword
+ || t_types[j].bitfield.tbyte)))
&& !match_operand_size (t, j, given))
return match;
if (i.types[given].bitfield.class == RegFP
- && (t->operand_types[j].bitfield.class == RegFP
- || (t->operand_types[j].bitfield.instance == Accum
- && t->operand_types[j].bitfield.tbyte))
- && !match_fp_size (t, j, given))
+ && (t_types[j].bitfield.class == RegFP
+ || (t_types[j].bitfield.instance == Accum
+ && t_types[j].bitfield.tbyte))
+ && !match_fp_size (t_types, j, given))
return match;
/* No need to check for Accum here: There are no such templates with D
set. */
if (i.types[given].bitfield.class == RegSIMD
- && t->operand_types[j].bitfield.class == RegSIMD
- && !match_simd_size (t, j, given))
+ && t_types[j].bitfield.class == RegSIMD
+ && !match_simd_size (t_types, j, given))
return match;
if ((i.flags[given] & Operand_Mem)
- && operand_type_check (t->operand_types[j], anymem)
+ && operand_type_check (t_types[j], anymem)
&& !match_mem_size (t, j, given))
return match;
}
@@ -3866,10 +3877,11 @@ pte (insn_template *t)
if (t->opcode_modifier.w)
fprintf (stdout, "W");
fprintf (stdout, "\n");
+ const i386_operand_type *t_types = get_operand_types (t);
for (j = 0; j < t->operands; j++)
{
fprintf (stdout, " #%d type ", j + 1);
- pt (t->operand_types[j]);
+ pt (t_types[j]);
fprintf (stdout, "\n");
}
}
@@ -4239,8 +4251,9 @@ install_template (const insn_template *t
i.tm = *t;
+ const i386_operand_type *t_types = get_operand_types (t);
for (l = 0; l < t->operands; ++l)
- i.tm_types[l] = t->operand_types[l];
+ i.tm_types[l] = t_types[l];
/* Dual VEX/EVEX templates need stripping one of the possible variants. */
if (t->opcode_modifier.vex && t->opcode_modifier.evex)
@@ -4500,6 +4513,7 @@ static unsigned int
get_broadcast_bytes (const insn_template *t, bool diag)
{
unsigned int op, bytes;
+ const i386_operand_type *t_types = get_operand_types (t);
const i386_operand_type *types;
if (i.broadcast.type)
@@ -4508,7 +4522,7 @@ get_broadcast_bytes (const insn_template
gas_assert (intel_syntax);
for (op = 0; op < t->operands; ++op)
- if (t->operand_types[op].bitfield.baseindex)
+ if (t_types[op].bitfield.baseindex)
break;
gas_assert (op < t->operands);
@@ -4517,23 +4531,23 @@ get_broadcast_bytes (const insn_template
switch (i.broadcast.bytes)
{
case 1:
- if (t->operand_types[op].bitfield.word)
+ if (t_types[op].bitfield.word)
return 2;
/* Fall through. */
case 2:
- if (t->operand_types[op].bitfield.dword)
+ if (t_types[op].bitfield.dword)
return 4;
/* Fall through. */
case 4:
- if (t->operand_types[op].bitfield.qword)
+ if (t_types[op].bitfield.qword)
return 8;
/* Fall through. */
case 8:
- if (t->operand_types[op].bitfield.xmmword)
+ if (t_types[op].bitfield.xmmword)
return 16;
- if (t->operand_types[op].bitfield.ymmword)
+ if (t_types[op].bitfield.ymmword)
return 32;
- if (t->operand_types[op].bitfield.zmmword)
+ if (t_types[op].bitfield.zmmword)
return 64;
/* Fall through. */
default:
@@ -4542,15 +4556,15 @@ get_broadcast_bytes (const insn_template
gas_assert (op + 1 < t->operands);
- if (t->operand_types[op + 1].bitfield.xmmword
- + t->operand_types[op + 1].bitfield.ymmword
- + t->operand_types[op + 1].bitfield.zmmword > 1)
+ if (t_types[op + 1].bitfield.xmmword
+ + t_types[op + 1].bitfield.ymmword
+ + t_types[op + 1].bitfield.zmmword > 1)
{
types = &i.types[op + 1];
diag = false;
}
else /* Ambiguous - guess with a preference to non-AVX512VL forms. */
- types = &t->operand_types[op];
+ types = &t_types[op];
if (types->bitfield.zmmword)
bytes = 64;
@@ -6877,7 +6891,7 @@ static INLINE bool may_need_pass2 (const
{
return t->opcode_modifier.sse2avx
/* Note that all SSE2AVX templates have at least one operand. */
- ? t->operand_types[t->operands - 1].bitfield.class == RegSIMD
+ ? get_operand_types (t)[t->operands - 1].bitfield.class == RegSIMD
: (t->opcode_space == SPACE_0F
&& (t->base_opcode | 1) == 0xbf)
|| (t->opcode_space == SPACE_BASE
@@ -7525,6 +7539,8 @@ i386_assemble (char *line)
free (xstrdup_copy);
+ const i386_operand_type *t_types = get_operand_types (t);
+
if (sse_check != check_none
/* The opcode space check isn't strictly needed; it's there only to
bypass the logic below when easily possible. */
@@ -7538,9 +7554,9 @@ i386_assemble (char *line)
for (j = 0; j < t->operands; ++j)
{
- if (t->operand_types[j].bitfield.class == RegMMX)
+ if (t_types[j].bitfield.class == RegMMX)
break;
- if (t->operand_types[j].bitfield.class == RegSIMD)
+ if (t_types[j].bitfield.class == RegSIMD)
simd = true;
}
@@ -8654,10 +8670,10 @@ optimize_imm (void)
break;
}
- allowed = operand_type_and (t->operand_types[op], mask);
+ allowed = operand_type_and (get_operand_types (t)[op], mask);
while (++t < current_templates.end)
{
- allowed = operand_type_or (allowed, t->operand_types[op]);
+ allowed = operand_type_or (allowed, get_operand_types (t)[op]);
allowed = operand_type_and (allowed, mask);
}
@@ -8803,6 +8819,7 @@ check_VecOperands (const insn_template *
{
unsigned int op;
i386_cpu_flags cpu;
+ const i386_operand_type *t_types = get_operand_types (t);
/* Templates allowing for ZMMword as well as YMMword and/or XMMword for
any one operand are implicity requiring AVX512VL support if the actual
@@ -8822,7 +8839,7 @@ check_VecOperands (const insn_template *
{
for (op = 0; op < t->operands; ++op)
{
- if (t->operand_types[op].bitfield.zmmword
+ if (t_types[op].bitfield.zmmword
&& (i.types[op].bitfield.ymmword
|| i.types[op].bitfield.xmmword))
{
@@ -8839,7 +8856,7 @@ check_VecOperands (const insn_template *
{
for (op = 0; op < t->operands; ++op)
{
- if (t->operand_types[op].bitfield.xmmword
+ if (t_types[op].bitfield.xmmword
&& i.types[op].bitfield.ymmword)
{
i.error = operand_size_mismatch;
@@ -8931,7 +8948,7 @@ check_VecOperands (const insn_template *
/* For AMX instructions with 3 TMM register operands, all operands
must be distinct. */
if (i.reg_operands == 3
- && t->operand_types[0].bitfield.tmmword
+ && t_types[0].bitfield.tmmword
&& (i.op[0].regs == i.op[1].regs
|| i.op[0].regs == i.op[2].regs
|| i.op[1].regs == i.op[2].regs))
@@ -9006,12 +9023,12 @@ check_VecOperands (const insn_template *
goto bad_broadcast;
}
- overlap = operand_type_and (type, t->operand_types[op]);
- if (t->operand_types[op].bitfield.class == RegSIMD
- && t->operand_types[op].bitfield.byte
- + t->operand_types[op].bitfield.word
- + t->operand_types[op].bitfield.dword
- + t->operand_types[op].bitfield.qword > 1)
+ overlap = operand_type_and (type, t_types[op]);
+ if (t_types[op].bitfield.class == RegSIMD
+ && t_types[op].bitfield.byte
+ + t_types[op].bitfield.word
+ + t_types[op].bitfield.dword
+ + t_types[op].bitfield.qword > 1)
{
overlap.bitfield.xmmword = 0;
overlap.bitfield.ymmword = 0;
@@ -9029,9 +9046,9 @@ check_VecOperands (const insn_template *
{
if (j != op
&& !operand_type_register_match(i.types[j],
- t->operand_types[j],
+ t_types[j],
type,
- t->operand_types[op]))
+ t_types[op]))
goto bad_broadcast;
}
}
@@ -9071,7 +9088,7 @@ check_VecOperands (const insn_template *
- scatter/gather insns (i.e. ones using vSIB) only allow merging-
masking. */
if (i.mask.zeroing
- && (t->operand_types[t->operands - 1].bitfield.class == RegMask
+ && (t_types[t->operands - 1].bitfield.class == RegMask
|| (i.flags[t->operands - 1] & Operand_Mem)
|| t->opcode_modifier.sib))
{
@@ -9155,14 +9172,14 @@ check_VecOperands (const insn_template *
{
if (t->opcode_modifier.evex == EVEXLIG)
i.memshift = 2 + (i.suffix == QWORD_MNEM_SUFFIX);
- else if (t->operand_types[op].bitfield.xmmword
- + t->operand_types[op].bitfield.ymmword
- + t->operand_types[op].bitfield.zmmword <= 1)
- type = &t->operand_types[op];
+ else if (t_types[op].bitfield.xmmword
+ + t_types[op].bitfield.ymmword
+ + t_types[op].bitfield.zmmword <= 1)
+ type = &t_types[op];
else if (!i.types[op].bitfield.unspecified)
type = &i.types[op];
else /* Ambiguities get resolved elsewhere. */
- fallback = &t->operand_types[op];
+ fallback = &t_types[op];
}
else if (i.types[op].bitfield.class == RegSIMD
&& t->opcode_modifier.evex != EVEXLIG)
@@ -9510,18 +9527,21 @@ match_template (char mnem_suffix)
if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE)
continue;
+ const i386_operand_type *t_types = get_operand_types (t);
+ for (j = 0; j < t->operands; ++j)
+ operand_types[j] = t_types[j];
+ for (; j < MAX_OPERANDS; ++j)
+ operand_types[j] = (i386_operand_type){ .array[0] = 0 };
+
/* In Intel syntax, normally we can check for memory operand size when
there is no mnemonic suffix. But jmp and call have 2 different
encodings with Dword memory operand size. Skip the "near" one
(permitting a register operand) when "far" was requested. */
if (i.far_branch
&& t->opcode_modifier.jump == JUMP_ABSOLUTE
- && t->operand_types[0].bitfield.class == Reg)
+ && operand_types[0].bitfield.class == Reg)
continue;
- for (j = 0; j < MAX_OPERANDS; j++)
- operand_types[j] = t->operand_types[j];
-
/* In general, don't allow 32-bit operands on pre-386. */
specific_error = progress (mnem_suffix ? invalid_instruction_suffix
: operand_size_mismatch);
@@ -9983,13 +10003,12 @@ match_template (char mnem_suffix)
size_match = true;
/* We ensure that the next template has the same input
operands as the original matching template by the first
- opernd (ATT). To avoid someone support new NDD insns and
+ operand (ATT). To avoid someone support new NDD insns and
put it in the wrong position. */
- overlap0 = operand_type_and (i.types[0],
- t[1].operand_types[0]);
+ const i386_operand_type *t1_types = get_operand_types (&t[1]);
+ overlap0 = operand_type_and (i.types[0], t1_types[0]);
if (t->opcode_modifier.d)
- overlap1 = operand_type_and (i.types[0],
- t[1].operand_types[1]);
+ overlap1 = operand_type_and (i.types[0], t1_types[1]);
if (!operand_type_match (overlap0, i.types[0])
&& (!t->opcode_modifier.d
|| !operand_type_match (overlap1, i.types[0])))
@@ -15294,6 +15313,7 @@ i386_index_check (const char *operand_st
if (t->opcode_modifier.isstring)
{
+ const i386_operand_type *t_types = get_operand_types (t);
/* Memory operands of string insns are special in that they only allow
a single register (rDI or rSI) as their memory address. */
const reg_entry *expected_reg;
@@ -15319,22 +15339,22 @@ i386_index_check (const char *operand_st
int es_op = t->opcode_modifier.isstring - IS_STRING_ES_OP0;
int op = 0;
- if (!t->operand_types[0].bitfield.baseindex
+ if (!t_types[0].bitfield.baseindex
|| ((!i.mem_operands != !intel_syntax)
- && t->operand_types[1].bitfield.baseindex))
+ && t_types[1].bitfield.baseindex))
op = 1;
expected_reg = str_hash_find (reg_hash,
di_si[addr_mode][op == es_op]);
}
else
{
- unsigned int op = t->operand_types[0].bitfield.baseindex ? 0 : 1;
+ unsigned int op = t_types[0].bitfield.baseindex ? 0 : 1;
- if (!t->operand_types[op].bitfield.instance)
+ if (!t_types[op].bitfield.instance)
return 1; /* Operand mismatch will be detected elsewhere. */
expected_reg
= str_hash_find (reg_hash,
- loregs[addr_mode][t->operand_types[op]
+ loregs[addr_mode][t_types[op]
.bitfield.instance - 1]);
}
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -923,9 +923,11 @@ i386_intel_operand (char *operand_string
i.types[this_operand].bitfield.tbyte = 1;
if (got_a_float)
break;
+ const i386_operand_type *t_types
+ = get_operand_types (current_templates.start);
if (flag_code == CODE_64BIT
- && (current_templates.start->operand_types[0].bitfield.fword
- || current_templates.start->operand_types[0].bitfield.tbyte
+ && (t_types[0].bitfield.fword
+ || t_types[0].bitfield.tbyte
|| current_templates.start->opcode_modifier.jump == JUMP_DWORD
|| current_templates.start->opcode_modifier.jump == JUMP))
suffix = QWORD_MNEM_SUFFIX; /* l[fgs]s, [ls][gi]dt, call, jmp */
@@ -1031,10 +1033,11 @@ i386_intel_operand (char *operand_string
if (!t->opcode_modifier.modrm)
break;
- if (!t->operand_types[op].bitfield.baseindex)
+ const i386_operand_type *t_types = get_operand_types (t);
+ if (!t_types[op].bitfield.baseindex)
continue;
- switch (t->operand_types[op].bitfield.class)
+ switch (t_types[op].bitfield.class)
{
case RegMMX:
case RegSIMD: