apx: smarter determination of REX2 prefix eligibility

REX2 encoding is mostly default, so flag the instruction patters which
do *not* support REX2 instead.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2024-07-31 16:18:17 -07:00
parent fd08822070
commit dda9152b35
6 changed files with 182 additions and 111 deletions

View File

@ -112,7 +112,10 @@ static void add_asp(insn *, int);
static int process_ea(operand *, ea *, int, int, opflags_t,
insn *, enum ea_type, const char **);
/* Return any of REX_[BXR]1 corresponding to non-GPR registers */
/*
* Return any of REX_[BXR]1 corresponding to non-GPR registers by
* masking them with the REX_[BXR]V flags.
*/
static inline uint32_t rex_highvec(uint32_t rexflags)
{
return rexflags & (rexflags >> 4) & REX_BXR1;
@ -1793,7 +1796,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
} else {
/* VEX */
if (ins->vexreg > 15 || (ins->rex & REX_BXR1)) {
nasm_nonfatal("invalid high-16 register in non-AVX-512");
nasm_nonfatal("invalid high-16 register in VEX encoded instruction");
return -1;
}
@ -1811,28 +1814,28 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
}
} else if (ins->rex & (REX_BXR1 | REX_2)) {
/* REX2 prefix needed */
if (!itemp_has(temp, IF_REX2) || rex_highvec(ins->rex)) {
nasm_nonfatal("this use of registers 16-31 not supported for this instruction");
return -1;
}
if (ins->rex & REX_H) {
nasm_nonfatal("cannot use high byte register in rex2 instruction");
return -1;
}
if (bits != 64) {
nasm_nonfatal("invalid operands in non-64-bit mode");
nasm_nonfatal("invalid operands in %d-bit mode", bits);
return -1;
}
if (!iflag_test(&cpu, IF_APX)) {
nasm_nonfatal("invalid operands in non-APX mode");
return -1;
}
if (itemp_has(temp, IF_NOAPX) || rex_highvec(ins->rex)) {
nasm_nonfatal("this use of registers 16-31 not supported for this instruction");
return -1;
}
if (ins->rex & REX_H) {
nasm_nonfatal("cannot use high byte register in this instruction");
return -1;
}
ins->rex |= REX_2 | REX_P;
length += 2;
} else if (ins->rex & REX_MASK) {
if (ins->rex & REX_H) {
nasm_nonfatal("cannot use high byte register in rex instruction");
nasm_nonfatal("cannot use high byte register in this instruction");
return -1;
} else if (bits == 64) {
ins->rex &= ~REX_L;
@ -1845,7 +1848,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
lockcheck = false; /* Already errored, no need for warning */
ins->rex &= ~REX_P;
} else {
nasm_nonfatal("invalid operands in non-64-bit mode");
nasm_nonfatal("invalid operands in %d-bit mode", bits);
return -1;
}
length++;
@ -2522,23 +2525,26 @@ static uint32_t rexflags(int val, opflags_t flags, uint32_t mask)
{
uint32_t rex = 0;
if (val >= 0) {
if (val & 8)
rex |= REX_B|REX_X|REX_R;
if (val & 16)
rex |= REX_B1|REX_X1|REX_R1;
if (val < 0 || !is_class(REGISTER, flags)) {
/* Not a register */
return 0;
}
if (flags & BITS64)
rex |= REX_W;
if (!is_class(REG_GPR, flags)) {
if (!is_class(REG_CDT, flags))
rex |= REX_BV|REX_XV|REX_RV;
if (val & 8)
rex |= REX_B|REX_X|REX_R;
if (val & 16)
rex |= REX_B1|REX_X1|REX_R1;
if (flags & REG_CLASS_VECTOR) {
rex |= REX_BV|REX_XV|REX_RV;
} else if (is_class(REG8, flags)) {
if (is_class(REG_HIGH, flags)) /* AH, CH, DH, BH */
if (is_class(REG_HIGH, flags)) {
/* AH, CH, DH, BH: REX/REX2/VEX/EVEX forbidden */
rex |= REX_H;
else if (val >= 4) /* SPL, BPL, SIL, DIL */
} else if (val >= 4) {
/* SPL, BPL, SIL, DIL, or extended: prefix required */
rex |= REX_P;
}
}
return rex & mask;
@ -2711,12 +2717,16 @@ static enum match_result matches(const struct itemplate *itemp,
return MERR_ENCMISMATCH;
break;
case P_REX:
if (itemp_has(itemp, IF_VEX) || itemp_has(itemp, IF_EVEX) ||
bits != 64)
if (bits != 64 ||
itemp_has(itemp, IF_VEX) ||
itemp_has(itemp, IF_EVEX) ||
itemp_has(itemp, IF_REX2))
return MERR_ENCMISMATCH;
break;
case P_REX2:
if (!itemp_has(itemp, IF_REX2) || bits != 64)
if (bits != 64 ||
itemp_has(itemp, IF_NOAPX) ||
itemp_has(itemp, IF_EVEX))
return MERR_ENCMISMATCH;
break;
default:
@ -2729,6 +2739,9 @@ static enum match_result matches(const struct itemplate *itemp,
} else if (itemp_has(itemp, IF_LATEVEX)) {
if (!iflag_test(&cpu, IF_LATEVEX) && iflag_test(&cpu, IF_EVEX))
return MERR_ENCMISMATCH;
} else if (itemp_has(itemp, IF_REX2)) {
if (bits != 64 || !iflag_test(&cpu, IF_APX))
return MERR_ENCMISMATCH;
}
}
break;

View File

@ -180,18 +180,24 @@
#define REG_CLASS_BND GEN_REG_CLASS(9)
#define REG_CLASS_RM_TMM GEN_REG_CLASS(10)
/* Verify value to be a valid register */
static inline bool is_register(opflags_t reg)
{
return reg >= EXPR_REG_START && reg < REG_ENUM_LIMIT;
}
/* Register classes treated as vectors for EVEX/REX2 encoding purposes */
#define REG_CLASS_VECTOR (REG_CLASS_RM_XMM|REG_CLASS_RM_YMM|\
REG_CLASS_RM_ZMM|REG_CLASS_RM_TMM)
/* Helper function to test for a value matching a class */
static inline bool is_class(opflags_t class, opflags_t op)
{
return !(class & ~op);
}
static inline bool is_reg_class(opflags_t class, opflags_t reg)
/* Verify a token value is a valid register */
static inline bool is_register(int reg)
{
return reg >= EXPR_REG_START && reg < REG_ENUM_LIMIT;
}
/* Helper function to test if a token is a register matching a class */
static inline bool is_reg_class(opflags_t class, int reg)
{
if (!is_register(reg))
return false;

View File

@ -31,3 +31,45 @@
add [rdx],cl
add {evex} [rdx],cl
add {nf} [rdx],cl
add al,[rdx],r25b
add {nf} al,[rdx],r25b
add [rdx],r25b
add {evex} [rdx],r25b
add {nf} [rdx],r25b
add al,[r27],cl
add {nf} al,[r27],cl
add [r27],cl
add {evex} [r27],cl
add {nf} [r27],cl
add al,[r27],r25b
add {nf} al,[r27],r25b
add [r27],r25b
add {evex} [r27],r25b
add {nf} [r27],r25b
add eax,[rdx],ecx
add {nf} eax,[rdx],ecx
add [rdx],ecx
add {evex} [rdx],ecx
add {nf} [rdx],ecx
add eax,[rdx],r25d
add {nf} eax,[rdx],r25d
add [rdx],r25d
add {evex} [rdx],r25d
add {nf} [rdx],r25d
add eax,[r27],ecx
add {nf} eax,[r27],ecx
add [r27],ecx
add {evex} [r27],ecx
add {nf} [r27],ecx
add eax,[r27],r25d
add {nf} eax,[r27],r25d
add [r27],r25d
add {evex} [r27],r25d
add {nf} [r27],r25d

View File

@ -31,6 +31,22 @@ if_("LATEVEX", "Only if EVEX instructions are disabled");
#
if_align('FEATURE');
#
# Encoding flags
#
if_("VEX", "VEX or XOP encoded instruction");
if_("EVEX", "EVEX encoded instruction");
if_("NOAPX", "Instruction does not support APX registers");
if_("REX2", "REX2 encoding required");
if_("NF", "Instruction supports the {nf} prefix");
if_("LIG", "Ignore VEX/EVEX L field");
if_("WIG", "Ignore VEX/EVEX W field");
if_("WW", "VEX/EVEX W is REX.W");
if_("SIB", "SIB encoding required");
#
# Feature filtering flags
#
if_("PRIV", "Privileged instruction");
if_("SMM", "Only valid in SMM");
if_("PROT", "Protected mode only");
@ -40,7 +56,6 @@ if_("NOLONG", "Not available in long mode");
if_("LONG", "Long mode");
if_("NOHLE", "HLE prefixes forbidden");
if_("MIB", "split base/index EA");
if_("SIB", "SIB encoding required");
if_("BND", "BND (0xF2) prefix available");
if_("UNDOC", "Undocumented");
if_("HLE", "HLE prefixed");
@ -123,18 +138,6 @@ if_("OBSOLETE", "Instruction removed from architecture");
if_("NEVER", "Instruction never implemented");
if_("NOP", "Instruction is always a (nonintentional) NOP");
#
# Encoding flags
#
if_("VEX", "VEX or XOP encoded instruction");
if_("EVEX", "EVEX encoded instruction");
if_("REXX", "Instruction supports REX2 encoding");
if_("REX2", "Instruction requires REX2 encoding");
if_("NF", "Instruction supports the {nf} prefix");
if_("LIG", "Ignore VEX/EVEX L field");
if_("WIG", "Ignore VEX/EVEX W field");
if_("WW", "VEX/EVEX W is REX.W");
#
# special immediates types like {dfv=}
#

View File

@ -194,8 +194,8 @@ AND mem,imm32 [mi: hle o32 81 /4 id] 386,SM,LOCK
AND rm8,imm [mi: hle 82 /4 ib] 8086,SM,LOCK,ND,NOLONG
ARPL mem,reg16 [mr: 63 /r] 286,PROT,SM,NOLONG
ARPL reg16,reg16 [mr: 63 /r] 286,PROT,NOLONG
BB0_RESET void [ 0f 3a] PENT,CYRIX,ND,OBSOLETE
BB1_RESET void [ 0f 3b] PENT,CYRIX,ND,OBSOLETE
BB0_RESET void [ 0f 3a] PENT,CYRIX,NOLONG,OBSOLETE,ND
BB1_RESET void [ 0f 3b] PENT,CYRIX,NOLONG,OBSOLETE,ND
BOUND reg16,mem [rm: o16 62 /r] 186,NOLONG
BOUND reg32,mem [rm: o32 62 /r] 386,NOLONG
BSF reg16,mem [rm: o16 nof3 0f bc /r] 386,SM
@ -326,10 +326,10 @@ CMP mem,imm16 [mi: o16 81 /7 iw] 8086,SM
CMP mem,sbytedword32 [mi: o32 83 /7 ib,s] 386,SM,ND
CMP mem,imm32 [mi: o32 81 /7 id] 386,SM
CMP rm8,imm [mi: 82 /7 ib] 8086,SM,ND,NOLONG
CMPSB void [ repe a6] 8086
CMPSD void [ repe o32 a7] 386
CMPSQ void [ repe o64 a7] X86_64,LONG
CMPSW void [ repe o16 a7] 8086
CMPSB void [ repe a6] 8086,NOAPX
CMPSD void [ repe o32 a7] 386,NOAPX
CMPSQ void [ repe o64 a7] X86_64,LONG,NOAPX
CMPSW void [ repe o16 a7] 8086,NOAPX
CMPXCHG mem,reg8 [mr: hle 0f b0 /r] PENT,SM,LOCK
CMPXCHG reg8,reg8 [mr: 0f b0 /r] PENT
CMPXCHG mem,reg16 [mr: hle o16 0f b1 /r] PENT,SM,LOCK
@ -347,8 +347,8 @@ CMPXCHG486 reg32,reg32 [mr: o32 0f a7 /r] 486,UNDOC,ND,OBSOLETE
CMPXCHG8B mem64 [m: hle norexw 0f c7 /1] PENT,LOCK
CMPXCHG16B mem128 [m: o64 0f c7 /1] X86_64,LONG,LOCK
CPUID void [ 0f a2] PENT
CPU_READ void [ 0f 3d] PENT,CYRIX
CPU_WRITE void [ 0f 3c] PENT,CYRIX
CPU_READ void [ 0f 3d] PENT,CYRIX,NOAPX
CPU_WRITE void [ 0f 3c] PENT,CYRIX,NOAPX
CQO void [ o64 99] X86_64,LONG
CWD void [ o16 99] 8086
CWDE void [ o32 98] 386
@ -364,7 +364,7 @@ DIV rm8 [m: f6 /6] 8086
DIV rm16 [m: o16 f7 /6] 8086
DIV rm32 [m: o32 f7 /6] 386
DIV rm64 [m: o64 f7 /6] X86_64,LONG
DMINT void [ 0f 39] P6,CYRIX
DMINT void [ 0f 39] P6,CYRIX,NOAPX
EMMS void [ 0f 77] PENT,MMX
ENTER imm,imm [ij: c8 iw ib,u] 186
EQU imm ignore 8086
@ -1121,10 +1121,10 @@ RCR rm32,imm8 [mi: o32 c1 /3 ib,u] 386
RCR rm64,unity [m-: o64 d1 /3] X86_64,LONG
RCR rm64,reg_cl [m-: o64 d3 /3] X86_64,LONG
RCR rm64,imm8 [mi: o64 c1 /3 ib,u] X86_64,LONG
RDSHR rm32 [m: o32 0f 36 /0] P6,CYRIX,SMM
RDMSR void [ 0f 32] PENT,PRIV
RDPMC void [ 0f 33] P6
RDTSC void [ 0f 31] PENT
RDSHR rm32 [m: o32 0f 36 /0] P6,CYRIX,SMM,NOAPX
RDMSR void [ 0f 32] PENT,PRIV,NOAPX
RDPMC void [ 0f 33] P6,NOAPX
RDTSC void [ 0f 31] PENT,NOAPX
RDTSCP void [ 0f 01 f9] X86_64
RET void [ c3] 8086,BND
RET imm [i: c2 iw] 8086,SW,BND
@ -1372,8 +1372,8 @@ SVLDT mem80 [m: 0f 7a /0] 486,CYRIX,SMM,ND
SVTS mem80 [m: 0f 7c /0] 486,CYRIX,SMM
SWAPGS void [ 0f 01 f8] X86_64,LONG
SYSCALL void [ 0f 05] P6,AMD
SYSENTER void [ 0f 34] P6
SYSEXIT void [ 0f 35] P6,PRIV
SYSENTER void [ 0f 34] P6,NOAPX
SYSEXIT void [ 0f 35] P6,PRIV,NOAPX
SYSRET void [ 0f 07] P6,PRIV,AMD
TEST mem,reg8 [mr: 84 /r] 8086,SM
TEST reg8,reg8 [mr: 84 /r] 8086
@ -1432,8 +1432,8 @@ VERW mem16 [m: 0f 00 /5] 286,PROT
VERW reg16 [m: 0f 00 /5] 286,PROT
FWAIT void [ wait] 8086
WBINVD void [ 0f 09] 486,PRIV
WRSHR rm32 [m: o32 0f 37 /0] P6,CYRIX,SMM
WRMSR void [ 0f 30] PENT,PRIV
WRSHR rm32 [m: o32 0f 37 /0] P6,CYRIX,SMM,NOAPX
WRMSR void [ 0f 30] PENT,PRIV,NOAPX
XADD mem,reg8 [mr: hle 0f c0 /r] 486,SM,LOCK
XADD reg8,reg8 [mr: 0f c0 /r] 486
XADD mem,reg16 [mr: hle o16 0f c1 /r] 486,SM,LOCK
@ -1514,13 +1514,13 @@ CMOVcc reg32,mem [rm: o32 0f 40+c /r] P6,SM
CMOVcc reg32,reg32 [rm: o32 0f 40+c /r] P6
CMOVcc reg64,mem [rm: o64 0f 40+c /r] X86_64,LONG,SM
CMOVcc reg64,reg64 [rm: o64 0f 40+c /r] X86_64,LONG
Jcc imm|near [i: odf 0f 80+c rel] 386,BND
Jcc imm|near [i: odf 0f 80+c rel] 386,BND,NOAPX
Jcc imm16|near [i: o16 0f 80+c rel] 386,NOLONG,BND
Jcc imm32|near [i: o32 0f 80+c rel] 386,NOLONG,BND
Jcc imm64|near [i: o64nw 0f 80+c rel] X86_64,LONG,BND
Jcc imm64|near [i: o64nw 0f 80+c rel] X86_64,LONG,BND,NOAPX
Jcc imm|short [i: 70+c rel8] 8086,ND,BND
Jcc imm [i: jcc8 70+c rel8] 8086,ND,BND
Jcc imm [i: 0f 80+c rel] 386,ND,BND
Jcc imm [i: 0f 80+c rel] 386,ND,BND,NOAPX
Jcc imm [i: 71+c jlen e9 rel] 8086,ND,BND
Jcc imm [i: 70+c rel8] 8086,BND
@ -1616,18 +1616,18 @@ FXSAVE64 mem [m: o64 np 0f ae /0] X86_64,LONG,SSE,FPU
; of CPU feature bits.
XGETBV void [ 0f 01 d0] NEHALEM
XSETBV void [ 0f 01 d1] NEHALEM,PRIV
XSAVE mem [m: np 0f ae /4] NEHALEM
XSAVE64 mem [m: o64 np 0f ae /4] LONG,NEHALEM
XSAVEC mem [m: np 0f c7 /4] FUTURE
XSAVEC64 mem [m: o64 np 0f c7 /4] LONG,FUTURE
XSAVEOPT mem [m: np 0f ae /6] FUTURE
XSAVEOPT64 mem [m: o64 np 0f ae /6] LONG,FUTURE
XSAVES mem [m: np 0f c7 /5] FUTURE
XSAVES64 mem [m: o64 np 0f c7 /5] LONG,FUTURE
XRSTOR mem [m: np 0f ae /5] NEHALEM
XRSTOR64 mem [m: o64 np 0f ae /5] LONG,NEHALEM
XRSTORS mem [m: np 0f c7 /3] FUTURE
XRSTORS64 mem [m: o64 np 0f c7 /3] LONG,FUTURE
XSAVE mem [m: np 0f ae /4] NEHALEM,NOAPX
XSAVE64 mem [m: o64 np 0f ae /4] LONG,NEHALEM,NOAPX
XSAVEC mem [m: np 0f c7 /4] FUTURE,NOAPX
XSAVEC64 mem [m: o64 np 0f c7 /4] LONG,FUTURE,NOAPX
XSAVEOPT mem [m: np 0f ae /6] FUTURE,NOAPX
XSAVEOPT64 mem [m: o64 np 0f ae /6] LONG,FUTURE,NOAPX
XSAVES mem [m: np 0f c7 /5] FUTURE,NOAPX
XSAVES64 mem [m: o64 np 0f c7 /5] LONG,FUTURE,NOAPX
XRSTOR mem [m: np 0f ae /5] NEHALEM,NOAPX
XRSTOR64 mem [m: o64 np 0f ae /5] LONG,NEHALEM,NOAPX
XRSTORS mem [m: np 0f c7 /3] FUTURE,NOAPX
XRSTORS64 mem [m: o64 np 0f c7 /3] LONG,FUTURE,NOAPX
; These instructions are not SSE-specific; they are
;# Generic memory operations
@ -2028,7 +2028,7 @@ POPCNT reg32,rm32 [rm: o32 f3i 0f b8 /r] NEHALEM,SD
POPCNT reg64,rm64 [rm: o64 f3i 0f b8 /r] NEHALEM,SQ,LONG
;# Intel SMX
GETSEC void [ 0f 37] KATMAI
GETSEC void [ 0f 37] KATMAI,NOAPX
;# Geode (Cyrix) 3DNow! additions
PFRCPV mmxreg,mmxrm [rm: o64nw 0f 0f /r 86] PENT,3DNOW,SQ,CYRIX
@ -6436,6 +6436,9 @@ PUSHP reg64 [r: o64nw rex.w rex2 50+r ] APX
POPP reg64 [r: o64nw rex.w rex2 58+r ] APX
ADD reg8?,rm8,reg8 [vmr: evex.ndx.l0.np.m4.wig 00 /r ] APX,NF
ADD reg16?,rm16,reg16 [vmr: evex.ndx.l0.66.m4.w0 01 /r ] APX,NF
ADD reg32?,rm32,reg32 [vmr: evex.ndx.l0.np.m4.w0 01 /r ] APX,NF
ADD reg64?,rm64,reg64 [vmr: evex.ndx.l0.np.m4.w1 01 /r ] APX,NF
JMP imm|abs [i: a64 np rex2 a1 iq ] APX
JMP imm64|abs [i: a64 np rex2 a1 iq ] APX,SQ

View File

@ -591,10 +591,9 @@ sub format_insn($$$$$) {
$flagsindex = insns_flag_index(keys %flags);
die "$fname:$line: error in flags $flags\n" unless (defined($flagsindex));
# Flags that imply long mode only
if ($flags{'APX'}) {
$flags->{'LONG'}++;
}
# Flags implying each other
$flags->{'LONG'}++ if ($flags{'APX'});
$flags->{'NOAPX'}++ if ($flags{'NOLONG'});
# format the operands
$operands =~ s/[\*\?]//g;
@ -604,6 +603,7 @@ sub format_insn($$$$$) {
@decos = ();
if ($operands ne 'void') {
foreach $op (split(/,/, $operands)) {
my $iszero = 0;
my $opsz = 0;
@opx = ();
@opevex = ();
@ -613,15 +613,21 @@ sub format_insn($$$$$) {
push(@opevex, $1);
}
if ($opp =~ s/(?<!\d)(8|16|32|64|80|128|256|512)$//) {
push(@oppx, "bits$1");
if ($opp =~ s/([^0-9]0?)(8|16|32|64|80|128|256|512|1024|1k)$/$1/) {
push(@oppx, "bits$2");
$opsz = $1 + 0;
}
if ($opp =~ s/0$//) {
push(@oppx, 'rm_zero');
$iszero = 1;
if ($opp !~ /reg/) {
$opp .= 'reg';
}
}
$opp =~ s/^mem$/memory/;
$opp =~ s/^memory_offs$/mem_offs/;
if ($opp =~ /^(spec|imm)4$/) {
if ($opp =~ s/^(spec|imm)4$/$1/) {
push(@oppx, 'fourbits');
$opp = $1;
}
$opp =~ s/^spec$/immediate/; # Immediate or special immediate
$opp =~ s/^imm$/imm_normal/; # Normal immediates only
@ -629,20 +635,15 @@ sub format_insn($$$$$) {
push(@oppx, 'imm_normal');
}
$opp =~ s/^([a-z]+)rm$/rm_$1/;
$opp =~ s/^rm$/rm_gpr/;
$opp =~ s/^reg$/reg_gpr/;
# only for evex and rex2 insns, high-16 GPR or creg regs are allowed
unless ($flags{'EVEX'} || $flags{'REX2'}) {
if ($opp =~ /^(rm_gpr|reg_gpr|reg_[cd]reg)$/) {
push(@oppx, 'rn_l16'); # Register number must be < 16
}
}
# only for evex, high vector registers are allowed
unless ($flags{'EVEX'}) {
if ($opp =~ /^[xyz]mm(reg|rm)$/) {
push(@oppx, 'rn_l16'); # Register number must be < 16
}
}
$opp =~ s/^(rm|reg)$/$1_gpr/;
$opp =~ s/^rm_k$/rm_opmask/;
$opp =~ s/^kreg$/opmaskreg/;
my $isreg = ($opp =~ /(\brm_|\breg_|reg\b)/);
my $isvec = ($opp =~ /\b[xyzt]mm/);
if ($isreg && !(($flags{'EVEX'} && $isvec) || !$flags{'NOAPX'})) {
# Register numbers >= 16 disallowed
push(@oppx, 'rn_l16');
}
push(@opx, $opp, @oppx) if $opp;
}
$op = join('|', @opx);
@ -693,7 +694,7 @@ sub format_insn($$$$$) {
foreach my $sf (keys(%sflags)) {
next if (!$flags{$sf});
for (my $i = $s; $i <= $e; $i++) {
if ($opsize[$i] && $ops[$i] !~ /\breg_(gpr|[cdts]reg)\b/) {
if ($opsize[$i] && $ops[$i] !~ /(\breg_|reg\b)/) {
die "$fname:$line: inconsistent $sf flag for argument $i ($ops[$i])\n"
if ($opsize[$i] != $sflags{$sf});
}
@ -1210,6 +1211,7 @@ sub byte_code_compile($$$) {
($c << 6)+$m, ($w << 7)+($l << 2)+$p);
$flags->{'VEX'}++;
$flags->{'NOAPX'}++; # VEX doesn't support registers 16+
$prefix_ok = 0;
} elsif ($op =~ /^(evex)(|\..*)$/) {
my $c = $vexmap{$1};
@ -1319,10 +1321,9 @@ sub byte_code_compile($$$) {
$flags->{'EVEX'}++;
$prefix_ok = 0;
} elsif ($op =~ /^(rex2(\??))(\..*)?$/) {
} elsif ($op =~ /^(rex2)(\..*)?$/) {
my $name = $1;
my $optional = $2 eq '?';
my @subops = split(/\./, $3);
my @subops = split(/\./, $2);
my $c = 0350;
my $m = undef;
foreach $oq (@subops) {
@ -1339,12 +1340,10 @@ sub byte_code_compile($$$) {
}
}
if (!$optional) {
push(@codes, $c);
$flags->{'APX'}++;
$flags->{'LONG'}++;
}
push(@codes, $c);
$flags->{'APX'}++;
$flags->{'REX2'}++;
$flags->{'LONG'}++;
$prefix_ok = 0;
} elsif (defined $imm_codes{$op}) {
if ($op eq 'seg') {
@ -1399,5 +1398,10 @@ sub byte_code_compile($$$) {
}
}
# Legacy maps 2+ do not support REX2 encodings
if ($opmap > 1 && !$flags{'EVEX'}) {
$flags->{'NOAPX'}++;
}
return @codes;
}