in js/src/wasm/WasmSummarizeInsn.cpp [81:641]
Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insn) {
const bool is64bit = sizeof(void*) == 8;
// First off, use up the prefix bytes, so we wind up pointing `insn` at the
// primary opcode byte, and at the same time accumulate the prefixes in
// `prefixes`.
uint32_t prefixes = 0;
bool hasREX = false;
bool hasVEX = false;
// Parse the "legacy" prefixes (only those we care about). Skip REX on
// 32-bit x86.
while (true) {
if (insn[0] >= 0x40 && insn[0] <= 0x4F && is64bit) {
hasREX = true;
// It has a REX prefix, but is REX.W set?
if (insn[0] >= 0x48) {
prefixes |= PfxRexW;
}
insn++;
continue;
}
if (insn[0] == 0x66) {
prefixes |= Pfx66;
insn++;
continue;
}
if (insn[0] == 0xF0) {
prefixes |= PfxLock;
insn++;
continue;
}
if (insn[0] == 0xF2) {
prefixes |= PfxF2;
insn++;
continue;
}
if (insn[0] == 0xF3) {
prefixes |= PfxF3;
insn++;
continue;
}
if (insn[0] == 0xC4 || insn[0] == 0xC5) {
hasVEX = true;
// And fall through to the `break`, leaving `insn` pointing at the start
// of the VEX prefix.
}
break;
}
// Throw out some invalid prefix combinations.
if (hasAllOf(prefixes, PfxF2 | PfxF3) || (hasREX && hasVEX)) {
return Nothing();
}
if (!hasVEX) {
// The instruction has legacy prefixes only. Deal with all these cases
// first.
// Determine the data size (in bytes) for "standard form" non-SIMD, non-FP
// instructions whose opcode byte(s) don't directly imply an 8-bit
// operation. If both REX.W and 0x66 are present then REX.W "wins".
int opSize = 4;
if (prefixes & Pfx66) {
opSize = 2;
}
if (prefixes & PfxRexW) {
MOZ_ASSERT(is64bit);
opSize = 8;
}
// `insn` should now point at the primary opcode, at least for the cases
// we care about. Start identifying instructions. The OP_/OP2_/OP3_
// comments are references to names as declared in Encoding-x86-shared.h.
// This is the most common trap insn, so deal with it early. Created by
// MacroAssembler::wasmTrapInstruction.
// OP_2BYTE_ESCAPE OP2_UD2
// 0F 0B = ud2
if (insn[0] == 0x0F && insn[1] == 0x0B && isEmpty(prefixes)) {
return Some(TrapMachineInsn::OfficialUD);
}
// ==== Atomics
// This is something of a kludge, but .. if the insn has a LOCK prefix,
// declare it to be TrapMachineInsn::Atomic, regardless of what it
// actually does. It's good enough for checking purposes.
if (prefixes & PfxLock) {
return Some(TrapMachineInsn::Atomic);
}
// After this point, we can assume that no instruction has a lock prefix.
// OP_XCHG_GbEb
// OP_XCHG_GvEv
// 86 = XCHG reg8, reg8/mem8.
// 87 = XCHG reg64/32/16, reg64/32/16 / mem64/32/16.
// The memory variants are atomic even though there is no LOCK prefix.
if (insn[0] == 0x86 && ModRMisM(insn[1]) && isEmpty(prefixes)) {
return Some(TrapMachineInsn::Atomic);
}
if (insn[0] == 0x87 && ModRMisM(insn[1]) &&
hasOnly(prefixes, Pfx66 | PfxRexW)) {
return Some(TrapMachineInsn::Atomic);
}
// ==== Scalar loads and stores
// OP_MOV_EbGv
// OP_MOV_GvEb
// 88 = MOV src=reg, dst=mem/reg (8 bit int only)
// 8A = MOV src=mem/reg, dst=reg (8 bit int only)
if ((insn[0] == 0x88 || insn[0] == 0x8A) && ModRMisM(insn[1]) &&
isEmpty(prefixes)) {
return Some(insn[0] == 0x88 ? TrapMachineInsn::Store8
: TrapMachineInsn::Load8);
}
// OP_MOV_EvGv
// OP_MOV_GvEv
// 89 = MOV src=reg, dst=mem/reg (64/32/16 bit int only)
// 8B = MOV src=mem/reg, dst=reg (64/32/16 bit int only)
if ((insn[0] == 0x89 || insn[0] == 0x8B) && ModRMisM(insn[1]) &&
hasOnly(prefixes, Pfx66 | PfxRexW)) {
return Some(insn[0] == 0x89 ? TrapMachineInsnForStore(opSize)
: TrapMachineInsnForLoad(opSize));
}
// OP_GROUP11_EvIb GROUP11_MOV
// C6 /0 = MOV src=immediate, dst=mem (8 bit int only)
if (insn[0] == 0xC6 && ModRMisM(insn[1]) && ModRMmid3(insn[1]) == 0 &&
isEmpty(prefixes)) {
return Some(TrapMachineInsn::Store8);
}
// OP_GROUP11_EvIz GROUP11_MOV
// C7 /0 = MOV src=immediate, dst=mem (64/32/16 bit int only)
if (insn[0] == 0xC7 && ModRMisM(insn[1]) && ModRMmid3(insn[1]) == 0 &&
hasOnly(prefixes, Pfx66 | PfxRexW)) {
return Some(TrapMachineInsnForStore(opSize));
}
// OP_2BYTE_ESCAPE OP2_MOVZX_GvEb
// OP_2BYTE_ESCAPE OP2_MOVSX_GvEb
// 0F B6 = MOVZB{W,L,Q} src=reg/mem, dst=reg (8 -> 16, 32 or 64, int only)
// 0F BE = MOVSB{W,L,Q} src=reg/mem, dst=reg (8 -> 16, 32 or 64, int only)
if (insn[0] == 0x0F && (insn[1] == 0xB6 || insn[1] == 0xBE) &&
ModRMisM(insn[2]) && (opSize == 2 || opSize == 4 || opSize == 8) &&
hasOnly(prefixes, Pfx66 | PfxRexW)) {
return Some(TrapMachineInsn::Load8);
}
// OP_2BYTE_ESCAPE OP2_MOVZX_GvEw
// OP_2BYTE_ESCAPE OP2_MOVSX_GvEw
// 0F B7 = MOVZW{L,Q} src=reg/mem, dst=reg (16 -> 32 or 64, int only)
// 0F BF = MOVSW{L,Q} src=reg/mem, dst=reg (16 -> 32 or 64, int only)
if (insn[0] == 0x0F && (insn[1] == 0xB7 || insn[1] == 0xBF) &&
ModRMisM(insn[2]) && (opSize == 4 || opSize == 8) &&
hasOnly(prefixes, PfxRexW)) {
return Some(TrapMachineInsn::Load16);
}
// OP_MOVSXD_GvEv
// REX.W 63 = MOVSLQ src=reg32/mem32, dst=reg64
if (hasAllOf(prefixes, PfxRexW) && insn[0] == 0x63 && ModRMisM(insn[1]) &&
hasOnly(prefixes, Pfx66 | PfxRexW)) {
return Some(TrapMachineInsn::Load32);
}
// ==== SSE{2,3,E3,4} insns
// OP_2BYTE_ESCAPE OP2_MOVPS_VpsWps
// OP_2BYTE_ESCAPE OP2_MOVPS_WpsVps
// 0F 10 = MOVUPS src=xmm/mem128, dst=xmm
// 0F 11 = MOVUPS src=xmm, dst=xmm/mem128
if (insn[0] == 0x0F && (insn[1] == 0x10 || insn[1] == 0x11) &&
ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
return Some(insn[1] == 0x10 ? TrapMachineInsn::Load128
: TrapMachineInsn::Store128);
}
// OP_2BYTE_ESCAPE OP2_MOVLPS_VqEq
// OP_2BYTE_ESCAPE OP2_MOVHPS_VqEq
// 0F 12 = MOVLPS src=xmm64/mem64, dst=xmm
// 0F 16 = MOVHPS src=xmm64/mem64, dst=xmm
if (insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16) &&
ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
return Some(TrapMachineInsn::Load64);
}
// OP_2BYTE_ESCAPE OP2_MOVLPS_EqVq
// OP_2BYTE_ESCAPE OP2_MOVHPS_EqVq
// 0F 13 = MOVLPS src=xmm64, dst=xmm64/mem64
// 0F 17 = MOVHPS src=xmm64, dst=xmm64/mem64
if (insn[0] == 0x0F && (insn[1] == 0x13 || insn[1] == 0x17) &&
ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
return Some(TrapMachineInsn::Store64);
}
// PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVSD_VsdWsd
// PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVSD_WsdVsd
// F2 0F 10 = MOVSD src=mem64/xmm64, dst=xmm64
// F2 0F 11 = MOVSD src=xmm64, dst=mem64/xmm64
if (hasAllOf(prefixes, PfxF2) && insn[0] == 0x0F &&
(insn[1] == 0x10 || insn[1] == 0x11) && ModRMisM(insn[2]) &&
hasOnly(prefixes, PfxRexW | PfxF2)) {
return Some(insn[1] == 0x10 ? TrapMachineInsn::Load64
: TrapMachineInsn::Store64);
}
// PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVDDUP_VqWq
// F2 0F 12 = MOVDDUP src=mem64/xmm64, dst=xmm
if (hasAllOf(prefixes, PfxF2) && insn[0] == 0x0F && insn[1] == 0x12 &&
ModRMisM(insn[2]) && hasOnly(prefixes, PfxF2)) {
return Some(TrapMachineInsn::Load64);
}
// PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVSS_VssWss (name does not exist)
// PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVSS_WssVss (name does not exist)
// F3 0F 10 = MOVSS src=mem32/xmm32, dst=xmm32
// F3 0F 11 = MOVSS src=xmm32, dst=mem32/xmm32
if (hasAllOf(prefixes, PfxF3) && insn[0] == 0x0F &&
(insn[1] == 0x10 || insn[1] == 0x11) && ModRMisM(insn[2]) &&
hasOnly(prefixes, PfxRexW | PfxF3)) {
return Some(insn[1] == 0x10 ? TrapMachineInsn::Load32
: TrapMachineInsn::Store32);
}
// PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVDQ_VdqWdq
// PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVDQ_WdqVdq
// F3 0F 6F = MOVDQU src=mem128/xmm, dst=xmm
// F3 0F 7F = MOVDQU src=xmm, dst=mem128/xmm
if (hasAllOf(prefixes, PfxF3) && insn[0] == 0x0F &&
(insn[1] == 0x6F || insn[1] == 0x7F) && ModRMisM(insn[2]) &&
hasOnly(prefixes, PfxF3)) {
return Some(insn[1] == 0x6F ? TrapMachineInsn::Load128
: TrapMachineInsn::Store128);
}
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PINSRB_VdqEvIb
// 66 0F 3A 20 /r ib = PINSRB $imm8, src=mem8/ireg8, dst=xmm128. I'd guess
// that REX.W is meaningless here and therefore we should exclude it.
if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
insn[2] == 0x20 && ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
return Some(TrapMachineInsn::Load8);
}
// PRE_SSE_66 OP_2BYTE_ESCAPE OP2_PINSRW
// 66 0F C4 /r ib = PINSRW $imm8, src=mem16/ireg16, dst=xmm128. REX.W is
// probably meaningless here.
if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0xC4 &&
ModRMisM(insn[2]) && hasOnly(prefixes, Pfx66)) {
return Some(TrapMachineInsn::Load16);
}
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_INSERTPS_VpsUps
// 66 0F 3A 21 /r ib = INSERTPS $imm8, src=mem32/xmm32, dst=xmm128.
// REX.W is probably meaningless here.
if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
insn[2] == 0x21 && ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
return Some(TrapMachineInsn::Load32);
}
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PEXTRB_EvVdqIb
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PEXTRW_EwVdqIb
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_EXTRACTPS_EdVdqIb
// 66 0F 3A 14 /r ib = PEXTRB src=xmm8, dst=reg8/mem8
// 66 0F 3A 15 /r ib = PEXTRW src=xmm16, dst=reg16/mem16
// 66 0F 3A 17 /r ib = EXTRACTPS src=xmm32, dst=reg32/mem32
// REX.W is probably meaningless here.
if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
(insn[2] == 0x14 || insn[2] == 0x15 || insn[2] == 0x17) &&
ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
return Some(insn[2] == 0x14 ? TrapMachineInsn::Store8
: insn[2] == 0x15 ? TrapMachineInsn::Store16
: TrapMachineInsn::Store32);
}
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXBW_VdqWdq
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXWD_VdqWdq
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXDQ_VdqWdq
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXBW_VdqWdq
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXWD_VdqWdq
// PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXDQ_VdqWdq
// 66 0F 38 20 /r = PMOVSXBW src=mem64/xmm64, dst=xmm
// 66 0F 38 23 /r = PMOVSXWD src=mem64/xmm64, dst=xmm
// 66 0F 38 25 /r = PMOVSXDQ src=mem64/xmm64, dst=xmm
// 66 0F 38 30 /r = PMOVZXBW src=mem64/xmm64, dst=xmm
// 66 0F 38 33 /r = PMOVZXWD src=mem64/xmm64, dst=xmm
// 66 0F 38 35 /r = PMOVZXDQ src=mem64/xmm64, dst=xmm
if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x38 &&
(insn[2] == 0x20 || insn[2] == 0x23 || insn[2] == 0x25 ||
insn[2] == 0x30 || insn[2] == 0x33 || insn[2] == 0x35) &&
ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
return Some(TrapMachineInsn::Load64);
}
// The insn only has legacy prefixes, and was not identified.
return Nothing();
}
// We're dealing with a VEX-prefixed insn. Fish out relevant bits of the
// VEX prefix. VEX prefixes come in two kinds: a 3-byte prefix, first byte
// 0xC4, which gives us 16 bits of extra data, and a 2-byte prefix, first
// byte 0xC5, which gives us 8 bits of extra data. The 2-byte variant
// contains a subset of the data that the 3-byte variant does and
// (presumably) is to be used when the default values of the omitted fields
// are correct for the instruction that is encoded.
//
// An instruction can't have both VEX and REX prefixes, because a 3-byte VEX
// prefix specifies everything a REX prefix does, that is, the four bits
// REX.{WRXB} and allowing both to be present would allow conflicting values
// for them. Of these four bits, we only care about REX.W (as obtained here
// from the VEX prefix).
//
// A VEX prefix can also specify (imply?) the presence of the legacy
// prefixes 66, F2 and F3. Although the byte sequence we will have parsed
// for this insn doesn't actually contain any of those, we must decode as if
// we had seen them as legacy prefixes.
//
// A VEX prefix can also specify (imply?) the presence of the opcode escape
// byte sequences 0F, 0F38 and 0F3A. These are collected up into `esc`.
// Again, we must decode as if we had actually seen these, although we
// haven't really.
//
// The VEX prefix also holds various other bits which we ignore, because
// these specify details of registers etc which we don't care about.
MOZ_ASSERT(hasVEX && !hasREX);
MOZ_ASSERT(hasNoneOf(prefixes, PfxRexW));
MOZ_ASSERT(insn[0] == 0xC4 || insn[0] == 0xC5);
Escape esc = EscNone;
if (insn[0] == 0xC4) {
// This is a 3-byte VEX prefix (3 bytes including the 0xC4).
switch (insn[1] & 0x1F) {
case 1:
esc = Esc0F;
break;
case 2:
esc = Esc0F38;
break;
case 3:
esc = Esc0F3A;
break;
default:
return Nothing();
}
switch (insn[2] & 3) {
case 0:
break;
case 1:
prefixes |= Pfx66;
break;
case 2:
prefixes |= PfxF3;
break;
case 3:
prefixes |= PfxF2;
break;
}
if (insn[2] & 4) {
// VEX.L distinguishes 128-bit (VEX.L==0) from 256-bit (VEX.L==1)
// operations.
prefixes |= PfxVexL;
}
if ((insn[2] & 0x80) && is64bit) {
// Pull out REX.W, but only on 64-bit targets. We'll need it for insn
// decoding. Recall that REX.W == 1 basically means "the
// integer-register (GPR) aspect of this instruction requires a 64-bit
// transaction", so we expect these to be relatively rare, since VEX is
// primary used for SIMD instructions.
prefixes |= PfxRexW;
}
// Step forwards to the primary opcode byte
insn += 3;
} else if (insn[0] == 0xC5) {
// This is a 2-byte VEX prefix (2 bytes including the 0xC5). Since it has
// only 8 bits of useful payload, it adds less information than an 0xC4
// prefix.
esc = Esc0F;
switch (insn[1] & 3) {
case 0:
break;
case 1:
prefixes |= Pfx66;
break;
case 2:
prefixes |= PfxF3;
break;
case 3:
prefixes |= PfxF2;
break;
}
if (insn[1] & 4) {
prefixes |= PfxVexL;
}
insn += 2;
}
// This isn't allowed.
if (hasAllOf(prefixes, PfxF2 | PfxF3)) {
return Nothing();
}
// This is useful for diagnosing decoding failures.
// if (0) {
// fprintf(stderr, "FAIL VEX 66=%d,F2=%d,F3=%d,REXW=%d,VEXL=%d esc=%s\n",
// (prefixes & Pfx66) ? 1 : 0, (prefixes & PfxF2) ? 1 : 0,
// (prefixes & PfxF3) ? 1 : 0, (prefixes & PfxRexW) ? 1 : 0,
// (prefixes & PfxVexL) ? 1 : 0,
// esc == Esc0F3A ? "0F3A"
// : esc == Esc0F38 ? "0F38"
// : esc == Esc0F ? "0F"
// : "none");
// }
// (vex prefix) OP2_MOVPS_VpsWps
// (vex prefix) OP2_MOVPS_WpsVps
// 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 10 = VMOVUPS src=xmm/mem128, dst=xmm
// 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 11 = VMOVUPS src=xmm, dst=xmm/mem128
// REX.W is ignored.
if (hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F && (insn[0] == 0x10 || insn[0] == 0x11) &&
ModRMisM(insn[1])) {
return Some(insn[0] == 0x10 ? TrapMachineInsn::Load128
: TrapMachineInsn::Store128);
}
// (vex prefix) OP2_MOVSD_VsdWsd
// (vex prefix) OP2_MOVSD_WsdVsd
// 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 10 = VMOVSD src=mem64, dst=xmm
// 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 11 = VMOVSD src=xmm, dst=mem64
// REX.W and VEX.L are ignored.
if (hasAllOf(prefixes, PfxF2) &&
hasNoneOf(prefixes, Pfx66 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
(insn[0] == 0x10 || insn[0] == 0x11) && ModRMisM(insn[1])) {
return Some(insn[0] == 0x10 ? TrapMachineInsn::Load64
: TrapMachineInsn::Store64);
}
// (vex prefix) OP2_MOVSS_VssWss (name does not exist)
// (vex prefix) OP2_MOVSS_WssVss (name does not exist)
// 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 10 = VMOVSS src=mem32, dst=xmm
// 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 11 = VMOVSS src=xmm, dst=mem32
// REX.W and VEX.L are ignored.
if (hasAllOf(prefixes, PfxF3) &&
hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxRexW | PfxVexL) && esc == Esc0F &&
(insn[0] == 0x10 || insn[0] == 0x11) && ModRMisM(insn[1])) {
return Some(insn[0] == 0x10 ? TrapMachineInsn::Load32
: TrapMachineInsn::Store32);
}
// (vex prefix) OP2_MOVDDUP_VqWq
// 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 12 = VMOVDDUP src=xmm/m64, dst=xmm
// REX.W is ignored.
if (hasAllOf(prefixes, PfxF2) &&
hasNoneOf(prefixes, Pfx66 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
insn[0] == 0x12 && ModRMisM(insn[1])) {
return Some(TrapMachineInsn::Load64);
}
// (vex prefix) OP2_MOVLPS_EqVq
// (vex prefix) OP2_MOVHPS_EqVq
// 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 13 = VMOVLPS src=xmm, dst=mem64
// 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 17 = VMOVHPS src=xmm, dst=mem64
// REX.W is ignored. These do a 64-bit mem transaction despite the 'S' in
// the name, because a pair of float32s are transferred.
if (hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F && (insn[0] == 0x13 || insn[0] == 0x17) &&
ModRMisM(insn[1])) {
return Some(TrapMachineInsn::Store64);
}
// (vex prefix) OP2_MOVDQ_VdqWdq
// (vex prefix) OP2_MOVDQ_WdqVdq
// 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 6F = VMOVDQU src=xmm/mem128, dst=xmm
// 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 7F = VMOVDQU src=xmm, dst=xmm/mem128
// REX.W is ignored.
if (hasAllOf(prefixes, PfxF3) &&
hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxRexW | PfxVexL) && esc == Esc0F &&
(insn[0] == 0x6F || insn[0] == 0x7F) && ModRMisM(insn[1])) {
return Some(insn[0] == 0x6F ? TrapMachineInsn::Load128
: TrapMachineInsn::Store128);
}
// (vex prefix) OP2_PINSRW
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=OF C4
// = PINSRW src=ireg/mem16,src=xmm,dst=xmm
// REX.W is ignored.
if (hasAllOf(prefixes, Pfx66) &&
hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
insn[0] == 0xC4 && ModRMisM(insn[1])) {
return Some(TrapMachineInsn::Load16);
}
// (vex prefix) OP3_PMOVSXBW_VdqWdq
// (vex prefix) OP3_PMOVSXWD_VdqWdq
// (vex prefix) OP3_PMOVSXDQ_VdqWdq
// (vex prefix) OP3_PMOVZXBW_VdqWdq
// (vex prefix) OP3_PMOVZXWD_VdqWdq
// (vex prefix) OP3_PMOVZXDQ_VdqWdq
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 20 = VPMOVSXBW src=xmm/m64, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 23 = VPMOVSXWD src=xmm/m64, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 25 = VPMOVSXDQ src=xmm/m64, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 30 = VPMOVZXBW src=xmm/m64, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 33 = VPMOVZXWD src=xmm/m64, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 35 = VPMOVZXDQ src=xmm/m64, dst=xmm
// REX.W is ignored.
if (hasAllOf(prefixes, Pfx66) &&
hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F38 &&
(insn[0] == 0x20 || insn[0] == 0x23 || insn[0] == 0x25 ||
insn[0] == 0x30 || insn[0] == 0x33 || insn[0] == 0x35) &&
ModRMisM(insn[1])) {
return Some(TrapMachineInsn::Load64);
}
// (vex prefix) OP3_VBROADCASTB_VxWx
// (vex prefix) OP3_VBROADCASTW_VxWx
// (vex prefix) OP3_VBROADCASTSS_VxWd
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 78
// = VPBROADCASTB src=xmm8/mem8, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 79
// = VPBROADCASTW src=xmm16/mem16, dst=xmm
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 18
// = VBROADCASTSS src=m32, dst=xmm
// VPBROADCASTB/W require REX.W == 0; VBROADCASTSS ignores REX.W.
if (hasAllOf(prefixes, Pfx66) &&
hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F38 &&
(insn[0] == 0x78 || insn[0] == 0x79 || insn[0] == 0x18) &&
ModRMisM(insn[1])) {
return Some(insn[0] == 0x78 ? TrapMachineInsn::Load8
: insn[0] == 0x79 ? TrapMachineInsn::Load16
: TrapMachineInsn::Load32);
}
// (vex prefix) OP3_PEXTRB_EvVdqIb
// (vex prefix) OP3_PEXTRW_EwVdqIb
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 14 = VPEXTRB src=xmm, dst=ireg/mem8
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 15 = VPEXTRW src=xmm, dst=ireg/mem16
// These require REX.W == 0.
if (hasAllOf(prefixes, Pfx66) &&
hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F3A && (insn[0] == 0x14 || insn[0] == 0x15) &&
ModRMisM(insn[1])) {
return Some(insn[0] == 0x14 ? TrapMachineInsn::Store8
: TrapMachineInsn::Store16);
}
// (vex prefix) OP3_EXTRACTPS_EdVdqIb
// 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 17
// = VEXTRACTPS src=xmm, dst=ireg/mem32
// REX.W is ignored.
if (hasAllOf(prefixes, Pfx66) &&
hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
esc == Esc0F3A && insn[0] == 0x17 && ModRMisM(insn[1])) {
return Some(TrapMachineInsn::Store32);
}
// The instruction was not identified.
return Nothing();
}