aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorCui, Lili <lili.cui@intel.com>2023-12-28 01:06:40 +0000
committerCui, Lili <lili.cui@intel.com>2023-12-28 11:31:01 +0000
commit6177c84d5edc2cb6b197f00bd06380b7b24a719f (patch)
treec23753c4b69099bb346a7e79f046d3919e7f2ea0 /gas/config
parent2b1d6655c5c62673547b9676d811ef58ce3f0d1e (diff)
downloadgdb-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.c85
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)