use crate::AsmError;
use crate::core::arch_traits::Arch;
use crate::core::globals::InstOptions;
use crate::core::inst::Inst;
use crate::core::operand::{Imm, Operand, OperandType, RegGroup, RegType};
use crate::core::rwinfo::{
CpuRwFlags, INVALID_PHYS_ID, InstRwFlags, InstRwInfo, InstSameRegHint, OpRwFlags, OpRwInfo,
};
use super::instdb::{
ADDITIONAL_INFO_TABLE, Avx512Flags, CommonInfo, INST_COMMON_INFO_TABLE, INST_FLAGS_TABLE,
INST_INFO_TABLE, InstId, InstInfo, RW_FLAGS_INFO_TABLE, RW_INFO_A_TABLE, RW_INFO_B_TABLE,
RW_INFO_INDEX_A_TABLE, RW_INFO_INDEX_B_TABLE, RW_INFO_OP_TABLE, RW_INFO_RM_TABLE,
RwInfoCategory, RwInfoRmCategory, RwInfoRmFlags,
};
use super::operands::{Gp, Mem};
const NATIVE_GP_SIZE: u32 = 8;
const R: OpRwFlags = OpRwFlags::READ;
const W: OpRwFlags = OpRwFlags::WRITE;
const X: OpRwFlags = OpRwFlags::RW;
const REG_M: OpRwFlags = OpRwFlags::REG_MEM;
const REG_PHYS: OpRwFlags = OpRwFlags::REG_PHYS_ID;
const MIB_READ: OpRwFlags =
OpRwFlags::from_bits_retain(OpRwFlags::MEM_BASE_READ.bits() | OpRwFlags::MEM_INDEX_READ.bits());
pub fn query_rw_info(inst: &Inst) -> Result<InstRwInfo, AsmError> {
if !matches!(inst.arch(), Arch::X86 | Arch::X64) {
return Err(AsmError::InvalidArch);
}
let inst_id = inst.id as usize;
if inst_id >= INST_INFO_TABLE.len() {
return Err(AsmError::InvalidInstruction);
}
let inst_info = &INST_INFO_TABLE[inst_id];
let common_info = &INST_COMMON_INFO_TABLE[inst_info.common_info_index as usize];
let mut out = InstRwInfo::new();
query_rw_info_internal(inst, inst_info, common_info, &mut out)?;
apply_same_reg_hint(inst, common_info, &mut out);
Ok(out)
}
const fn lsb_mask_u64(n: u32) -> u64 {
if n >= 64 {
u64::MAX
} else {
(1u64 << n).wrapping_sub(1)
}
}
const fn fill_trailing_bits(value: u64) -> u64 {
let leading = (value | 1).leading_zeros();
((u64::MAX >> 1) >> leading) | value
}
const fn reg_group_byte_mask(group: RegGroup) -> u64 {
match group {
RegGroup::Gp => 0xFF,
RegGroup::Vec => u64::MAX,
RegGroup::X86MM => 0xFF,
RegGroup::X86K => 0xFF,
RegGroup::X86SReg => 0x03,
RegGroup::X86CReg => 0xFF,
RegGroup::X86DReg => 0xFF,
RegGroup::X86St => 0x03FF,
RegGroup::X86Bnd => 0xFFFF,
RegGroup::X86Rip => 0xFF,
RegGroup::X86Tmm => 0,
}
}
fn reset_op(op: &mut OpRwInfo, op_flags: OpRwFlags, register_size: u32, phys_id: u8) {
op.op_flags = op_flags;
op.phys_id = phys_id;
op.rm_size = if op_flags.contains(OpRwFlags::REG_MEM) {
register_size as u8
} else {
0
};
op.consecutive_lead_count = 0;
let mask = lsb_mask_u64(register_size.min(64));
op.read_byte_mask = if op_flags.contains(OpRwFlags::READ) {
mask
} else {
0
};
op.write_byte_mask = if op_flags.contains(OpRwFlags::WRITE) {
mask
} else {
0
};
op.extend_byte_mask = 0;
}
fn rw_zero_extend_gp(op: &mut OpRwInfo, reg: &Operand, native_gp_size: u32) {
if reg.x86_rm_size() + 4 == native_gp_size {
op.op_flags |= OpRwFlags::ZEXT;
op.extend_byte_mask = !op.write_byte_mask & 0xFF;
}
}
fn rw_zero_extend_avx_vec(op: &mut OpRwInfo) {
let msk = !fill_trailing_bits(op.write_byte_mask);
if msk != 0 {
op.op_flags |= OpRwFlags::ZEXT;
op.extend_byte_mask = msk;
}
}
fn rw_zero_extend_non_vec(op: &mut OpRwInfo, reg: &Operand) {
let msk =
!fill_trailing_bits(op.write_byte_mask) & reg_group_byte_mask(reg.signature.reg_group());
if msk != 0 {
op.op_flags |= OpRwFlags::ZEXT;
op.extend_byte_mask = msk;
}
}
fn rw_handle_avx512(inst: &Inst, common_info: &CommonInfo, out: &mut InstRwInfo) {
if inst.extra_reg.is_reg() && inst.extra_reg.is_reg_type_of(RegType::Mask) && out.op_count > 0 {
out.extra_reg.op_flags |= OpRwFlags::READ;
out.extra_reg.read_byte_mask = 0xFF;
if !inst.options.contains(InstOptions::X86_ZMASK)
&& !common_info.has_avx512_flag(Avx512Flags::IMPLICIT_Z)
{
out.operands[0].op_flags |= OpRwFlags::READ;
out.operands[0].read_byte_mask |= out.operands[0].write_byte_mask;
}
}
}
fn has_same_reg_type(operands: &[Operand]) -> bool {
debug_assert!(!operands.is_empty());
let reg_type = operands[0].signature.reg_type();
operands[1..]
.iter()
.all(|op| op.signature.reg_type() == reg_type)
}
fn apply_same_reg_hint(inst: &Inst, common_info: &CommonInfo, out: &mut InstRwInfo) {
let hint = common_info.same_reg_hint;
if hint == InstSameRegHint::None || out.op_count < 2 {
return;
}
let operands = inst.operands();
if !operands[0].is_reg() {
return;
}
let id0 = operands[0].id();
let type0 = operands[0].signature.reg_type();
let all_same = operands[1..]
.iter()
.all(|op| op.is_reg() && op.id() == id0 && op.signature.reg_type() == type0);
if !all_same {
return;
}
for op in out.operands_mut() {
match hint {
InstSameRegHint::RO => {
op.op_flags &= !(OpRwFlags::WRITE | OpRwFlags::ZEXT);
op.write_byte_mask = 0;
op.extend_byte_mask = 0;
}
InstSameRegHint::WO => {
op.op_flags &= !OpRwFlags::READ;
op.read_byte_mask = 0;
}
InstSameRegHint::None => {}
}
}
}
fn query_rw_info_internal(
inst: &Inst,
inst_info: &InstInfo,
common_info: &CommonInfo,
out: &mut InstRwInfo,
) -> Result<(), AsmError> {
let operands = inst.operands();
let op_count = operands.len();
let additional_info = &ADDITIONAL_INFO_TABLE[inst_info.additional_info_index as usize];
let rw_flags = &RW_FLAGS_INFO_TABLE[additional_info.rw_flags_index as usize];
let inst_id = inst.id as usize;
let inst_rw_info = if op_count == 2 {
&RW_INFO_A_TABLE[RW_INFO_INDEX_A_TABLE[inst_id] as usize]
} else {
&RW_INFO_B_TABLE[RW_INFO_INDEX_B_TABLE[inst_id] as usize]
};
let inst_rm_info = &RW_INFO_RM_TABLE[inst_rw_info.rm_info as usize];
out.inst_flags = INST_FLAGS_TABLE[additional_info.inst_flags_index as usize];
out.op_count = op_count as u8;
out.rm_feature = inst_rm_info.rm_feature;
out.extra_reg = OpRwInfo::new();
out.read_flags = CpuRwFlags::from_bits_retain(rw_flags.read_flags);
out.write_flags = CpuRwFlags::from_bits_retain(rw_flags.write_flags);
let mut op_type_mask: u32 = 0;
if (inst_rw_info.category as u8) <= (RwInfoCategory::GenericEx as u8) {
let mut rm_ops_mask: u32 = 0;
let mut rm_max_size: u32 = 0;
for i in 0..op_count {
let src_op = &operands[i];
let rw_op_data = &RW_INFO_OP_TABLE[inst_rw_info.op_info_index[i] as usize];
op_type_mask |= 1u32 << (src_op.op_type() as u32);
let op = &mut out.operands[i];
if !src_op.is_reg_or_mem() {
*op = OpRwInfo::new();
continue;
}
op.op_flags = rw_op_data.flags & !OpRwFlags::ZEXT;
op.phys_id = rw_op_data.phys_id;
op.rm_size = 0;
let mut r_byte_mask = rw_op_data.r_byte_mask;
let mut w_byte_mask = rw_op_data.w_byte_mask;
if op.is_read() && r_byte_mask == 0 {
r_byte_mask = lsb_mask_u64(src_op.x86_rm_size());
}
if op.is_write() && w_byte_mask == 0 {
w_byte_mask = lsb_mask_u64(src_op.x86_rm_size());
}
op.read_byte_mask = r_byte_mask;
op.write_byte_mask = w_byte_mask;
op.extend_byte_mask = 0;
op.consecutive_lead_count = rw_op_data.consecutive_lead_count;
if src_op.is_reg() {
if op.is_write() {
if src_op.is_gp() {
rw_zero_extend_gp(op, src_op, NATIVE_GP_SIZE);
} else if rw_op_data.flags.contains(OpRwFlags::ZEXT) {
rw_zero_extend_non_vec(op, src_op);
}
}
rm_max_size = rm_max_size.max(src_op.x86_rm_size());
rm_ops_mask |= 1u32 << i;
} else {
let mem_op = src_op.as_::<Mem>();
if mem_op.has_base_reg() && !op.op_flags.contains(OpRwFlags::MEM_BASE_RW) {
op.op_flags |= OpRwFlags::MEM_BASE_READ;
}
if mem_op.has_index_reg() && !op.op_flags.contains(OpRwFlags::MEM_INDEX_RW) {
op.op_flags |= OpRwFlags::MEM_INDEX_READ;
}
}
}
if out.inst_flags.contains(InstRwFlags::MOV_OP) {
let reg_bit = 1u32 << (OperandType::Reg as u32);
if !(op_count >= 2 && op_type_mask == reg_bit && has_same_reg_type(operands)) {
out.inst_flags &= !InstRwFlags::MOV_OP;
}
}
let rm_flags = RwInfoRmFlags::from_bits_retain(inst_rm_info.flags);
if rm_flags.intersects(
RwInfoRmFlags::MOVSS_MOVSD | RwInfoRmFlags::PEXTRW | RwInfoRmFlags::FEATURE_IF_RMI,
) {
if rm_flags.contains(RwInfoRmFlags::MOVSS_MOVSD) {
if op_count == 2 && operands[0].is_reg() && operands[1].is_reg() {
out.operands[0].extend_byte_mask = 0;
}
} else if rm_flags.contains(RwInfoRmFlags::PEXTRW) {
if op_count == 3 && operands[1].is_reg_type_of(RegType::X86Mm) {
out.rm_feature = 0;
rm_ops_mask = 0;
}
} else if rm_flags.contains(RwInfoRmFlags::FEATURE_IF_RMI)
&& (op_count != 3 || !operands[2].is_imm())
{
out.rm_feature = 0;
}
}
rm_ops_mask &= inst_rm_info.rm_ops_mask as u32;
if rm_ops_mask != 0 && !inst.options.contains(InstOptions::X86_ER) {
let mut mask = rm_ops_mask;
while mask != 0 {
let i = mask.trailing_zeros() as usize;
mask &= mask - 1;
let op = &mut out.operands[i];
op.op_flags |= REG_M;
match inst_rm_info.category {
RwInfoRmCategory::Fixed => op.rm_size = inst_rm_info.fixed_size,
RwInfoRmCategory::Consistent => op.rm_size = operands[i].x86_rm_size() as u8,
RwInfoRmCategory::Half => op.rm_size = (rm_max_size / 2) as u8,
RwInfoRmCategory::Quarter => op.rm_size = (rm_max_size / 4) as u8,
RwInfoRmCategory::Eighth => op.rm_size = (rm_max_size / 8) as u8,
RwInfoRmCategory::None => {}
}
}
}
if inst_rw_info.category == RwInfoCategory::GenericEx {
match inst.id {
id if (id == InstId::Vpternlogd as u32 || id == InstId::Vpternlogq as u32)
&& op_count == 4
&& operands[3].is_imm() =>
{
let predicate = operands[3].as_::<Imm>().value() as u8;
if (predicate >> 4) == (predicate & 0xF) {
out.operands[0].op_flags &= !OpRwFlags::READ;
out.operands[0].read_byte_mask = 0;
}
}
_ => {}
}
}
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
match inst_rw_info.category {
RwInfoCategory::Mov => {
out.inst_flags &= !InstRwFlags::MOV_OP;
if op_count == 2 {
if operands[0].is_reg() && operands[1].is_reg() {
let o0_gp = operands[0].is_gp();
let o1_gp = operands[1].is_gp();
let o0_sreg = operands[0].is_reg_type_of(RegType::X86SReg);
let o1_sreg = operands[1].is_reg_type_of(RegType::X86SReg);
let o0_cd = operands[0].is_reg_type_of(RegType::X86CReg)
|| operands[0].is_reg_type_of(RegType::X86DReg);
let o1_cd = operands[1].is_reg_type_of(RegType::X86CReg)
|| operands[1].is_reg_type_of(RegType::X86DReg);
if o0_gp && o1_gp {
reset_op(
&mut out.operands[0],
W | REG_M,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R | REG_M,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
out.inst_flags |= InstRwFlags::MOV_OP;
return Ok(());
}
if o0_gp && o1_sreg {
reset_op(
&mut out.operands[0],
W | REG_M,
NATIVE_GP_SIZE,
INVALID_PHYS_ID,
);
out.operands[0].rm_size = 2;
reset_op(&mut out.operands[1], R, 2, INVALID_PHYS_ID);
return Ok(());
}
if o0_sreg && o1_gp {
reset_op(&mut out.operands[0], W, 2, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R | REG_M, 2, INVALID_PHYS_ID);
out.operands[1].rm_size = 2;
return Ok(());
}
if (o0_gp && o1_cd) || (o0_cd && o1_gp) {
reset_op(&mut out.operands[0], W, NATIVE_GP_SIZE, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, NATIVE_GP_SIZE, INVALID_PHYS_ID);
out.write_flags = CpuRwFlags::X86_OF
| CpuRwFlags::X86_SF
| CpuRwFlags::X86_ZF
| CpuRwFlags::X86_AF
| CpuRwFlags::X86_PF
| CpuRwFlags::X86_CF;
return Ok(());
}
}
if operands[0].is_reg() && operands[1].is_mem() {
let o1 = operands[1].as_::<Mem>();
if operands[0].is_gp() {
if !o1.is_offset_64bit() {
reset_op(
&mut out.operands[0],
W,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
} else {
reset_op(
&mut out.operands[0],
W | REG_PHYS,
operands[0].x86_rm_size(),
Gp::AX as u8,
);
}
reset_op(
&mut out.operands[1],
R | MIB_READ,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
return Ok(());
}
if operands[0].is_reg_type_of(RegType::X86SReg) {
reset_op(&mut out.operands[0], W, 2, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, 2, INVALID_PHYS_ID);
return Ok(());
}
}
if operands[0].is_mem() && operands[1].is_reg() {
let o0 = operands[0].as_::<Mem>();
if operands[1].is_gp() {
reset_op(
&mut out.operands[0],
W | MIB_READ,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
if !o0.is_offset_64bit() {
reset_op(
&mut out.operands[1],
R,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
} else {
reset_op(
&mut out.operands[1],
R | REG_PHYS,
operands[1].x86_rm_size(),
Gp::AX as u8,
);
}
return Ok(());
}
if operands[1].is_reg_type_of(RegType::X86SReg) {
reset_op(&mut out.operands[0], W | MIB_READ, 2, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, 2, INVALID_PHYS_ID);
return Ok(());
}
}
if operands[0].is_gp() && operands[1].is_imm() {
reset_op(
&mut out.operands[0],
W | REG_M,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
out.operands[1] = OpRwInfo::new();
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
return Ok(());
}
if operands[0].is_mem() && operands[1].is_imm() {
reset_op(
&mut out.operands[0],
W | MIB_READ,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
out.operands[1] = OpRwInfo::new();
return Ok(());
}
}
}
RwInfoCategory::Movabs => {
if op_count == 2 {
if operands[0].is_gp() && operands[1].is_mem() {
reset_op(
&mut out.operands[0],
W | REG_PHYS,
operands[0].x86_rm_size(),
Gp::AX as u8,
);
reset_op(
&mut out.operands[1],
R | MIB_READ,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
return Ok(());
}
if operands[0].is_mem() && operands[1].is_gp() {
reset_op(
&mut out.operands[0],
W | MIB_READ,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R | REG_PHYS,
operands[1].x86_rm_size(),
Gp::AX as u8,
);
return Ok(());
}
if operands[0].is_gp() && operands[1].is_imm() {
reset_op(
&mut out.operands[0],
W,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
out.operands[1] = OpRwInfo::new();
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
return Ok(());
}
}
}
RwInfoCategory::Imul => {
if op_count == 2 {
if operands[0].is_reg() && operands[1].is_imm() {
reset_op(
&mut out.operands[0],
X,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
out.operands[1] = OpRwInfo::new();
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
return Ok(());
}
if operands[0].is_reg_type_of(RegType::Gp16) && operands[1].x86_rm_size() == 1 {
reset_op(&mut out.operands[0], X | REG_PHYS, 2, Gp::AX as u8);
out.operands[0].read_byte_mask = lsb_mask_u64(1);
reset_op(&mut out.operands[1], R | REG_M, 1, INVALID_PHYS_ID);
} else {
reset_op(
&mut out.operands[0],
X,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R | REG_M,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
}
if operands[1].is_mem() {
out.operands[1].op_flags |= MIB_READ;
}
return Ok(());
}
if op_count == 3 {
if operands[2].is_imm() {
reset_op(
&mut out.operands[0],
W,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R | REG_M,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
out.operands[2] = OpRwInfo::new();
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
if operands[1].is_mem() {
out.operands[1].op_flags |= MIB_READ;
}
return Ok(());
} else {
reset_op(
&mut out.operands[0],
W | REG_PHYS,
operands[0].x86_rm_size(),
Gp::DX as u8,
);
reset_op(
&mut out.operands[1],
X | REG_PHYS,
operands[1].x86_rm_size(),
Gp::AX as u8,
);
reset_op(
&mut out.operands[2],
R | REG_M,
operands[2].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
rw_zero_extend_gp(&mut out.operands[1], &operands[1], NATIVE_GP_SIZE);
if operands[2].is_mem() {
out.operands[2].op_flags |= MIB_READ;
}
return Ok(());
}
}
}
RwInfoCategory::Movh64 => {
if op_count == 2 {
if operands[0].is_vec() && operands[1].is_mem() {
reset_op(&mut out.operands[0], W, 8, INVALID_PHYS_ID);
out.operands[0].write_byte_mask = lsb_mask_u64(8) << 8;
reset_op(&mut out.operands[1], R | MIB_READ, 8, INVALID_PHYS_ID);
return Ok(());
}
if operands[0].is_mem() && operands[1].is_vec() {
reset_op(&mut out.operands[0], W | MIB_READ, 8, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, 8, INVALID_PHYS_ID);
out.operands[1].read_byte_mask = lsb_mask_u64(8) << 8;
return Ok(());
}
}
}
RwInfoCategory::Punpcklxx => {
if op_count == 2 {
if operands[0].is_vec128() {
reset_op(&mut out.operands[0], X, 16, INVALID_PHYS_ID);
out.operands[0].read_byte_mask = 0x0F0F;
out.operands[0].write_byte_mask = 0xFFFF;
reset_op(&mut out.operands[1], R, 16, INVALID_PHYS_ID);
out.operands[1].write_byte_mask = 0x0F0F;
if operands[1].is_vec128() {
return Ok(());
}
if operands[1].is_mem() {
out.operands[1].op_flags |= MIB_READ;
return Ok(());
}
}
if operands[0].is_reg_type_of(RegType::X86Mm) {
reset_op(&mut out.operands[0], X, 8, INVALID_PHYS_ID);
out.operands[0].read_byte_mask = 0x0F;
out.operands[0].write_byte_mask = 0xFF;
reset_op(&mut out.operands[1], R, 4, INVALID_PHYS_ID);
out.operands[1].read_byte_mask = 0x0F;
if operands[1].is_reg_type_of(RegType::X86Mm) {
return Ok(());
}
if operands[1].is_mem() {
out.operands[1].op_flags |= MIB_READ;
return Ok(());
}
}
}
}
RwInfoCategory::Vmaskmov => {
if op_count == 3 {
if operands[0].is_vec() && operands[1].is_vec() && operands[2].is_mem() {
reset_op(
&mut out.operands[0],
W,
operands[0].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[2],
R | MIB_READ,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
rw_zero_extend_avx_vec(&mut out.operands[0]);
return Ok(());
}
if operands[0].is_mem() && operands[1].is_vec() && operands[2].is_vec() {
reset_op(
&mut out.operands[0],
X | MIB_READ,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[1],
R,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
reset_op(
&mut out.operands[2],
R,
operands[2].x86_rm_size(),
INVALID_PHYS_ID,
);
return Ok(());
}
}
}
RwInfoCategory::Vmovddup => {
if op_count == 2 {
if operands[0].is_vec() && operands[1].is_vec() {
let o0_size = operands[0].x86_rm_size();
let o1_size = if o0_size == 16 { 8 } else { o0_size };
reset_op(&mut out.operands[0], W, o0_size, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R | REG_M, o1_size, INVALID_PHYS_ID);
out.operands[1].read_byte_mask &= 0x00FF00FF00FF00FF;
rw_zero_extend_avx_vec(&mut out.operands[0]);
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
if operands[0].is_vec() && operands[1].is_mem() {
let o0_size = operands[0].x86_rm_size();
let o1_size = if o0_size == 16 { 8 } else { o0_size };
reset_op(&mut out.operands[0], W, o0_size, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R | MIB_READ, o1_size, INVALID_PHYS_ID);
rw_zero_extend_avx_vec(&mut out.operands[0]);
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
}
}
RwInfoCategory::Vmovmskpd | RwInfoCategory::Vmovmskps => {
if op_count == 2 && operands[0].is_gp() && operands[1].is_vec() {
reset_op(&mut out.operands[0], W, 1, INVALID_PHYS_ID);
out.operands[0].extend_byte_mask = lsb_mask_u64(NATIVE_GP_SIZE - 1) << 1;
reset_op(
&mut out.operands[1],
R,
operands[1].x86_rm_size(),
INVALID_PHYS_ID,
);
return Ok(());
}
}
RwInfoCategory::Vmov1_2 | RwInfoCategory::Vmov1_4 | RwInfoCategory::Vmov1_8 => {
let shift = inst_rw_info.category as u32 - RwInfoCategory::Vmov1_2 as u32 + 1;
if op_count >= 2 {
if op_count >= 3 {
if op_count > 3 {
return Err(AsmError::InvalidInstruction);
}
out.operands[2] = OpRwInfo::new();
}
if operands[0].is_reg() && operands[1].is_reg() {
let size1 = operands[1].x86_rm_size();
let size0 = size1 >> shift;
reset_op(&mut out.operands[0], W, size0, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, size1, INVALID_PHYS_ID);
if inst_rm_info.rm_ops_mask & 0x1 != 0 {
out.operands[0].op_flags |= REG_M;
out.operands[0].rm_size = size0 as u8;
}
if inst_rm_info.rm_ops_mask & 0x2 != 0 {
out.operands[1].op_flags |= REG_M;
out.operands[1].rm_size = size1 as u8;
}
if operands[0].is_gp() {
rw_zero_extend_gp(&mut out.operands[0], &operands[0], NATIVE_GP_SIZE);
}
if operands[0].is_vec() {
rw_zero_extend_avx_vec(&mut out.operands[0]);
}
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
if operands[0].is_reg() && operands[1].is_mem() {
let rm1 = operands[1].x86_rm_size();
let size1 = if rm1 != 0 { rm1 } else { 16 };
let size0 = size1 >> shift;
reset_op(&mut out.operands[0], W, size0, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R | MIB_READ, size1, INVALID_PHYS_ID);
if operands[0].is_vec() {
rw_zero_extend_avx_vec(&mut out.operands[0]);
}
return Ok(());
}
if operands[0].is_mem() && operands[1].is_reg() {
let size1 = operands[1].x86_rm_size();
let size0 = size1 >> shift;
reset_op(&mut out.operands[0], W | MIB_READ, size0, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, size1, INVALID_PHYS_ID);
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
}
}
RwInfoCategory::Vmov2_1 | RwInfoCategory::Vmov4_1 | RwInfoCategory::Vmov8_1 => {
let shift = inst_rw_info.category as u32 - RwInfoCategory::Vmov2_1 as u32 + 1;
if op_count >= 2 {
if op_count >= 3 {
if op_count > 3 {
return Err(AsmError::InvalidInstruction);
}
out.operands[2] = OpRwInfo::new();
}
let size0 = operands[0].x86_rm_size();
let size1 = size0 >> shift;
reset_op(&mut out.operands[0], W, size0, INVALID_PHYS_ID);
reset_op(&mut out.operands[1], R, size1, INVALID_PHYS_ID);
if operands[0].is_vec() {
rw_zero_extend_avx_vec(&mut out.operands[0]);
}
if operands[0].is_reg() && operands[1].is_reg() {
if inst_rm_info.rm_ops_mask & 0x1 != 0 {
out.operands[0].op_flags |= REG_M;
out.operands[0].rm_size = size0 as u8;
}
if inst_rm_info.rm_ops_mask & 0x2 != 0 {
out.operands[1].op_flags |= REG_M;
out.operands[1].rm_size = size1 as u8;
}
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
if operands[0].is_reg() && operands[1].is_mem() {
out.operands[1].op_flags |= MIB_READ;
rw_handle_avx512(inst, common_info, out);
return Ok(());
}
}
}
_ => {}
}
Err(AsmError::InvalidInstruction)
}
#[cfg(all(test, feature = "x86"))]
mod tests {
use super::*;
use crate::core::globals::InstOptions;
use crate::core::inst::Inst;
use crate::core::operand::{OperandCast, imm};
use crate::x86::operands::{Mem, ptr, regs, u64_ptr_abs};
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
fn inst_of(id: InstId, ops: &[Operand]) -> Inst {
Inst::with_operands(id as u32, ops)
}
fn inst_k(id: InstId, zeroing: bool, ops: &[Operand]) -> Inst {
let mut inst = inst_of(id, ops);
if zeroing {
inst.options = InstOptions::X86_ZMASK;
}
inst.extra_reg = *regs::K1.as_operand();
inst
}
fn vsib() -> Mem {
Mem::from_base_and_index_shift_disp(®s::RAX, ®s::XMM1, 2, 0, 0, 0.into())
}
fn oracle_cases() -> Vec<(&'static str, Inst)> {
use regs::*;
alloc::vec![
(
"add_rax_rcx",
inst_of(InstId::Add, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"add_eax_ecx",
inst_of(InstId::Add, &[*EAX.as_operand(), *ECX.as_operand()])
),
(
"add_al_cl",
inst_of(InstId::Add, &[*AL.as_operand(), *CL.as_operand()])
),
(
"add_ax_cx",
inst_of(InstId::Add, &[*AX.as_operand(), *CX.as_operand()])
),
(
"add_rax_m64",
inst_of(
InstId::Add,
&[*RAX.as_operand(), *ptr(RBX, 0, 8).as_operand()]
)
),
(
"add_m64_rax",
inst_of(
InstId::Add,
&[*ptr(RBX, 0, 8).as_operand(), *RAX.as_operand()]
)
),
(
"adc_rax_rcx",
inst_of(InstId::Adc, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"cmp_rax_rcx",
inst_of(InstId::Cmp, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"test_eax_ecx",
inst_of(InstId::Test, &[*EAX.as_operand(), *ECX.as_operand()])
),
(
"xor_eax_eax",
inst_of(InstId::Xor, &[*EAX.as_operand(), *EAX.as_operand()])
),
(
"xor_rax_rax",
inst_of(InstId::Xor, &[*RAX.as_operand(), *RAX.as_operand()])
),
(
"and_eax_eax",
inst_of(InstId::And, &[*EAX.as_operand(), *EAX.as_operand()])
),
(
"sub_rax_rax",
inst_of(InstId::Sub, &[*RAX.as_operand(), *RAX.as_operand()])
),
("mul_rbx", inst_of(InstId::Mul, &[*RBX.as_operand()])),
("mul_ebx", inst_of(InstId::Mul, &[*EBX.as_operand()])),
(
"imul_rax_rcx",
inst_of(InstId::Imul, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"imul_eax_ecx",
inst_of(InstId::Imul, &[*EAX.as_operand(), *ECX.as_operand()])
),
(
"imul_ax_cl",
inst_of(InstId::Imul, &[*AX.as_operand(), *CL.as_operand()])
),
(
"imul_rax_rcx_5",
inst_of(
InstId::Imul,
&[*RAX.as_operand(), *RCX.as_operand(), *imm(5).as_operand()]
)
),
(
"imul_dx_ax_bx",
inst_of(
InstId::Imul,
&[*DX.as_operand(), *AX.as_operand(), *BX.as_operand()]
)
),
("push_rax", inst_of(InstId::Push, &[*RAX.as_operand()])),
("pop_rax", inst_of(InstId::Pop, &[*RAX.as_operand()])),
(
"shl_rax_cl",
inst_of(InstId::Shl, &[*RAX.as_operand(), *CL.as_operand()])
),
(
"shl_rax_3",
inst_of(InstId::Shl, &[*RAX.as_operand(), *imm(3).as_operand()])
),
(
"mov_rax_rcx",
inst_of(InstId::Mov, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"mov_eax_ecx",
inst_of(InstId::Mov, &[*EAX.as_operand(), *ECX.as_operand()])
),
(
"mov_rax_m64",
inst_of(
InstId::Mov,
&[*RAX.as_operand(), *ptr(RBX, 0, 8).as_operand()]
)
),
(
"mov_m64_rax",
inst_of(
InstId::Mov,
&[*ptr(RBX, 0, 8).as_operand(), *RAX.as_operand()]
)
),
(
"mov_eax_42",
inst_of(InstId::Mov, &[*EAX.as_operand(), *imm(42).as_operand()])
),
(
"mov_cr0_rax",
inst_of(InstId::Mov, &[*CR0.as_operand(), *RAX.as_operand()])
),
(
"mov_rax_cr0",
inst_of(InstId::Mov, &[*RAX.as_operand(), *CR0.as_operand()])
),
(
"mov_ax_es",
inst_of(InstId::Mov, &[*AX.as_operand(), *ES.as_operand()])
),
(
"mov_es_ax",
inst_of(InstId::Mov, &[*ES.as_operand(), *AX.as_operand()])
),
(
"movabs_rax_m64abs",
inst_of(
InstId::Movabs,
&[*RAX.as_operand(), *u64_ptr_abs(0x11223344, 8).as_operand()]
)
),
(
"movabs_m64abs_rax",
inst_of(
InstId::Movabs,
&[*u64_ptr_abs(0x11223344, 8).as_operand(), *RAX.as_operand()]
)
),
(
"movabs_rax_imm",
inst_of(
InstId::Movabs,
&[*RAX.as_operand(), *imm(0x1122334455667788i64).as_operand()]
)
),
(
"vaddps_xmm",
inst_of(
InstId::Vaddps,
&[*XMM0.as_operand(), *XMM1.as_operand(), *XMM2.as_operand()]
)
),
(
"vaddps_ymm",
inst_of(
InstId::Vaddps,
&[*YMM0.as_operand(), *YMM1.as_operand(), *YMM2.as_operand()]
)
),
(
"vaddps_zmm",
inst_of(
InstId::Vaddps,
&[*ZMM0.as_operand(), *ZMM1.as_operand(), *ZMM2.as_operand()]
)
),
(
"vaddps_xmm_k1",
inst_k(
InstId::Vaddps,
false,
&[*XMM0.as_operand(), *XMM1.as_operand(), *XMM2.as_operand()]
)
),
(
"vaddps_xmm_k1z",
inst_k(
InstId::Vaddps,
true,
&[*XMM0.as_operand(), *XMM1.as_operand(), *XMM2.as_operand()]
)
),
(
"vaddps_zmm_k1z",
inst_k(
InstId::Vaddps,
true,
&[*ZMM0.as_operand(), *ZMM1.as_operand(), *ZMM2.as_operand()]
)
),
(
"vmovddup_xmm_xmm",
inst_of(InstId::Vmovddup, &[*XMM0.as_operand(), *XMM1.as_operand()])
),
(
"vmovddup_xmm_m64",
inst_of(
InstId::Vmovddup,
&[*XMM0.as_operand(), *ptr(RBX, 0, 8).as_operand()]
)
),
(
"vmovddup_ymm_ymm",
inst_of(InstId::Vmovddup, &[*YMM0.as_operand(), *YMM1.as_operand()])
),
(
"punpcklbw_xmm_xmm",
inst_of(InstId::Punpcklbw, &[*XMM0.as_operand(), *XMM1.as_operand()])
),
(
"punpcklbw_mm_mm",
inst_of(InstId::Punpcklbw, &[*MM0.as_operand(), *MM1.as_operand()])
),
(
"vpternlogd_fe",
inst_of(
InstId::Vpternlogd,
&[
*XMM0.as_operand(),
*XMM1.as_operand(),
*XMM2.as_operand(),
*imm(0xFE).as_operand()
]
)
),
(
"vpternlogd_cc",
inst_of(
InstId::Vpternlogd,
&[
*XMM0.as_operand(),
*XMM1.as_operand(),
*XMM2.as_operand(),
*imm(0xCC).as_operand()
]
)
),
(
"cmovz_rax_rcx",
inst_of(InstId::Cmovz, &[*RAX.as_operand(), *RCX.as_operand()])
),
(
"lea_rax_m8",
inst_of(
InstId::Lea,
&[*RAX.as_operand(), *ptr(RBX, 8, 0).as_operand()]
)
),
(
"movhps_xmm_m64",
inst_of(
InstId::Movhps,
&[*XMM0.as_operand(), *ptr(RBX, 0, 8).as_operand()]
)
),
(
"movhps_m64_xmm",
inst_of(
InstId::Movhps,
&[*ptr(RBX, 0, 8).as_operand(), *XMM0.as_operand()]
)
),
(
"vgatherdps_vsib",
inst_of(
InstId::Vgatherdps,
&[*XMM0.as_operand(), *vsib().as_operand()]
)
),
(
"vpgatherdd_k1_vsib",
inst_k(
InstId::Vpgatherdd,
false,
&[*XMM0.as_operand(), *vsib().as_operand()]
)
),
(
"movsb",
inst_of(
InstId::Movs,
&[*ptr(RDI, 0, 1).as_operand(), *ptr(RSI, 0, 1).as_operand()]
)
),
(
"stosb",
inst_of(
InstId::Stos,
&[*ptr(RDI, 0, 1).as_operand(), *AL.as_operand()]
)
),
(
"lodsb",
inst_of(
InstId::Lods,
&[*AL.as_operand(), *ptr(RSI, 0, 1).as_operand()]
)
),
(
"cmpsb",
inst_of(
InstId::Cmps,
&[*ptr(RSI, 0, 1).as_operand(), *ptr(RDI, 0, 1).as_operand()]
)
),
(
"scasb",
inst_of(
InstId::Scas,
&[*AL.as_operand(), *ptr(RDI, 0, 1).as_operand()]
)
),
(
"kaddb_k1_k2_k3",
inst_of(
InstId::Kaddb,
&[*K1.as_operand(), *K2.as_operand(), *K3.as_operand()]
)
),
(
"vp2intersectd_k1k2",
inst_of(
InstId::Vp2intersectd,
&[
*K1.as_operand(),
*K2.as_operand(),
*ZMM0.as_operand(),
*ZMM1.as_operand()
]
)
),
("stc", inst_of(InstId::Stc, &[])),
("clc", inst_of(InstId::Clc, &[])),
(
"vmovmskpd_eax",
inst_of(InstId::Vmovmskpd, &[*EAX.as_operand(), *XMM0.as_operand()])
),
(
"pmovmskb_eax",
inst_of(InstId::Pmovmskb, &[*EAX.as_operand(), *XMM0.as_operand()])
),
(
"vpmovzxbd_xmm",
inst_of(InstId::Vpmovzxbd, &[*XMM0.as_operand(), *XMM1.as_operand()])
),
(
"vcvtpd2dq_xmm_ymm",
inst_of(InstId::Vcvtpd2dq, &[*XMM0.as_operand(), *YMM1.as_operand()])
),
(
"vmaskmovpd_load",
inst_of(
InstId::Vmaskmovpd,
&[
*XMM0.as_operand(),
*XMM1.as_operand(),
*ptr(RBX, 0, 16).as_operand()
]
)
),
(
"vmaskmovpd_store",
inst_of(
InstId::Vmaskmovpd,
&[
*ptr(RBX, 0, 16).as_operand(),
*XMM0.as_operand(),
*XMM1.as_operand()
]
)
),
(
"pextrw_eax_mm1",
inst_of(
InstId::Pextrw,
&[*EAX.as_operand(), *MM1.as_operand(), *imm(1).as_operand()]
)
),
(
"pextrw_eax_xmm1",
inst_of(
InstId::Pextrw,
&[*EAX.as_operand(), *XMM1.as_operand(), *imm(1).as_operand()]
)
),
(
"vpslld_imm",
inst_of(
InstId::Vpslld,
&[*XMM1.as_operand(), *XMM2.as_operand(), *imm(8).as_operand()]
)
),
(
"vpslld_reg",
inst_of(
InstId::Vpslld,
&[*XMM1.as_operand(), *XMM2.as_operand(), *XMM3.as_operand()]
)
),
(
"movss_xmm_xmm",
inst_of(InstId::Movss, &[*XMM0.as_operand(), *XMM1.as_operand()])
),
(
"movss_xmm_m32",
inst_of(
InstId::Movss,
&[*XMM0.as_operand(), *ptr(RBX, 0, 4).as_operand()]
)
),
(
"movsd_xmm_xmm",
inst_of(InstId::Movsd, &[*XMM0.as_operand(), *XMM1.as_operand()])
),
]
}
fn fmt_op(op: &OpRwInfo) -> String {
format!(
"(f={:08x} p={:02X} rm={:02x} c={} r={:016x} w={:016x} x={:016x})",
op.op_flags.bits(),
op.phys_id,
op.rm_size,
op.consecutive_lead_count,
op.read_byte_mask,
op.write_byte_mask,
op.extend_byte_mask
)
}
fn fmt_case(name: &str, rw: &InstRwInfo) -> String {
let mut s = format!(
"{} if={:08x} rmf={:02x} rf={:08x} wf={:08x} x={}",
name,
rw.inst_flags.bits(),
rw.rm_feature,
rw.read_flags.bits(),
rw.write_flags.bits(),
fmt_op(&rw.extra_reg)
);
for (i, op) in rw.operands().iter().enumerate() {
s.push_str(&format!(" o{}={}", i, fmt_op(op)));
}
s
}
const ORACLE: &[&str] = &[
"add_rax_rcx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=08 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"add_eax_ecx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000017 p=FF rm=04 c=0 r=000000000000000f w=000000000000000f x=00000000000000f0) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"add_al_cl if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=01 c=0 r=0000000000000001 w=0000000000000001 x=0000000000000000) o1=(f=00000005 p=FF rm=01 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"add_ax_cx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=02 c=0 r=0000000000000003 w=0000000000000003 x=0000000000000000) o1=(f=00000005 p=FF rm=02 c=0 r=0000000000000003 w=0000000000000000 x=0000000000000000)",
"add_rax_m64 if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=08 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00001001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"add_m64_rax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00001003 p=FF rm=00 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"adc_rax_rcx if=00000000 rmf=00 rf=00000002 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=08 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"cmp_rax_rcx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"test_eax_ecx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"xor_eax_eax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=04 c=0 r=0000000000000000 w=000000000000000f x=00000000000000f0) o1=(f=00000004 p=FF rm=04 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"xor_rax_rax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000006 p=FF rm=08 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000004 p=FF rm=08 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"and_eax_eax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"sub_rax_rax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000006 p=FF rm=08 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000004 p=FF rm=08 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"mul_rbx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000102 p=02 rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000)",
"mul_ebx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000112 p=02 rm=00 c=0 r=0000000000000000 w=000000000000000f x=00000000000000f0)",
"imul_rax_rcx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000003 p=FF rm=00 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"imul_eax_ecx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000013 p=FF rm=00 c=0 r=000000000000000f w=000000000000000f x=00000000000000f0) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"imul_ax_cl if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000103 p=00 rm=00 c=0 r=0000000000000001 w=0000000000000003 x=0000000000000000) o1=(f=00000005 p=FF rm=01 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"imul_rax_rcx_5 if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o2=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"imul_dx_ax_bx if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000102 p=02 rm=00 c=0 r=0000000000000000 w=0000000000000003 x=0000000000000000) o1=(f=00000103 p=00 rm=00 c=0 r=0000000000000003 w=0000000000000003 x=0000000000000000) o2=(f=00000005 p=FF rm=02 c=0 r=0000000000000003 w=0000000000000000 x=0000000000000000)",
"push_rax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"pop_rax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000006 p=FF rm=08 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000)",
"shl_rax_cl if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=08 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000101 p=01 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"shl_rax_3 if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000007 p=FF rm=08 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"mov_rax_rcx if=00000001 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000006 p=FF rm=08 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"mov_eax_ecx if=00000001 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=04 c=0 r=0000000000000000 w=000000000000000f x=00000000000000f0) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"mov_rax_m64 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00005001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"mov_m64_rax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00005002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"mov_eax_42 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=04 c=0 r=0000000000000000 w=000000000000000f x=00000000000000f0) o1=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"mov_cr0_rax if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"mov_rax_cr0 if=00000000 rmf=00 rf=00000000 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"mov_ax_es if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000006 p=FF rm=02 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=0000000000000003 w=0000000000000000 x=0000000000000000)",
"mov_es_ax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000003 x=0000000000000000) o1=(f=00000005 p=FF rm=02 c=0 r=0000000000000003 w=0000000000000000 x=0000000000000000)",
"movabs_rax_m64abs if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000102 p=00 rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00005001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"movabs_m64abs_rax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00005002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000101 p=00 rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"movabs_rax_imm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vaddps_xmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"vaddps_ymm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=00000000ffffffff x=ffffffff00000000) o1=(f=00000001 p=FF rm=00 c=0 r=00000000ffffffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=20 c=0 r=00000000ffffffff w=0000000000000000 x=0000000000000000)",
"vaddps_zmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=ffffffffffffffff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=40 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000)",
"vaddps_xmm_k1 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o0=(f=00000013 p=FF rm=00 c=0 r=000000000000ffff w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"vaddps_xmm_k1z if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"vaddps_zmm_k1z if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=ffffffffffffffff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=40 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000)",
"vmovddup_xmm_xmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"vmovddup_xmm_m64 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00005001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"vmovddup_ymm_ymm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=00000000ffffffff x=ffffffff00000000) o1=(f=00000005 p=FF rm=20 c=0 r=0000000000ff00ff w=0000000000000000 x=0000000000000000)",
"punpcklbw_xmm_xmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000003 p=FF rm=00 c=0 r=0000000000000f0f w=000000000000ffff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000f0f x=0000000000000000)",
"punpcklbw_mm_mm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000003 p=FF rm=00 c=0 r=000000000000000f w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"vpternlogd_fe if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000013 p=FF rm=00 c=0 r=000000000000ffff w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o3=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vpternlogd_cc if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o3=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"cmovz_rax_rcx if=00000000 rmf=00 rf=00000004 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000003 p=FF rm=00 c=0 r=00000000000000ff w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"lea_rax_m8 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00001001 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"movhps_xmm_m64 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ff00 x=0000000000000000) o1=(f=00005001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
"movhps_m64_xmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00005002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ff00 w=0000000000000000 x=0000000000000000)",
"vgatherdps_vsib if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000013 p=FF rm=00 c=0 r=000000000000ffff w=000000000000ffff x=ffffffffffff0000) o1=(f=00005001 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vpgatherdd_k1_vsib if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o0=(f=00000013 p=FF rm=00 c=0 r=000000000000ffff w=000000000000ffff x=ffffffffffff0000) o1=(f=00005001 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"movsb if=00000000 rmf=00 rf=00000400 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00023202 p=07 rm=00 c=0 r=0000000000000000 w=0000000000000001 x=0000000000000000) o1=(f=00023201 p=06 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"stosb if=00000000 rmf=00 rf=00000400 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00023202 p=07 rm=00 c=0 r=0000000000000000 w=0000000000000001 x=0000000000000000) o1=(f=00000101 p=00 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"lodsb if=00000000 rmf=00 rf=00000400 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000102 p=00 rm=00 c=0 r=0000000000000000 w=0000000000000001 x=0000000000000000) o1=(f=00023201 p=06 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"cmpsb if=00000000 rmf=00 rf=00000400 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00023201 p=06 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000) o1=(f=00023201 p=07 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"scasb if=00000000 rmf=00 rf=00000400 wf=0000030f x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000101 p=00 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000) o1=(f=00023201 p=07 rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"kaddb_k1_k2_k3 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000001 x=00000000000000fe) o1=(f=00000001 p=FF rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000) o2=(f=00000001 p=FF rm=00 c=0 r=0000000000000001 w=0000000000000000 x=0000000000000000)",
"vp2intersectd_k1k2 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=0000001a p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=00000000000000ff) o2=(f=00000001 p=FF rm=00 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000) o3=(f=00000005 p=FF rm=40 c=0 r=ffffffffffffffff w=0000000000000000 x=0000000000000000)",
"stc if=00000000 rmf=00 rf=00000000 wf=00000002 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"clc if=00000000 rmf=00 rf=00000000 wf=00000002 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vmovmskpd_eax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000002 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000001 x=00000000000000fe) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"pmovmskb_eax if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000003 x=00000000000000fc) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"vpmovzxbd_xmm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"vcvtpd2dq_xmm_ymm if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000005 p=FF rm=20 c=0 r=00000000ffffffff w=0000000000000000 x=0000000000000000)",
"vmaskmovpd_load if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00005001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"vmaskmovpd_store if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00005003 p=FF rm=00 c=0 r=000000000000ffff w=000000000000ffff x=0000000000000000) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"pextrw_eax_mm1 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000003 x=00000000000000fc) o1=(f=00000001 p=FF rm=00 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000) o2=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"pextrw_eax_xmm1 if=00000000 rmf=63 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=02 c=0 r=0000000000000000 w=0000000000000003 x=00000000000000fc) o1=(f=00000001 p=FF rm=00 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vpslld_imm if=00000000 rmf=77 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000)",
"vpslld_reg if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000012 p=FF rm=00 c=0 r=0000000000000000 w=000000000000ffff x=ffffffffffff0000) o1=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000) o2=(f=00000005 p=FF rm=10 c=0 r=000000000000ffff w=0000000000000000 x=0000000000000000)",
"movss_xmm_xmm if=00000001 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=04 c=0 r=0000000000000000 w=000000000000000f x=0000000000000000) o1=(f=00000005 p=FF rm=04 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"movss_xmm_m32 if=00000000 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=04 c=0 r=0000000000000000 w=000000000000000f x=fffffffffffffff0) o1=(f=00001001 p=FF rm=00 c=0 r=000000000000000f w=0000000000000000 x=0000000000000000)",
"movsd_xmm_xmm if=00000001 rmf=00 rf=00000000 wf=00000000 x=(f=00000000 p=FF rm=00 c=0 r=0000000000000000 w=0000000000000000 x=0000000000000000) o0=(f=00000016 p=FF rm=08 c=0 r=0000000000000000 w=00000000000000ff x=0000000000000000) o1=(f=00000005 p=FF rm=08 c=0 r=00000000000000ff w=0000000000000000 x=0000000000000000)",
];
#[test]
#[ignore]
fn print_oracle_replay() {
for (name, inst) in oracle_cases() {
let rw = query_rw_info(&inst).unwrap();
std::println!("{}", fmt_case(name, &rw));
}
}
#[test]
fn query_matches_cpp_oracle() {
let cases = oracle_cases();
assert_eq!(cases.len(), ORACLE.len());
for ((name, inst), expected) in cases.iter().zip(ORACLE.iter()) {
let rw = query_rw_info(inst).unwrap();
let actual = fmt_case(name, &rw);
assert_eq!(&actual, expected, "case {name}");
}
}
fn query(inst: &Inst) -> InstRwInfo {
query_rw_info(inst).unwrap()
}
#[test]
fn partial_write_masks() {
let rw = query(&inst_of(
InstId::Add,
&[*regs::AL.as_operand(), *regs::CL.as_operand()],
));
assert_eq!(rw.operands[0].read_byte_mask, 0x1);
assert_eq!(rw.operands[0].write_byte_mask, 0x1);
assert!(!rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
let rw = query(&inst_of(
InstId::Add,
&[*regs::AX.as_operand(), *regs::CX.as_operand()],
));
assert_eq!(rw.operands[0].write_byte_mask, 0x3);
assert!(!rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
let rw = query(&inst_of(
InstId::Add,
&[*regs::EAX.as_operand(), *regs::ECX.as_operand()],
));
assert_eq!(rw.operands[0].write_byte_mask, 0xF);
assert!(rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
assert_eq!(rw.operands[0].extend_byte_mask, 0xF0);
let rw = query(&inst_of(
InstId::Add,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert_eq!(rw.operands[0].write_byte_mask, 0xFF);
assert!(!rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
}
#[test]
fn implicit_phys_ids() {
let rw = query(&inst_of(InstId::Mul, &[*regs::RBX.as_operand()]));
assert!(rw.operands[0].op_flags.contains(OpRwFlags::REG_PHYS_ID));
assert_eq!(rw.operands[0].phys_id, Gp::DX as u8);
let rw = query(&inst_of(
InstId::Imul,
&[
*regs::DX.as_operand(),
*regs::AX.as_operand(),
*regs::BX.as_operand(),
],
));
assert_eq!(rw.operands[0].phys_id, Gp::DX as u8);
assert_eq!(rw.operands[1].phys_id, Gp::AX as u8);
assert!(rw.operands[1].is_read_write());
let rw = query(&inst_of(
InstId::Shl,
&[*regs::RAX.as_operand(), *regs::CL.as_operand()],
));
assert!(rw.operands[1].op_flags.contains(OpRwFlags::REG_PHYS_ID));
assert_eq!(rw.operands[1].phys_id, Gp::CX as u8);
let rw = query(&inst_of(
InstId::Movs,
&[
*ptr(regs::RDI, 0, 1).as_operand(),
*ptr(regs::RSI, 0, 1).as_operand(),
],
));
assert!(rw.operands[0].op_flags.contains(OpRwFlags::MEM_PHYS_ID));
assert_eq!(rw.operands[0].phys_id, Gp::DI as u8);
assert!(
rw.operands[0]
.op_flags
.contains(OpRwFlags::MEM_BASE_POST_MODIFY)
);
assert_eq!(rw.operands[1].phys_id, Gp::SI as u8);
assert_eq!(rw.read_flags, CpuRwFlags::X86_DF);
}
#[test]
fn eflags_read_write() {
let rw = query(&inst_of(
InstId::Add,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert_eq!(rw.read_flags, CpuRwFlags::NONE);
assert_eq!(
rw.write_flags,
CpuRwFlags::X86_OF
| CpuRwFlags::X86_SF
| CpuRwFlags::X86_ZF
| CpuRwFlags::X86_AF
| CpuRwFlags::X86_PF
| CpuRwFlags::X86_CF
);
let rw = query(&inst_of(
InstId::Adc,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert_eq!(rw.read_flags, CpuRwFlags::X86_CF);
let rw = query(&inst_of(
InstId::Cmp,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert!(rw.operands[0].is_read_only());
assert!(rw.operands[1].is_read_only());
for id in [InstId::Stc, InstId::Clc] {
let rw = query(&inst_of(id, &[]));
assert_eq!(rw.op_count, 0);
assert_eq!(rw.write_flags, CpuRwFlags::X86_CF);
}
let rw = query(&inst_of(
InstId::Cmovz,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert_eq!(rw.read_flags, CpuRwFlags::X86_ZF);
}
#[test]
fn mov_op_and_zext() {
let rw = query(&inst_of(
InstId::Mov,
&[*regs::EAX.as_operand(), *regs::ECX.as_operand()],
));
assert!(rw.is_mov_op());
assert!(rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
assert_eq!(rw.operands[0].extend_byte_mask, 0xF0);
let rw = query(&inst_of(
InstId::Mov,
&[*regs::RAX.as_operand(), *regs::RCX.as_operand()],
));
assert!(rw.is_mov_op());
assert!(rw.operands[0].is_write_only());
let rw = query(&inst_of(
InstId::Movss,
&[*regs::XMM0.as_operand(), *regs::XMM1.as_operand()],
));
assert!(rw.is_mov_op());
assert_eq!(rw.operands[0].extend_byte_mask, 0);
let rw = query(&inst_of(
InstId::Mov,
&[*regs::EAX.as_operand(), *imm(42).as_operand()],
));
assert!(!rw.is_mov_op());
}
#[test]
fn same_reg_hints() {
let rw = query(&inst_of(
InstId::Xor,
&[*regs::EAX.as_operand(), *regs::EAX.as_operand()],
));
assert!(rw.operands[0].is_write_only());
assert_eq!(rw.operands[0].read_byte_mask, 0);
assert_eq!(rw.operands[0].write_byte_mask, 0xF);
assert!(rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
assert_eq!(rw.operands[0].extend_byte_mask, 0xF0);
let rw = query(&inst_of(
InstId::And,
&[*regs::EAX.as_operand(), *regs::EAX.as_operand()],
));
assert!(rw.operands[0].is_read_only());
assert_eq!(rw.operands[0].write_byte_mask, 0);
assert_eq!(rw.operands[0].extend_byte_mask, 0);
let rw = query(&inst_of(
InstId::Xor,
&[*regs::EAX.as_operand(), *regs::ECX.as_operand()],
));
assert!(rw.operands[0].is_read_write());
}
#[test]
fn avx512_mask_merge_vs_zero() {
let rw = query(&inst_k(
InstId::Vaddps,
false,
&[
*regs::XMM0.as_operand(),
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
],
));
assert!(rw.extra_reg.is_read_only());
assert_eq!(rw.extra_reg.read_byte_mask, 0xFF);
assert!(rw.operands[0].is_read_write());
assert_eq!(rw.operands[0].read_byte_mask, 0xFFFF);
let rw = query(&inst_k(
InstId::Vaddps,
true,
&[
*regs::XMM0.as_operand(),
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
],
));
assert!(rw.extra_reg.is_read_only());
assert!(rw.operands[0].is_write_only());
assert_eq!(rw.operands[0].read_byte_mask, 0);
assert_eq!(rw.operands[0].extend_byte_mask, 0xFFFFFFFFFFFF0000);
}
#[test]
fn avx_vector_zext() {
let rw = query(&inst_of(
InstId::Vaddps,
&[
*regs::XMM0.as_operand(),
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
],
));
assert!(rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
assert_eq!(rw.operands[0].extend_byte_mask, 0xFFFFFFFFFFFF0000);
let rw = query(&inst_of(
InstId::Vaddps,
&[
*regs::ZMM0.as_operand(),
*regs::ZMM1.as_operand(),
*regs::ZMM2.as_operand(),
],
));
assert!(!rw.operands[0].op_flags.contains(OpRwFlags::ZEXT));
assert_eq!(rw.operands[0].extend_byte_mask, 0);
}
#[test]
fn consecutive_vp2intersect() {
let rw = query(&inst_of(
InstId::Vp2intersectd,
&[
*regs::K1.as_operand(),
*regs::K2.as_operand(),
*regs::ZMM0.as_operand(),
*regs::ZMM1.as_operand(),
],
));
assert!(rw.operands[1].op_flags.contains(OpRwFlags::CONSECUTIVE));
assert!(rw.operands[0].is_write_only());
assert!(rw.operands[2].is_read_only());
assert!(rw.operands[3].is_read_only());
}
#[test]
fn lea_mem_base_read() {
let rw = query(&inst_of(
InstId::Lea,
&[*regs::RAX.as_operand(), *ptr(regs::RBX, 8, 0).as_operand()],
));
assert!(rw.operands[0].is_write_only());
let mem = &rw.operands[1];
assert!(mem.op_flags.contains(OpRwFlags::MEM_BASE_READ));
assert!(!mem.op_flags.contains(OpRwFlags::MEM_FAKE));
assert_eq!(mem.read_byte_mask, 0);
assert_eq!(mem.write_byte_mask, 0);
}
#[test]
fn vsib_gather_mem_flags() {
let rw = query(&inst_of(
InstId::Vgatherdps,
&[*regs::XMM0.as_operand(), *vsib().as_operand()],
));
let mem = &rw.operands[1];
assert!(mem.op_flags.contains(OpRwFlags::MEM_BASE_READ));
assert!(mem.op_flags.contains(OpRwFlags::MEM_INDEX_READ));
}
#[test]
fn rm_feature_gating() {
let rw = query(&inst_of(
InstId::Pextrw,
&[
*regs::EAX.as_operand(),
*regs::MM1.as_operand(),
*imm(1).as_operand(),
],
));
assert_eq!(rw.rm_feature, 0);
let rw = query(&inst_of(
InstId::Pextrw,
&[
*regs::EAX.as_operand(),
*regs::XMM1.as_operand(),
*imm(1).as_operand(),
],
));
assert_eq!(
rw.rm_feature,
super::super::instdb::CpuFeature::SSE4_1 as u8
);
let rw = query(&inst_of(
InstId::Vpslld,
&[
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
*imm(8).as_operand(),
],
));
assert_eq!(
rw.rm_feature,
super::super::instdb::CpuFeature::AVX512_F as u8
);
let rw = query(&inst_of(
InstId::Vpslld,
&[
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
*regs::XMM3.as_operand(),
],
));
assert_eq!(rw.rm_feature, 0);
}
#[test]
fn vpternlogd_predicate_analysis() {
let rw = query(&inst_of(
InstId::Vpternlogd,
&[
*regs::XMM0.as_operand(),
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
*imm(0xCC).as_operand(),
],
));
assert!(rw.operands[0].is_write_only());
assert_eq!(rw.operands[0].read_byte_mask, 0);
let rw = query(&inst_of(
InstId::Vpternlogd,
&[
*regs::XMM0.as_operand(),
*regs::XMM1.as_operand(),
*regs::XMM2.as_operand(),
*imm(0xFE).as_operand(),
],
));
assert!(rw.operands[0].is_read_write());
}
#[test]
fn instruction_id_bounds() {
assert!(query_rw_info(&inst_of(InstId::None, &[])).is_ok());
let inst = Inst::new(u32::MAX);
assert!(query_rw_info(&inst).is_err());
}
}