aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2023-11-09 12:54:58 +0100
committerJan Beulich <jbeulich@suse.com>2023-11-09 12:54:58 +0100
commita5e91879d14fd5f2e477e556e629e1b8e06359a6 (patch)
tree621b421fd9d9002f8c865a55ec5797062f7505da /gas
parent3e624fa4b870f90c8f5c31ad533b3abc4a4bfa93 (diff)
downloadfsf-binutils-gdb-a5e91879d14fd5f2e477e556e629e1b8e06359a6.zip
fsf-binutils-gdb-a5e91879d14fd5f2e477e556e629e1b8e06359a6.tar.gz
fsf-binutils-gdb-a5e91879d14fd5f2e477e556e629e1b8e06359a6.tar.bz2
x86: split insn templates' CPU field
Right now the opcode table has entries with ISA restrictions of the form FEAT1|FEAT2, the meaning of which depends on context and requires special treatment in tc-i386.c: Sometimes this means "both features requires", whereas originally it was intended to solely mean "all of these features required". Split the field, with the original one regaining its original meaning. The new field now truly means "any of these". The combination of both fields is still and &&-type check, i.e. (all of these) && (any of these). In the opcode table more involved combinations of features then also need expressing this way: "all" entities first, follow by "any" entities enclosed in parentheses, e.g. x64&(AVX|AVX512F). If the "all" part is empty, parentheses may not be added around the "any" part (unless parsing logic was further relaxed). Note that this way AVX512VL no longer needs as much special treatment, and hence templates previously using AVX512F|AVX512VL are switched to just AVX512VL. Note further that this requires FMA handling as resulting from da0784f961d8 ("x86: fold FMA VEX and EVEX templates") to be slightly re-done: FMA now becomes more similar to AVX and AVX2.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-i386.c173
1 files changed, 81 insertions, 92 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index c6a1521..bb02347 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1655,24 +1655,36 @@ operand_type_equal (const union i386_operand_type *x,
}
static INLINE bool
-is_cpu (const insn_template *t, enum i386_cpu cpu)
+_is_cpu (const i386_cpu_attr *a, enum i386_cpu cpu)
{
switch (cpu)
{
- case Cpu287: return t->cpu.bitfield.cpu287;
- case Cpu387: return t->cpu.bitfield.cpu387;
- case Cpu3dnow: return t->cpu.bitfield.cpu3dnow;
- case Cpu3dnowA: return t->cpu.bitfield.cpu3dnowa;
- case CpuAVX: return t->cpu.bitfield.cpuavx;
- case CpuHLE: return t->cpu.bitfield.cpuhle;
- case CpuAVX512F: return t->cpu.bitfield.cpuavx512f;
- case CpuAVX512VL: return t->cpu.bitfield.cpuavx512vl;
- case Cpu64: return t->cpu.bitfield.cpu64;
- case CpuNo64: return t->cpu.bitfield.cpuno64;
+ case Cpu287: return a->bitfield.cpu287;
+ case Cpu387: return a->bitfield.cpu387;
+ case Cpu3dnow: return a->bitfield.cpu3dnow;
+ case Cpu3dnowA: return a->bitfield.cpu3dnowa;
+ case CpuAVX: return a->bitfield.cpuavx;
+ case CpuHLE: return a->bitfield.cpuhle;
+ case CpuAVX512F: return a->bitfield.cpuavx512f;
+ case CpuAVX512VL: return a->bitfield.cpuavx512vl;
+ case Cpu64: return a->bitfield.cpu64;
+ case CpuNo64: return a->bitfield.cpuno64;
default:
gas_assert (cpu < CpuAttrEnums);
}
- return t->cpu.bitfield.isa == cpu + 1u;
+ return a->bitfield.isa == cpu + 1u;
+}
+
+static INLINE bool
+is_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+ return _is_cpu(&t->cpu, cpu);
+}
+
+static INLINE bool
+maybe_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+ return _is_cpu(&t->cpu_any, cpu);
}
static i386_cpu_flags cpu_flags_from_attr (i386_cpu_attr a)
@@ -1863,96 +1875,68 @@ static INLINE bool need_evex_encoding (void)
static int
cpu_flags_match (const insn_template *t)
{
- i386_cpu_flags x = cpu_flags_from_attr (t->cpu);
+ i386_cpu_flags cpu, active, all = cpu_flags_from_attr (t->cpu);
+ i386_cpu_flags any = cpu_flags_from_attr (t->cpu_any);
int match = cpu_flags_check_cpu64 (t) ? CPU_FLAGS_64BIT_MATCH : 0;
- x.bitfield.cpu64 = 0;
- x.bitfield.cpuno64 = 0;
+ all.bitfield.cpu64 = 0;
+ all.bitfield.cpuno64 = 0;
+ gas_assert (!any.bitfield.cpu64);
+ gas_assert (!any.bitfield.cpuno64);
- if (cpu_flags_all_zero (&x))
+ if (cpu_flags_all_zero (&all) && cpu_flags_all_zero (&any))
{
/* This instruction is available on all archs. */
- match |= CPU_FLAGS_ARCH_MATCH;
+ return match | CPU_FLAGS_ARCH_MATCH;
}
- else
- {
- /* This instruction is available only on some archs. */
- i386_cpu_flags active, cpu;
- if (flag_code != CODE_64BIT)
- active = cpu_flags_and_not (cpu_arch_flags, cpu_64_flags);
- else
- active = cpu_arch_flags;
+ /* This instruction is available only on some archs. */
- /* Dual VEX/EVEX templates may need stripping of one of the flags. */
- if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+ /* Dual VEX/EVEX templates may need stripping of one of the flags. */
+ if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+ {
+ /* Dual AVX/AVX512 templates need to retain AVX512* only if we already
+ know that EVEX encoding will be needed. */
+ if ((any.bitfield.cpuavx || any.bitfield.cpuavx2 || any.bitfield.cpufma)
+ && (any.bitfield.cpuavx512f || any.bitfield.cpuavx512vl))
{
- /* Dual AVX/AVX512F templates need to retain AVX512F only if we already
- know that EVEX encoding will be needed. */
- if ((x.bitfield.cpuavx || x.bitfield.cpuavx2)
- && x.bitfield.cpuavx512f)
+ if (need_evex_encoding ())
{
- if (need_evex_encoding ())
- {
- x.bitfield.cpuavx = 0;
- x.bitfield.cpuavx2 = 0;
- }
- /* need_evex_encoding() isn't reliable before operands were
- parsed. */
- else if (i.operands)
- {
- x.bitfield.cpuavx512f = 0;
- x.bitfield.cpuavx512vl = 0;
- if (x.bitfield.cpufma && !active.bitfield.cpufma)
- x.bitfield.cpuavx = 0;
- }
+ any.bitfield.cpuavx = 0;
+ any.bitfield.cpuavx2 = 0;
+ any.bitfield.cpufma = 0;
+ }
+ /* need_evex_encoding() isn't reliable before operands were
+ parsed. */
+ else if (i.operands)
+ {
+ any.bitfield.cpuavx512f = 0;
+ any.bitfield.cpuavx512vl = 0;
}
}
+ }
- /* AVX512VL is no standalone feature - match it and then strip it. */
- if (x.bitfield.cpuavx512vl && !active.bitfield.cpuavx512vl)
- return match;
- x.bitfield.cpuavx512vl = 0;
-
+ if (flag_code != CODE_64BIT)
+ active = cpu_flags_and_not (cpu_arch_flags, cpu_64_flags);
+ else
+ active = cpu_arch_flags;
+ cpu = cpu_flags_and (all, active);
+ if (cpu_flags_equal (&cpu, &all))
+ {
/* AVX and AVX2 present at the same time express an operand size
dependency - strip AVX2 for the purposes here. The operand size
dependent check occurs in check_vecOperands(). */
- if (x.bitfield.cpuavx && x.bitfield.cpuavx2)
- x.bitfield.cpuavx2 = 0;
-
- cpu = cpu_flags_and (x, active);
- if (!cpu_flags_all_zero (&cpu))
- {
- if (t->cpu.bitfield.cpuavx && t->cpu.bitfield.cpuavx512f)
- {
- if ((need_evex_encoding ()
- ? cpu.bitfield.cpuavx512f
- : cpu.bitfield.cpuavx)
- && (!x.bitfield.cpufma || cpu.bitfield.cpufma
- || active.bitfield.cpuavx512f)
- && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
- && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
- && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
- match |= CPU_FLAGS_ARCH_MATCH;
- }
- else if (x.bitfield.cpuavx)
- {
- /* We need to check a few extra flags with AVX. */
- if (cpu.bitfield.cpuavx
- && (!t->opcode_modifier.sse2avx
- || (sse2avx && !i.prefix[DATA_PREFIX]))
- && (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
- && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
- && (!x.bitfield.cpupclmulqdq || cpu.bitfield.cpupclmulqdq))
- match |= CPU_FLAGS_ARCH_MATCH;
- }
- else if (x.bitfield.cpuavx2 && cpu.bitfield.cpuavx2)
- match |= CPU_FLAGS_ARCH_MATCH;
- else if (x.bitfield.cpuavx512f)
+ if (any.bitfield.cpuavx && any.bitfield.cpuavx2)
+ any.bitfield.cpuavx2 = 0;
+
+ cpu = cpu_flags_and (any, active);
+ if (cpu_flags_all_zero (&any) || !cpu_flags_all_zero (&cpu))
+ {
+ if (all.bitfield.cpuavx)
{
- /* We need to check a few extra flags with AVX512F. */
- if (cpu.bitfield.cpuavx512f
- && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni))
+ /* We need to check SSE2AVX with AVX. */
+ if (!t->opcode_modifier.sse2avx
+ || (sse2avx && !i.prefix[DATA_PREFIX]))
match |= CPU_FLAGS_ARCH_MATCH;
}
else
@@ -3679,20 +3663,25 @@ install_template (const insn_template *t)
/* Dual VEX/EVEX templates need stripping one of the possible variants. */
if (t->opcode_modifier.vex && t->opcode_modifier.evex)
{
- if ((is_cpu (t, CpuAVX) || is_cpu (t, CpuAVX2))
- && is_cpu (t, CpuAVX512F))
+ if ((maybe_cpu (t, CpuAVX) || maybe_cpu (t, CpuAVX2)
+ || maybe_cpu (t, CpuFMA))
+ && (maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512VL)))
{
if (need_evex_encoding ())
{
i.tm.opcode_modifier.vex = 0;
- i.tm.cpu.bitfield.cpuavx = 0;
- if (is_cpu (&i.tm, CpuAVX2))
- i.tm.cpu.bitfield.isa = 0;
+ i.tm.cpu.bitfield.cpuavx512f = i.tm.cpu_any.bitfield.cpuavx512f;
+ i.tm.cpu.bitfield.cpuavx512vl = i.tm.cpu_any.bitfield.cpuavx512vl;
}
else
{
i.tm.opcode_modifier.evex = 0;
- i.tm.cpu.bitfield.cpuavx512f = 0;
+ if (i.tm.cpu_any.bitfield.cpuavx)
+ i.tm.cpu.bitfield.cpuavx = 1;
+ else if (!i.tm.cpu.bitfield.isa)
+ i.tm.cpu.bitfield.isa = i.tm.cpu_any.bitfield.isa;
+ else
+ gas_assert (i.tm.cpu.bitfield.isa == i.tm.cpu_any.bitfield.isa);
}
}
}
@@ -6570,7 +6559,7 @@ check_VecOperands (const insn_template *t)
/* Somewhat similarly, templates specifying both AVX and AVX2 are
requiring AVX2 support if the actual operand size is YMMword. */
- if (is_cpu (t, CpuAVX) && is_cpu (t, CpuAVX2)
+ if (maybe_cpu (t, CpuAVX) && maybe_cpu (t, CpuAVX2)
&& !cpu_arch_flags.bitfield.cpuavx2)
{
for (op = 0; op < t->operands; ++op)