aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
authorCui, Lili <lili.cui@intel.com>2023-12-28 01:06:39 +0000
committerCui, Lili <lili.cui@intel.com>2023-12-28 11:14:41 +0000
commit80d61d8d614d68a0b1932ed3a86d4cda01e5633e (patch)
treed96a3481c4563e2fd0fee9ae049626ee9dea6053 /gas/config/tc-i386.c
parentfcd5cdd5aeecf7eae91a402755c260bb64a0fe0f (diff)
downloadgdb-80d61d8d614d68a0b1932ed3a86d4cda01e5633e.zip
gdb-80d61d8d614d68a0b1932ed3a86d4cda01e5633e.tar.gz
gdb-80d61d8d614d68a0b1932ed3a86d4cda01e5633e.tar.bz2
Support APX GPR32 with rex2 prefix
APX uses the REX2 prefix to support EGPR for map0 and map1 of legacy instructions. We added the NoEgpr flag in i386-gen.c for instructions that do not support EGPR. 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 (enum i386_error): Add unsupported_EGPR_for_addressing and invalid_pseudo_prefix. (struct _i386_insn): Add rex2 and rex2_encoding for gpr32. (cpu_arch): Add apx_f. (is_cpu): Ditto. (register_number): Handle RegRex2 for gpr32. (is_apx_rex2_encoding): New func. Test rex2 prefix encoding. (build_rex2_prefix): New func. Build legacy insn in opcode 0/1 use gpr32 with rex2 prefix. (establish_rex): Handle rex2 and rex2_encoding. (optimize_encoding): Handel add r16-r31 for registers. (md_assemble): Handle apx encoding. (parse_insn): Handle Prefix_REX2. (check_EgprOperands): New func. Check if Egprs operands are valid for the instruction (match_template): Handle Egpr operands check. (set_rex_rex2): New func. set i.rex and i.rex2. (build_modrm_byte): Ditto. (output_insn): Handle rex2 2-byte prefix output. (check_register): Handle check egpr illegal without target apx, 64-bit mode and with rex_prefix. * doc/c-i386.texi: Document .apx. * testsuite/gas/i386/ilp32/x86-64-opcode-inval-intel.d: D5 valid in 64-bit mode. * testsuite/gas/i386/ilp32/x86-64-opcode-inval.d: Ditto. * testsuite/gas/i386/rex-bad: Adjust rex testcase. * testsuite/gas/i386/x86-64-opcode-inval-intel.d: Ditto. * testsuite/gas/i386/x86-64-opcode-inval.d: Ditto. * testsuite/gas/i386/x86-64-opcode-inval.s: Ditto. * testsuite/gas/i386/x86-64-pseudos-bad.l: Add illegal rex2 test. * testsuite/gas/i386/x86-64-pseudos-bad.s: Ditto. * testsuite/gas/i386/x86-64-pseudos.d: Add rex2 test. * testsuite/gas/i386/x86-64-pseudos.s: Ditto. * testsuite/gas/i386/x86-64.exp: Run APX tests. * testsuite/gas/i386/x86-64-apx-egpr-inval.l: New test. * testsuite/gas/i386/x86-64-apx-egpr-inval.s: New test. * testsuite/gas/i386/x86-64-apx-rex2.d: New test. * testsuite/gas/i386/x86-64-apx-rex2.s: New test. include/ChangeLog: * opcode/i386.h (REX2_OPCODE): New. (REX2_M): Ditto. opcodes/ChangeLog: * i386-dis.c (struct instr_info): Add erex for gpr32. Add last_erex_prefix for rex2 prefix. (REX2_M): Extend for gpr32. (PREFIX_REX2): Ditto. (PREFIX_REX2_ILLEGAL): Ditto. (ckprefix): Ditto. (prefix_name): Ditto. (print_insn): Ditto. (print_register): Ditto. (OP_E_memory): Ditto. (OP_REG): Ditto. (OP_EX): Ditto. * i386-gen.c (rex2_disallowed): Some instructions are not allowed rex2 prefix. (process_i386_opcode_modifier): Set NoEgpr for VEX and some special instructions. (output_i386_opcode): Handle if_entry_needs_special_handle. * i386-init.h : Regenerated. * i386-mnem.h : Regenerated. * i386-opc.h (enum i386_cpu): Add CpuAPX_F. (NoEgpr): New. (Prefix_NoOptimize): Ditto. (Prefix_REX2): Ditto. (RegRex2): Ditto. * i386-opc.tbl: Add rex2 prefix. * i386-reg.tbl: Add egprs (r16-r31). * i386-tbl.h: Regenerated.
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c178
1 files changed, 158 insertions, 20 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index cdd3b55..11b3927 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -239,6 +239,7 @@ enum i386_error
bad_imm4,
unsupported_with_intel_mnemonic,
unsupported_syntax,
+ unsupported_EGPR_for_addressing,
unsupported,
unsupported_on_arch,
unsupported_64bit,
@@ -249,6 +250,7 @@ enum i386_error
invalid_vector_register_set,
invalid_tmm_register_set,
invalid_dest_and_src_register_set,
+ invalid_pseudo_prefix,
unsupported_vector_index_register,
unsupported_broadcast,
broadcast_needed,
@@ -356,6 +358,7 @@ struct _i386_insn
modrm_byte rm;
rex_byte rex;
rex_byte vrex;
+ rex_byte rex2;
sib_byte sib;
vex_prefix vex;
@@ -429,6 +432,9 @@ struct _i386_insn
/* Prefer the REX byte in encoding. */
bool rex_encoding;
+ /* Prefer the REX2 prefix in encoding. */
+ bool rex2_encoding;
+
/* Disable instruction size optimization. */
bool no_optimize;
@@ -1149,6 +1155,7 @@ static const arch_entry cpu_arch[] =
SUBARCH (pbndkb, PBNDKB, PBNDKB, false),
VECARCH (avx10.1, AVX10_1, ANY_AVX512F, set),
SUBARCH (user_msr, USER_MSR, USER_MSR, false),
+ SUBARCH (apx_f, APX_F, APX_F, false),
};
#undef SUBARCH
@@ -1664,6 +1671,7 @@ _is_cpu (const i386_cpu_attr *a, enum i386_cpu cpu)
case CpuHLE: return a->bitfield.cpuhle;
case CpuAVX512F: return a->bitfield.cpuavx512f;
case CpuAVX512VL: return a->bitfield.cpuavx512vl;
+ case CpuAPX_F: return a->bitfield.cpuapx_f;
case Cpu64: return a->bitfield.cpu64;
case CpuNo64: return a->bitfield.cpuno64;
default:
@@ -2335,7 +2343,7 @@ register_number (const reg_entry *r)
if (r->reg_flags & RegRex)
nr += 8;
- if (r->reg_flags & RegVRex)
+ if (r->reg_flags & (RegVRex | RegRex2))
nr += 16;
return nr;
@@ -3871,6 +3879,12 @@ is_any_vex_encoding (const insn_template *t)
return t->opcode_modifier.vex || t->opcode_modifier.evex;
}
+static INLINE bool
+is_apx_rex2_encoding (void)
+{
+ return i.rex2 || i.rex2_encoding;
+}
+
static unsigned int
get_broadcast_bytes (const insn_template *t, bool diag)
{
@@ -4126,6 +4140,22 @@ build_evex_prefix (void)
i.vex.bytes[3] |= i.mask.reg->reg_num;
}
+/* Build (2 bytes) rex2 prefix.
+ | D5h |
+ | m | R4 X4 B4 | W R X B |
+
+ Rex2 reuses i.vex as they both encode i.tm.opcode_space in their prefixes.
+ */
+static void
+build_rex2_prefix (void)
+{
+ i.vex.length = 2;
+ i.vex.bytes[0] = 0xd5;
+ /* For the W R X B bits, the variables of rex prefix will be reused. */
+ i.vex.bytes[1] = ((i.tm.opcode_space << 7)
+ | (i.rex2 << 4) | i.rex);
+}
+
static void establish_rex (void)
{
/* Note that legacy encodings have at most 2 non-immediate operands. */
@@ -4140,13 +4170,16 @@ static void establish_rex (void)
registers to new ones. */
if ((i.types[first].bitfield.class == Reg && i.types[first].bitfield.byte
- && ((i.op[first].regs->reg_flags & RegRex64) != 0 || i.rex != 0))
+ && ((i.op[first].regs->reg_flags & RegRex64) != 0 || i.rex != 0
+ || i.rex2 != 0))
|| (i.types[last].bitfield.class == Reg && i.types[last].bitfield.byte
- && ((i.op[last].regs->reg_flags & RegRex64) != 0 || i.rex != 0)))
+ && ((i.op[last].regs->reg_flags & RegRex64) != 0 || i.rex != 0
+ || i.rex2 != 0)))
{
unsigned int x;
- i.rex |= REX_OPCODE;
+ if (!is_apx_rex2_encoding () && !is_any_vex_encoding(&i.tm))
+ i.rex |= REX_OPCODE;
for (x = first; x <= last; x++)
{
/* Look for 8 bit operand that uses old registers. */
@@ -4157,7 +4190,7 @@ static void establish_rex (void)
/* In case it is "hi" register, give up. */
if (i.op[x].regs->reg_num > 3)
as_bad (_("can't encode register '%s%s' in an "
- "instruction requiring REX prefix"),
+ "instruction requiring REX/REX2 prefix"),
register_prefix, i.op[x].regs->reg_name);
/* Otherwise it is equivalent to the extended register.
@@ -4168,11 +4201,11 @@ static void establish_rex (void)
}
}
- if (i.rex == 0 && i.rex_encoding)
+ if (i.rex == 0 && i.rex2 == 0 && (i.rex_encoding || i.rex2_encoding))
{
/* Check if we can add a REX_OPCODE byte. Look for 8 bit operand
that uses legacy register. If it is "hi" register, don't add
- the REX_OPCODE byte. */
+ rex and rex2 prefix. */
unsigned int x;
for (x = first; x <= last; x++)
@@ -4183,6 +4216,7 @@ static void establish_rex (void)
{
gas_assert (!(i.op[x].regs->reg_flags & RegRex));
i.rex_encoding = false;
+ i.rex2_encoding = false;
break;
}
@@ -4190,8 +4224,14 @@ static void establish_rex (void)
i.rex = REX_OPCODE;
}
- if (i.rex != 0)
- add_prefix (REX_OPCODE | i.rex);
+ if (is_apx_rex2_encoding ())
+ {
+ build_rex2_prefix ();
+ /* The individual REX.RXBW bits got consumed. */
+ i.rex &= REX_OPCODE;
+ }
+ else if (i.rex != 0)
+ add_prefix (REX_OPCODE | i.rex);
}
static void
@@ -4457,14 +4497,22 @@ optimize_encoding (void)
i.types[1].bitfield.byte = 1;
/* Ignore the suffix. */
i.suffix = 0;
- /* Convert to byte registers. */
+ /* Convert to byte registers. 8-bit registers are special,
+ RegRex64 and non-RegRex64 each have 8 registers. */
if (i.types[1].bitfield.word)
- j = 16;
- else if (i.types[1].bitfield.dword)
+ /* 32 (or 40) 8-bit registers. */
j = 32;
+ else if (i.types[1].bitfield.dword)
+ /* 32 (or 40) 8-bit registers + 32 16-bit registers. */
+ j = 64;
else
- j = 48;
- if (!(i.op[1].regs->reg_flags & RegRex) && base_regnum < 4)
+ /* 32 (or 40) 8-bit registers + 32 16-bit registers
+ + 32 32-bit registers. */
+ j = 96;
+
+ /* In 64-bit mode, the following byte registers cannot be accessed
+ if using the Rex and Rex2 prefix: AH, BH, CH, DH */
+ if (!(i.op[1].regs->reg_flags & (RegRex | RegRex2)) && base_regnum < 4)
j += 8;
i.op[1].regs -= j;
}
@@ -5354,6 +5402,9 @@ md_assemble (char *line)
case unsupported_syntax:
err_msg = _("unsupported syntax");
break;
+ case unsupported_EGPR_for_addressing:
+ err_msg = _("extended GPR cannot be used as base/index");
+ break;
case unsupported:
as_bad (_("unsupported instruction `%s'"),
pass1_mnem ? pass1_mnem : insn_name (current_templates.start));
@@ -5407,6 +5458,9 @@ md_assemble (char *line)
case invalid_dest_and_src_register_set:
err_msg = _("destination and source registers must be distinct");
break;
+ case invalid_pseudo_prefix:
+ err_msg = _("rex2 pseudo prefix cannot be used");
+ break;
case unsupported_vector_index_register:
err_msg = _("unsupported vector index register");
break;
@@ -5662,6 +5716,13 @@ md_assemble (char *line)
return;
}
+ /* Check for explicit REX2 prefix. */
+ if (i.rex2_encoding)
+ {
+ as_bad (_("{rex2} prefix invalid with `%s'"), insn_name (&i.tm));
+ return;
+ }
+
if (i.tm.opcode_modifier.vex)
build_vex_prefix (t);
else
@@ -5868,6 +5929,10 @@ parse_insn (const char *line, char *mnemonic, bool prefix_only)
/* {rex} */
i.rex_encoding = true;
break;
+ case Prefix_REX2:
+ /* {rex2} */
+ i.rex2_encoding = true;
+ break;
case Prefix_NoOptimize:
/* {nooptimize} */
i.no_optimize = true;
@@ -7015,6 +7080,43 @@ VEX_check_encoding (const insn_template *t)
return 0;
}
+/* Check if Egprs operands are valid for the instruction. */
+
+static bool
+check_EgprOperands (const insn_template *t)
+{
+ if (!t->opcode_modifier.noegpr)
+ return 0;
+
+ for (unsigned int op = 0; op < i.operands; op++)
+ {
+ if (i.types[op].bitfield.class != Reg)
+ continue;
+
+ if (i.op[op].regs->reg_flags & RegRex2)
+ {
+ i.error = register_type_mismatch;
+ return 1;
+ }
+ }
+
+ if ((i.index_reg && (i.index_reg->reg_flags & RegRex2))
+ || (i.base_reg && (i.base_reg->reg_flags & RegRex2)))
+ {
+ i.error = unsupported_EGPR_for_addressing;
+ return 1;
+ }
+
+ /* Check if pseudo prefix {rex2} is valid. */
+ if (i.rex2_encoding)
+ {
+ i.error = invalid_pseudo_prefix;
+ return 1;
+ }
+
+ return 0;
+}
+
/* Helper function for the progress() macro in match_template(). */
static INLINE enum i386_error progress (enum i386_error new,
enum i386_error last,
@@ -7159,6 +7261,13 @@ match_template (char mnem_suffix)
continue;
}
+ /* Check if pseudo prefix {rex2} is valid. */
+ if (t->opcode_modifier.noegpr && i.rex2_encoding)
+ {
+ specific_error = progress (invalid_pseudo_prefix);
+ continue;
+ }
+
/* We've found a match; break out of loop. */
break;
}
@@ -7482,6 +7591,13 @@ match_template (char mnem_suffix)
continue;
}
+ /* Check if EGPR operands(r16-r31) are valid. */
+ if (check_EgprOperands (t))
+ {
+ specific_error = progress (i.error);
+ continue;
+ }
+
/* Check if vector operands are valid. */
if (check_VecOperands (t))
{
@@ -8387,6 +8503,18 @@ static INLINE void set_rex_vrex (const reg_entry *r, unsigned int rex_bit,
if (r->reg_flags & RegVRex)
i.vrex |= rex_bit;
+
+ if (r->reg_flags & RegRex2)
+ i.rex2 |= rex_bit;
+}
+
+static INLINE void
+set_rex_rex2 (const reg_entry *r, unsigned int rex_bit)
+{
+ if ((r->reg_flags & RegRex) != 0)
+ i.rex |= rex_bit;
+ if ((r->reg_flags & RegRex2) != 0)
+ i.rex2 |= rex_bit;
}
static int
@@ -8870,8 +8998,7 @@ build_modrm_byte (void)
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.types[op] = operand_type_and_not (i.types[op], anydisp);
i.types[op].bitfield.disp32 = 1;
- if ((i.index_reg->reg_flags & RegRex) != 0)
- i.rex |= REX_X;
+ set_rex_rex2 (i.index_reg, REX_X);
}
}
/* RIP addressing for 64bit mode. */
@@ -8942,8 +9069,7 @@ build_modrm_byte (void)
if (!i.tm.opcode_modifier.sib)
i.rm.regmem = i.base_reg->reg_num;
- if ((i.base_reg->reg_flags & RegRex) != 0)
- i.rex |= REX_B;
+ set_rex_rex2 (i.base_reg, REX_B);
i.sib.base = i.base_reg->reg_num;
/* x86-64 ignores REX prefix bit here to avoid decoder
complications. */
@@ -8981,8 +9107,7 @@ build_modrm_byte (void)
else
i.sib.index = i.index_reg->reg_num;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- if ((i.index_reg->reg_flags & RegRex) != 0)
- i.rex |= REX_X;
+ set_rex_rex2 (i.index_reg, REX_X);
}
if (i.disp_operands
@@ -10126,6 +10251,12 @@ output_insn (const struct last_insn *last_insn)
for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
if (*q)
frag_opcode_byte (*q);
+
+ if (is_apx_rex2_encoding ())
+ {
+ frag_opcode_byte (i.vex.bytes[0]);
+ frag_opcode_byte (i.vex.bytes[1]);
+ }
}
else
{
@@ -14164,6 +14295,13 @@ static bool check_register (const reg_entry *r)
i.vec_encoding = vex_encoding_error;
}
+ if (r->reg_flags & RegRex2)
+ {
+ if (!cpu_arch_flags.bitfield.cpuapx_f
+ || flag_code != CODE_64BIT)
+ return false;
+ }
+
if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
&& (!cpu_arch_flags.bitfield.cpu64
|| r->reg_type.bitfield.class != RegCR