Skip to content

Commit 87bbaf1

Browse files
ahunter6Ingo Molnar
authored andcommitted
x86/insn: Add support for APX EVEX to the instruction decoder logic
Intel Advanced Performance Extensions (APX) extends the EVEX prefix to support: - extended general purpose registers (EGPRs) i.e. r16 to r31 - Push-Pop Acceleration (PPX) hints - new data destination (NDD) register - suppress status flags writes (NF) of common instructions - new instructions Refer to the Intel Advanced Performance Extensions (Intel APX) Architecture Specification for details. The extended EVEX prefix does not need amended instruction decoder logic, except in one area. Some instructions are defined as SCALABLE which means the EVEX.W bit and EVEX.pp bits are used to determine operand size. Specifically, if an instruction is SCALABLE and EVEX.W is zero, then EVEX.pp value 0 (representing no prefix NP) means default operand size, whereas EVEX.pp value 1 (representing 66 prefix) means operand size override i.e. 16 bits Add an attribute (INAT_EVEX_SCALABLE) to identify such instructions, and amend the logic appropriately. Amend the awk script that generates the attribute tables from the opcode map, to recognise "(es)" as attribute INAT_EVEX_SCALABLE. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20240502105853.5338-8-adrian.hunter@intel.com
1 parent 159039a commit 87bbaf1

File tree

8 files changed

+42
-0
lines changed

8 files changed

+42
-0
lines changed

arch/x86/include/asm/inat.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
8282
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
8383
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
84+
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
8485
/* Attribute making macros for attribute tables */
8586
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
8687
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
@@ -236,4 +237,9 @@ static inline int inat_must_evex(insn_attr_t attr)
236237
{
237238
return attr & INAT_EVEXONLY;
238239
}
240+
241+
static inline int inat_evex_scalable(insn_attr_t attr)
242+
{
243+
return attr & INAT_EVEX_SCALABLE;
244+
}
239245
#endif

arch/x86/include/asm/insn.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
215215
return X86_VEX_P(insn->vex_prefix.bytes[2]);
216216
}
217217

218+
static inline insn_byte_t insn_vex_w_bit(struct insn *insn)
219+
{
220+
if (insn->vex_prefix.nbytes < 3)
221+
return 0;
222+
return X86_VEX_W(insn->vex_prefix.bytes[2]);
223+
}
224+
218225
/* Get the last prefix id from last prefix or VEX prefix */
219226
static inline int insn_last_prefix_id(struct insn *insn)
220227
{

arch/x86/lib/insn.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ int insn_get_opcode(struct insn *insn)
294294
m = insn_vex_m_bits(insn);
295295
p = insn_vex_p_bits(insn);
296296
insn->attr = inat_get_avx_attribute(op, m, p);
297+
/* SCALABLE EVEX uses p bits to encode operand size */
298+
if (inat_evex_scalable(insn->attr) && !insn_vex_w_bit(insn) &&
299+
p == INAT_PFX_OPNDSZ)
300+
insn->opnd_bytes = 2;
297301
if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
298302
(!inat_accept_vex(insn->attr) &&
299303
!inat_is_group(insn->attr))) {

arch/x86/tools/gen-insn-attr-x86.awk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ BEGIN {
8383
vexonly_expr = "\\(v\\)"
8484
# All opcodes with (ev) superscript supports *only* EVEX prefix
8585
evexonly_expr = "\\(ev\\)"
86+
# (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
87+
evex_scalable_expr = "\\(es\\)"
8688

8789
prefix_expr = "\\(Prefix\\)"
8890
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
@@ -332,6 +334,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
332334
# check VEX codes
333335
if (match(ext, evexonly_expr))
334336
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
337+
else if (match(ext, evex_scalable_expr))
338+
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
335339
else if (match(ext, vexonly_expr))
336340
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
337341
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))

tools/arch/x86/include/asm/inat.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
8282
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
8383
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
84+
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
8485
/* Attribute making macros for attribute tables */
8586
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
8687
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
@@ -236,4 +237,9 @@ static inline int inat_must_evex(insn_attr_t attr)
236237
{
237238
return attr & INAT_EVEXONLY;
238239
}
240+
241+
static inline int inat_evex_scalable(insn_attr_t attr)
242+
{
243+
return attr & INAT_EVEX_SCALABLE;
244+
}
239245
#endif

tools/arch/x86/include/asm/insn.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
215215
return X86_VEX_P(insn->vex_prefix.bytes[2]);
216216
}
217217

218+
static inline insn_byte_t insn_vex_w_bit(struct insn *insn)
219+
{
220+
if (insn->vex_prefix.nbytes < 3)
221+
return 0;
222+
return X86_VEX_W(insn->vex_prefix.bytes[2]);
223+
}
224+
218225
/* Get the last prefix id from last prefix or VEX prefix */
219226
static inline int insn_last_prefix_id(struct insn *insn)
220227
{

tools/arch/x86/lib/insn.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ int insn_get_opcode(struct insn *insn)
294294
m = insn_vex_m_bits(insn);
295295
p = insn_vex_p_bits(insn);
296296
insn->attr = inat_get_avx_attribute(op, m, p);
297+
/* SCALABLE EVEX uses p bits to encode operand size */
298+
if (inat_evex_scalable(insn->attr) && !insn_vex_w_bit(insn) &&
299+
p == INAT_PFX_OPNDSZ)
300+
insn->opnd_bytes = 2;
297301
if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
298302
(!inat_accept_vex(insn->attr) &&
299303
!inat_is_group(insn->attr))) {

tools/arch/x86/tools/gen-insn-attr-x86.awk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ BEGIN {
8383
vexonly_expr = "\\(v\\)"
8484
# All opcodes with (ev) superscript supports *only* EVEX prefix
8585
evexonly_expr = "\\(ev\\)"
86+
# (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
87+
evex_scalable_expr = "\\(es\\)"
8688

8789
prefix_expr = "\\(Prefix\\)"
8890
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
@@ -332,6 +334,8 @@ function convert_operands(count,opnd, i,j,imm,mod)
332334
# check VEX codes
333335
if (match(ext, evexonly_expr))
334336
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
337+
else if (match(ext, evex_scalable_expr))
338+
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
335339
else if (match(ext, vexonly_expr))
336340
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
337341
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))

0 commit comments

Comments
 (0)