diff options
author | Cui, Lili <lili.cui@intel.com> | 2023-12-28 01:06:40 +0000 |
---|---|---|
committer | Cui, Lili <lili.cui@intel.com> | 2023-12-28 11:31:01 +0000 |
commit | 6177c84d5edc2cb6b197f00bd06380b7b24a719f (patch) | |
tree | c23753c4b69099bb346a7e79f046d3919e7f2ea0 /gas/config | |
parent | 2b1d6655c5c62673547b9676d811ef58ce3f0d1e (diff) | |
download | gdb-6177c84d5edc2cb6b197f00bd06380b7b24a719f.zip gdb-6177c84d5edc2cb6b197f00bd06380b7b24a719f.tar.gz gdb-6177c84d5edc2cb6b197f00bd06380b7b24a719f.tar.bz2 |
Support APX GPR32 with extend evex prefix
This patch adds non-ND, non-NF forms of EVEX promotion insn.
EVEX extension of legacy instructions:
All promoted legacy instructions are placed in EVEX map 4, which is
currently reserved.
EVEX extension of EVEX instructions:
All existing EVEX instructions are extended by APX using the extended
EVEX prefix, so that they can access all 32 GPRs.
EVEX extension of VEX instructions:
Promoting a VEX instruction into the EVEX space does not change the map
id, the opcode, or the operand encoding of the VEX instruction.
Note: The promoted versions of MOVBE will be extended to include the “MOVBE
reg1, reg2”.
gas/ChangeLog:
2023-12-28 Lingling Kong <lingling.kong@intel.com>
H.J. Lu <hongjiu.lu@intel.com>
Lili Cui <lili.cui@intel.com>
Lin Hu <lin1.hu@intel.com>
* config/tc-i386.c (struct _i386_insn): Add has_egpr.
(need_evex_encoding): Adjusted for apx.
(cpu_flags_match): Ditto.
(install_template): Handled APX combines.
(is_apx_evex_encoding): Test apx evex encoding.
(build_apx_evex_prefix): Enabe APX evex prefix.
(md_assemble): Handle apx with evex encoding.
(process_suffix): Handle apx map4 prefix.
(check_register): Assign i.vec_encoding for APX evex instructions.
* testsuite/gas/i386/x86-64-evex.d: Adjust test cases.
* testsuite/gas/i386/x86-64.exp: Adjust x86-64-inval-movbe.
opcodes/ChangeLog:
* i386-dis-evex-len.h: Handle EVEX_LEN_0F38F2, EVEX_LEN_0F38F3.
* i386-dis-evex-prefix.h: Handle PREFIX_EVEX_0F38F2_L_0,
PREFIX_EVEX_0F38F3_L_0, PREFIX_EVEX_MAP4_D8,
PREFIX_EVEX_MAP4_DA, PREFIX_EVEX_MAP4_DB,
PREFIX_EVEX_MAP4_DC, PREFIX_EVEX_MAP4_DD,
PREFIX_EVEX_MAP4_DE, PREFIX_EVEX_MAP4_DF,
PREFIX_EVEX_MAP4_F0, PREFIX_EVEX_MAP4_F1,
PREFIX_EVEX_MAP4_F2, PREFIX_EVEX_MAP4_F8.
* i386-dis-evex-reg.h: Handle REG_EVEX_0F38F3_L_0_P_0.
* i386-dis-evex.h: Add EVEX_MAP4_ for legacy insn
promote to apx to use gpr32
* opcodes/i386-dis-evex-x86-64.h: Handle Add X86_64_EVEX_0F90,
X86_64_EVEX_0F92, X86_64_EVEX_0F93, X86_64_EVEX_0F38F2,
X86_64_EVEX_0F38F3, X86_64_EVEX_0F38F5, X86_64_EVEX_0F38F6,
X86_64_EVEX_0F38F7, X86_64_EVEX_0F3AF0, X86_64_EVEX_0F91.
* i386-dis.c
(struct instr_info): Deleted bool r.
(PREFIX_NP_OR_DATA): New.
(NO_PREFIX): New.
(putop): Ditto.
(X86_64_EVEX_FROM_VEX_TABLE): Diito.
(get_valid_dis386): Decode insn erex in extend evex prefix.
Handle EVEX_MAP4
(print_insn): Handle PREFIX_DATA_AND_NP_ONLY.
(print_register): Handle apx instructions decode.
(OP_E_memory): Diito.
(OP_G): Diito.
(OP_XMM): Diito.
(DistinctDest_Fixup): Diito.
* i386-gen.c (process_i386_opcode_modifier): Add EVEXMAP4.
* i386-opc.h (SPACE_EVEXMAP4): Add legacy insn
promote to evex.
* i386-opc.tbl: Handle some legacy and vex insns don't
support gpr32. And add some legacy insn (map2 / 3) promote
to evex.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-i386.c | 85 |
1 files changed, 73 insertions, 12 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 11b3927..e41b79a 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -435,6 +435,9 @@ struct _i386_insn /* Prefer the REX2 prefix in encoding. */ bool rex2_encoding; + /* Need to use an Egpr capable encoding (REX2 or EVEX). */ + bool has_egpr; + /* Disable instruction size optimization. */ bool no_optimize; @@ -1862,10 +1865,11 @@ cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y) static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS; -static INLINE bool need_evex_encoding (void) +static INLINE bool need_evex_encoding (const insn_template *t) { return i.vec_encoding == vex_encoding_evex || i.vec_encoding == vex_encoding_evex512 + || (t->opcode_modifier.vex && i.has_egpr) || i.mask.reg; } @@ -1905,13 +1909,13 @@ cpu_flags_match (const insn_template *t) if ((any.bitfield.cpuavx || any.bitfield.cpuavx2 || any.bitfield.cpufma) && (any.bitfield.cpuavx512f || any.bitfield.cpuavx512vl)) { - if (need_evex_encoding ()) + if (need_evex_encoding (t)) { any.bitfield.cpuavx = 0; any.bitfield.cpuavx2 = 0; any.bitfield.cpufma = 0; } - /* need_evex_encoding() isn't reliable before operands were + /* need_evex_encoding(t) isn't reliable before operands were parsed. */ else if (i.operands) { @@ -3676,12 +3680,12 @@ 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 ((maybe_cpu (t, CpuAVX) || maybe_cpu (t, CpuAVX2) || maybe_cpu (t, CpuFMA)) && (maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512VL))) { - if (need_evex_encoding ()) + if (need_evex_encoding (t)) { i.tm.opcode_modifier.vex = 0; i.tm.cpu.bitfield.cpuavx512f = i.tm.cpu_any.bitfield.cpuavx512f; @@ -3698,7 +3702,19 @@ install_template (const insn_template *t) gas_assert (i.tm.cpu.bitfield.isa == i.tm.cpu_any.bitfield.isa); } } - } + + if ((maybe_cpu (t, CpuCMPCCXADD) || maybe_cpu (t, CpuAMX_TILE) + || maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512DQ) + || maybe_cpu (t, CpuAVX512BW) || maybe_cpu (t, CpuBMI) + || maybe_cpu (t, CpuBMI2)) + && maybe_cpu (t, CpuAPX_F)) + { + if (need_evex_encoding (t)) + i.tm.opcode_modifier.vex = 0; + else + i.tm.opcode_modifier.evex = 0; + } + } /* Note that for pseudo prefixes this produces a length of 1. But for them the length isn't interesting at all. */ @@ -3879,6 +3895,15 @@ is_any_vex_encoding (const insn_template *t) return t->opcode_modifier.vex || t->opcode_modifier.evex; } +/* We can use this function only when the current encoding is evex. */ +static INLINE bool +is_apx_evex_encoding (void) +{ + return i.rex2 || i.tm.opcode_space == SPACE_EVEXMAP4 + || (i.vex.register_specifier + && (i.vex.register_specifier->reg_flags & RegRex2)); +} + static INLINE bool is_apx_rex2_encoding (void) { @@ -4156,6 +4181,27 @@ build_rex2_prefix (void) | (i.rex2 << 4) | i.rex); } +/* Build the EVEX prefix (4-byte) for evex insn + | 62h | + | `R`X`B`R' | B'mmm | + | W | v`v`v`v | `x' | pp | + | z| L'L | b | `v | aaa | +*/ +static void +build_apx_evex_prefix (void) +{ + build_evex_prefix (); + if (i.rex2 & REX_R) + i.vex.bytes[1] &= ~0x10; + if (i.rex2 & REX_B) + i.vex.bytes[1] |= 0x08; + if (i.rex2 & REX_X) + i.vex.bytes[2] &= ~0x04; + if (i.vex.register_specifier + && i.vex.register_specifier->reg_flags & RegRex2) + i.vex.bytes[3] &= ~0x08; +} + static void establish_rex (void) { /* Note that legacy encodings have at most 2 non-immediate operands. */ @@ -5723,13 +5769,18 @@ md_assemble (char *line) return; } - if (i.tm.opcode_modifier.vex) + if (is_apx_evex_encoding ()) + build_apx_evex_prefix (); + else if (i.tm.opcode_modifier.vex) build_vex_prefix (t); else build_evex_prefix (); /* The individual REX.RXBW bits got consumed. */ i.rex &= REX_OPCODE; + + /* The rex2 bits got consumed. */ + i.rex2 = 0; } /* Handle conversion of 'int $3' --> special int3 insn. */ @@ -6648,7 +6699,7 @@ check_VecOperands (const insn_template *t) if (!cpu_flags_all_zero (&cpu) && !is_cpu (t, CpuAVX512VL) && !cpu_arch_flags.bitfield.cpuavx512vl - && (!t->opcode_modifier.vex || need_evex_encoding ())) + && (!t->opcode_modifier.vex || need_evex_encoding (t))) { for (op = 0; op < t->operands; ++op) { @@ -6960,7 +7011,7 @@ check_VecOperands (const insn_template *t) /* Check vector Disp8 operand. */ if (t->opcode_modifier.disp8memshift && (!t->opcode_modifier.vex - || need_evex_encoding ()) + || need_evex_encoding (t)) && i.disp_encoding <= disp_encoding_8bit) { if (i.broadcast.type || i.broadcast.bytes) @@ -7617,7 +7668,7 @@ match_template (char mnem_suffix) if ((t == current_templates.start || j > 1) && t->opcode_modifier.disp8memshift && !t->opcode_modifier.vex - && !need_evex_encoding () + && !need_evex_encoding (t) && t + j < current_templates.end && t[j].opcode_modifier.vex) { @@ -8084,7 +8135,8 @@ process_suffix (void) if (i.suffix != QWORD_MNEM_SUFFIX && i.tm.opcode_modifier.mnemonicsize != IGNORESIZE && !i.tm.opcode_modifier.floatmf - && !is_any_vex_encoding (&i.tm) + && (!is_any_vex_encoding (&i.tm) + || i.tm.opcode_space == SPACE_EVEXMAP4) && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) || (flag_code == CODE_64BIT && i.tm.opcode_modifier.jump == JUMP_BYTE))) @@ -8094,7 +8146,14 @@ process_suffix (void) if (i.tm.opcode_modifier.jump == JUMP_BYTE) /* jcxz, loop */ prefix = ADDR_PREFIX_OPCODE; - if (!add_prefix (prefix)) + /* The DATA PREFIX of EVEX promoted from legacy APX instructions + needs to be adjusted. */ + if (i.tm.opcode_space == SPACE_EVEXMAP4) + { + gas_assert (!i.tm.opcode_modifier.opcodeprefix); + i.tm.opcode_modifier.opcodeprefix = PREFIX_0X66; + } + else if (!add_prefix (prefix)) return 0; } @@ -14300,6 +14359,8 @@ static bool check_register (const reg_entry *r) if (!cpu_arch_flags.bitfield.cpuapx_f || flag_code != CODE_64BIT) return false; + + i.has_egpr = true; } if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword) |