diff options
author | Jan Beulich <jbeulich@suse.com> | 2023-11-09 12:54:58 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2023-11-09 12:54:58 +0100 |
commit | a5e91879d14fd5f2e477e556e629e1b8e06359a6 (patch) | |
tree | 621b421fd9d9002f8c865a55ec5797062f7505da /gas | |
parent | 3e624fa4b870f90c8f5c31ad533b3abc4a4bfa93 (diff) | |
download | fsf-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.c | 173 |
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) |