use crate::tablegen::{
BinOp, ClassDef, DagExpr, DefMDef, FieldDef, LetStmt, MultiClassDef, RecordDef, TGValue,
TableGenBackend, TableGenNode, TdClass, TdExpr, TdField, UnOp,
};
use crate::x86::{
AddressPattern, ISelTable, ISelTableEntry, OperandType, PatCondition, PatNode, PatResult,
X86Opcode, X86RegisterInfo, X86SchedInfo,
};
#[derive(Debug, Clone)]
pub struct X86TableGenFull {
pub target: String,
pub enable_avx512: bool,
pub enable_avx10: bool,
pub enable_amx: bool,
pub instructions: Vec<X86InstrTableGenDef>,
pub register_classes: Vec<X86RegisterClassDef>,
pub registers: Vec<X86RegisterDef>,
pub patterns: Vec<X86PatFragDef>,
pub complex_patterns: Vec<X86ComplexPattern>,
pub isel_dag_patterns: Vec<ISelTableEntry>,
pub calling_conventions: Vec<X86CallingConvRule>,
pub scheduling_records: Vec<X86SchedWriteRecord>,
}
impl X86TableGenFull {
pub fn new() -> Self {
Self {
target: "x86_64-unknown-linux-gnu".to_string(),
enable_avx512: true,
enable_avx10: false,
enable_amx: true,
instructions: Vec::new(),
register_classes: Vec::new(),
registers: Vec::new(),
patterns: Vec::new(),
complex_patterns: Vec::new(),
isel_dag_patterns: Vec::new(),
calling_conventions: Vec::new(),
scheduling_records: Vec::new(),
}
}
pub fn new_i386() -> Self {
Self {
target: "i386-unknown-linux-gnu".to_string(),
enable_avx512: false,
enable_avx10: false,
enable_amx: false,
..Self::new()
}
}
pub fn generate_all(&mut self) {
self.gen_register_classes();
self.gen_registers();
self.gen_instructions();
self.gen_patterns();
self.gen_complex_patterns();
self.gen_calling_conventions();
self.gen_scheduling_info();
}
pub fn build_isel_table(&self) -> ISelTable {
ISelTable::from_entries(self.isel_dag_patterns.clone())
}
pub fn export_instr_defs(&self) -> &[X86InstrTableGenDef] {
&self.instructions
}
pub fn instr_count(&self) -> usize {
self.instructions.len()
}
pub fn export_register_info(&self) -> X86RegisterInfo {
X86RegisterInfo
}
}
impl Default for X86TableGenFull {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct X86InstrTableGenDef {
pub mnemonic: String,
pub intel_mnemonic: Option<String>,
pub opcode: X86Opcode,
pub num_operands: u8,
pub operand_types: Vec<OperandType>,
pub format: X86InstrFormat,
pub encoding_prefix: Option<X86EncodingPrefix>,
pub opcode_map: X86OpcodeMap,
pub opcode_byte: u8,
pub fixed_modrm: Option<u8>,
pub requires_rex: bool,
pub is_vex: bool,
pub vex_l: Option<bool>,
pub vex_w: Option<bool>,
pub is_evex: bool,
pub evex_tuple: Option<X86EvexTuple>,
pub evex_broadcast: bool,
pub evex_rounding: bool,
pub evex_sae: bool,
pub required_features: Vec<String>,
pub fallback_opcode: Option<X86Opcode>,
pub is_terminator: bool,
pub is_branch: bool,
pub is_conditional: bool,
pub is_call: bool,
pub is_return: bool,
pub is_compare: bool,
pub is_move_imm: bool,
pub is_bitcast: bool,
pub is_convert: bool,
pub has_side_effects: bool,
pub may_load: bool,
pub may_store: bool,
pub is_commutative: bool,
pub is_three_address: bool,
pub can_fold_load: bool,
pub is_re_materializable: bool,
pub is_barrier: bool,
pub uses_custom_inserter: bool,
pub is_code_gen_only: bool,
pub is_pseudo: bool,
pub implicit_defs: Vec<u32>,
pub implicit_uses: Vec<u32>,
pub sched_info: Option<X86SchedInfo>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86InstrFormat {
RawFrm,
AddRegFrm,
MRMDestReg,
MRMDestMem,
MRMSrcReg,
MRMSrcMem,
MRMXm,
MRMXr,
MRM0r,
MRM1r,
MRM2r,
MRM3r,
MRM4r,
MRM5r,
MRM6r,
MRM7r,
MRM0m,
MRM1m,
MRM2m,
MRM3m,
MRM4m,
MRM5m,
MRM6m,
MRM7m,
Pseudo,
Prefix,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86EncodingPrefix {
None,
OpSize,
RepNE,
Rep,
Lock,
Vex2,
Vex3,
Evex,
Xop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86OpcodeMap {
OB,
TB,
T8,
TA,
XOP8,
XOP9,
XOPA,
ThreeDNow,
Map5,
Map6,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86EvexTuple {
FV,
HV,
QV,
OV,
SCALAR,
T1S,
T1F,
T2,
T4,
T8,
MEM,
}
#[derive(Debug, Clone)]
pub struct X86RegisterClassDef {
pub name: String,
pub reg_names: Vec<String>,
pub spill_size: u32,
pub spill_alignment: u32,
pub copy_cost: u32,
pub is_allocatable: bool,
pub is_virtual: bool,
pub value_type: String,
}
#[derive(Debug, Clone)]
pub struct X86RegisterDef {
pub name: String,
pub width_bits: u32,
pub reg_class: String,
pub sub_regs: Vec<String>,
pub super_regs: Vec<String>,
pub aliases: Vec<String>,
pub encoding: u32,
pub dwarf_number: Option<u32>,
}
#[derive(Debug, Clone)]
pub struct X86RegisterDefs {
pub gr8: Vec<X86RegisterDef>,
pub gr16: Vec<X86RegisterDef>,
pub gr32: Vec<X86RegisterDef>,
pub gr64: Vec<X86RegisterDef>,
pub fr32: Vec<X86RegisterDef>,
pub fr64: Vec<X86RegisterDef>,
pub vr128: Vec<X86RegisterDef>,
pub vr256: Vec<X86RegisterDef>,
pub vr512: Vec<X86RegisterDef>,
pub mask_regs: Vec<X86RegisterDef>,
pub segment_regs: Vec<X86RegisterDef>,
pub control_regs: Vec<X86RegisterDef>,
pub debug_regs: Vec<X86RegisterDef>,
pub rflags: Vec<X86RegisterDef>,
pub eflags: Vec<X86RegisterDef>,
pub x87_regs: Vec<X86RegisterDef>,
pub mmx_regs: Vec<X86RegisterDef>,
pub bound_regs: Vec<X86RegisterDef>,
pub tile_regs: Vec<X86RegisterDef>,
}
impl X86RegisterDefs {
pub fn generate() -> Self {
let mut defs = Self {
gr8: Vec::new(),
gr16: Vec::new(),
gr32: Vec::new(),
gr64: Vec::new(),
fr32: Vec::new(),
fr64: Vec::new(),
vr128: Vec::new(),
vr256: Vec::new(),
vr512: Vec::new(),
mask_regs: Vec::new(),
segment_regs: Vec::new(),
control_regs: Vec::new(),
debug_regs: Vec::new(),
rflags: Vec::new(),
eflags: Vec::new(),
x87_regs: Vec::new(),
mmx_regs: Vec::new(),
bound_regs: Vec::new(),
tile_regs: Vec::new(),
};
let gr8_names = [
"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8B", "R9B", "R10B", "R11B", "R12B",
"R13B", "R14B", "R15B", "SPL", "BPL", "SIL", "DIL",
];
for (i, name) in gr8_names.iter().enumerate() {
defs.gr8.push(X86RegisterDef {
name: name.to_string(),
width_bits: 8,
reg_class: "GR8".to_string(),
sub_regs: vec![],
super_regs: vec![format!(
"{}X",
name.chars()
.filter(|c| c.is_alphabetic() && *c != 'B' && *c != 'L' && *c != 'H')
.collect::<String>()
)],
aliases: vec![],
encoding: i as u32,
dwarf_number: None,
});
}
let gr16_names = [
"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "R8W", "R9W", "R10W", "R11W", "R12W",
"R13W", "R14W", "R15W",
];
for (i, name) in gr16_names.iter().enumerate() {
defs.gr16.push(X86RegisterDef {
name: name.to_string(),
width_bits: 16,
reg_class: "GR16".to_string(),
sub_regs: vec![format!("{}L", &name[..name.len() - 1])],
super_regs: vec![format!("E{}", name)],
aliases: vec![],
encoding: i as u32,
dwarf_number: Some(i as u32 + 3), });
}
let gr32_names = [
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", "R8D", "R9D", "R10D", "R11D",
"R12D", "R13D", "R14D", "R15D",
];
for (i, name) in gr32_names.iter().enumerate() {
defs.gr32.push(X86RegisterDef {
name: name.to_string(),
width_bits: 32,
reg_class: "GR32".to_string(),
sub_regs: vec![format!("{}", {
let n = name.trim_start_matches('E');
if n == "AX" {
"AX".into()
} else if n == "SP" {
"SP".into()
} else if n == "BP" {
"BP".into()
} else if n == "SI" {
"SI".into()
} else if n == "DI" {
"DI".into()
} else if n == "CX" {
"CX".into()
} else if n == "DX" {
"DX".into()
} else if n == "BX" {
"BX".into()
} else {
format!("{}W", &n[..n.len() - 1])
}
})],
super_regs: vec![format!(
"R{}",
name.trim_start_matches('E').trim_end_matches('D')
)],
aliases: vec![],
encoding: i as u32,
dwarf_number: Some(i as u32),
});
}
let gr64_names = [
"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11",
"R12", "R13", "R14", "R15",
];
for (i, name) in gr64_names.iter().enumerate() {
defs.gr64.push(X86RegisterDef {
name: name.to_string(),
width_bits: 64,
reg_class: "GR64".to_string(),
sub_regs: vec![format!("E{}", &name[1..])],
super_regs: vec![],
aliases: vec![],
encoding: i as u32,
dwarf_number: Some(i as u32),
});
}
for i in 0..32 {
defs.fr32.push(X86RegisterDef {
name: format!("XMM{}", i),
width_bits: 32,
reg_class: "FR32".to_string(),
sub_regs: vec![],
super_regs: vec![format!("XMM{}", i)],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 17),
});
}
for i in 0..32 {
defs.fr64.push(X86RegisterDef {
name: format!("XMM{}", i),
width_bits: 64,
reg_class: "FR64".to_string(),
sub_regs: vec![],
super_regs: vec![format!("YMM{}", i)],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 17),
});
}
for i in 0..32 {
defs.vr128.push(X86RegisterDef {
name: format!("XMM{}", i),
width_bits: 128,
reg_class: "VR128".to_string(),
sub_regs: vec![format!("XMM{}_FR32", i), format!("XMM{}_FR64", i)],
super_regs: vec![format!("YMM{}", i)],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 17),
});
}
for i in 0..32 {
defs.vr256.push(X86RegisterDef {
name: format!("YMM{}", i),
width_bits: 256,
reg_class: "VR256".to_string(),
sub_regs: vec![format!("XMM{}", i)],
super_regs: vec![format!("ZMM{}", i)],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 17),
});
}
for i in 0..32 {
defs.vr512.push(X86RegisterDef {
name: format!("ZMM{}", i),
width_bits: 512,
reg_class: "VR512".to_string(),
sub_regs: vec![format!("YMM{}", i)],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: None,
});
}
for i in 0..8 {
defs.mask_regs.push(X86RegisterDef {
name: format!("K{}", i),
width_bits: 64,
reg_class: "VK64".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 118),
});
}
let seg_names = ["CS", "DS", "SS", "ES", "FS", "GS"];
for (i, name) in seg_names.iter().enumerate() {
defs.segment_regs.push(X86RegisterDef {
name: name.to_string(),
width_bits: 16,
reg_class: "SEGMENT_REG".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i as u32,
dwarf_number: Some(i as u32 + 40),
});
}
for i in 0..16 {
defs.control_regs.push(X86RegisterDef {
name: format!("CR{}", i),
width_bits: if i <= 8 { 64 } else { 64 },
reg_class: "CONTROL_REG".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: None,
});
}
for i in 0..16 {
defs.debug_regs.push(X86RegisterDef {
name: format!("DR{}", i),
width_bits: 64,
reg_class: "DEBUG_REG".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: None,
});
}
defs.rflags.push(X86RegisterDef {
name: "RFLAGS".to_string(),
width_bits: 64,
reg_class: "RFLAGS".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec!["EFLAGS".into()],
encoding: 0,
dwarf_number: Some(49),
});
defs.eflags.push(X86RegisterDef {
name: "EFLAGS".to_string(),
width_bits: 32,
reg_class: "EFLAGS".to_string(),
sub_regs: vec![],
super_regs: vec!["RFLAGS".into()],
aliases: vec![],
encoding: 0,
dwarf_number: Some(49),
});
for i in 0..8 {
defs.x87_regs.push(X86RegisterDef {
name: format!("ST{}", i),
width_bits: 80,
reg_class: "RFP80".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 33),
});
}
for i in 0..8 {
defs.mmx_regs.push(X86RegisterDef {
name: format!("MM{}", i),
width_bits: 64,
reg_class: "VR64".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 29),
});
}
for i in 0..4 {
defs.bound_regs.push(X86RegisterDef {
name: format!("BND{}", i),
width_bits: 128,
reg_class: "BNDREG".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: Some(i + 126),
});
}
for i in 0..8 {
defs.tile_regs.push(X86RegisterDef {
name: format!("TMM{}", i),
width_bits: 8192, reg_class: "TILEREG".to_string(),
sub_regs: vec![],
super_regs: vec![],
aliases: vec![],
encoding: i,
dwarf_number: None,
});
}
defs
}
}
impl Default for X86RegisterDefs {
fn default() -> Self {
Self::generate()
}
}
#[derive(Debug, Clone)]
pub struct X86PatFragDef {
pub name: String,
pub dag: X86PatFragDag,
pub root_type: Option<String>,
pub operands: Vec<String>,
pub predicate: Option<String>,
pub is_leaf: bool,
}
#[derive(Debug, Clone)]
pub enum X86PatFragDag {
Operator(String, Vec<X86PatFragOperand>),
ImplicitDef(String),
Constant(i64),
Register(String),
ComplexPattern(String),
}
#[derive(Debug, Clone)]
pub enum X86PatFragOperand {
Var(String),
Nested(X86PatFragDag),
IntLit(i64),
}
#[derive(Debug, Clone)]
pub struct X86InstrPattern {
pub patterns: Vec<X86PatFragDef>,
}
impl X86InstrPattern {
pub fn generate() -> Self {
let mut patterns = Vec::new();
patterns.push(X86PatFragDef {
name: "load".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("iPTR".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadi8".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("i8".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadi16".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("i16".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadi32".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("i32".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadi64".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("i64".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadf32".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("f32".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadf64".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("f64".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadv4f32".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("v4f32".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "loadv2f64".into(),
dag: X86PatFragDag::Operator("ld".into(), vec![X86PatFragOperand::Var("addr".into())]),
root_type: Some("v2f64".into()),
operands: vec!["addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "store".into(),
dag: X86PatFragDag::Operator(
"st".into(),
vec![
X86PatFragOperand::Var("val".into()),
X86PatFragOperand::Var("addr".into()),
],
),
root_type: None,
operands: vec!["val".into(), "addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "storei8".into(),
dag: X86PatFragDag::Operator(
"st".into(),
vec![
X86PatFragOperand::Var("val".into()),
X86PatFragOperand::Var("addr".into()),
],
),
root_type: None,
operands: vec!["val".into(), "addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "storei32".into(),
dag: X86PatFragDag::Operator(
"st".into(),
vec![
X86PatFragOperand::Var("val".into()),
X86PatFragOperand::Var("addr".into()),
],
),
root_type: None,
operands: vec!["val".into(), "addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "storei64".into(),
dag: X86PatFragDag::Operator(
"st".into(),
vec![
X86PatFragOperand::Var("val".into()),
X86PatFragOperand::Var("addr".into()),
],
),
root_type: None,
operands: vec!["val".into(), "addr".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "add".into(),
dag: X86PatFragDag::Operator(
"add".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "sub".into(),
dag: X86PatFragDag::Operator(
"sub".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "mul".into(),
dag: X86PatFragDag::Operator(
"mul".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "and".into(),
dag: X86PatFragDag::Operator(
"and".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "or".into(),
dag: X86PatFragDag::Operator(
"or".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "xor".into(),
dag: X86PatFragDag::Operator(
"xor".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "shl".into(),
dag: X86PatFragDag::Operator(
"shl".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "srl".into(),
dag: X86PatFragDag::Operator(
"srl".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "sra".into(),
dag: X86PatFragDag::Operator(
"sra".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fadd".into(),
dag: X86PatFragDag::Operator(
"fadd".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("fPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fsub".into(),
dag: X86PatFragDag::Operator(
"fsub".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("fPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fmul".into(),
dag: X86PatFragDag::Operator(
"fmul".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("fPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fdiv".into(),
dag: X86PatFragDag::Operator(
"fdiv".into(),
vec![
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("fPTR".into()),
operands: vec!["a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fsqrt".into(),
dag: X86PatFragDag::Operator("fsqrt".into(), vec![X86PatFragOperand::Var("a".into())]),
root_type: Some("fPTR".into()),
operands: vec!["a".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fneg".into(),
dag: X86PatFragDag::Operator("fneg".into(), vec![X86PatFragOperand::Var("a".into())]),
root_type: Some("fPTR".into()),
operands: vec!["a".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "fabs".into(),
dag: X86PatFragDag::Operator("fabs".into(), vec![X86PatFragOperand::Var("a".into())]),
root_type: Some("fPTR".into()),
operands: vec!["a".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "zext".into(),
dag: X86PatFragDag::Operator("zext".into(), vec![X86PatFragOperand::Var("val".into())]),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "sext".into(),
dag: X86PatFragDag::Operator("sext".into(), vec![X86PatFragOperand::Var("val".into())]),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "trunc".into(),
dag: X86PatFragDag::Operator(
"trunc".into(),
vec![X86PatFragOperand::Var("val".into())],
),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "anyext".into(),
dag: X86PatFragDag::Operator(
"anyext".into(),
vec![X86PatFragOperand::Var("val".into())],
),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "setcc".into(),
dag: X86PatFragDag::Operator(
"setcc".into(),
vec![
X86PatFragOperand::Var("cond".into()),
X86PatFragOperand::Var("a".into()),
X86PatFragOperand::Var("b".into()),
],
),
root_type: Some("i8".into()),
operands: vec!["cond".into(), "a".into(), "b".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "bitcast_to_f32".into(),
dag: X86PatFragDag::Operator(
"bitconvert".into(),
vec![X86PatFragOperand::Var("val".into())],
),
root_type: Some("f32".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "bitcast_i32_to_f32".into(),
dag: X86PatFragDag::Operator(
"bitconvert".into(),
vec![X86PatFragOperand::Var("val".into())],
),
root_type: Some("f32".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "lea_addr".into(),
dag: X86PatFragDag::Operator(
"X86lea_addr".into(),
vec![
X86PatFragOperand::Var("base".into()),
X86PatFragOperand::Var("index".into()),
X86PatFragOperand::Var("scale".into()),
X86PatFragOperand::Var("disp".into()),
],
),
root_type: None,
operands: vec!["base".into(), "index".into(), "scale".into(), "disp".into()],
predicate: Some("is_legal_address".into()),
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "select".into(),
dag: X86PatFragDag::Operator(
"select".into(),
vec![
X86PatFragOperand::Var("cond".into()),
X86PatFragOperand::Var("tval".into()),
X86PatFragOperand::Var("fval".into()),
],
),
root_type: Some("iPTR".into()),
operands: vec!["cond".into(), "tval".into(), "fval".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "brcond".into(),
dag: X86PatFragDag::Operator(
"brcond".into(),
vec![
X86PatFragOperand::Var("cond".into()),
X86PatFragOperand::Var("bb".into()),
],
),
root_type: None,
operands: vec!["cond".into(), "bb".into()],
predicate: None,
is_leaf: false,
});
patterns.push(X86PatFragDef {
name: "imm".into(),
dag: X86PatFragDag::Operator("imm".into(), vec![X86PatFragOperand::Var("val".into())]),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: None,
is_leaf: true,
});
patterns.push(X86PatFragDef {
name: "imm_small".into(),
dag: X86PatFragDag::Operator("imm".into(), vec![X86PatFragOperand::Var("val".into())]),
root_type: Some("iPTR".into()),
operands: vec!["val".into()],
predicate: Some("imm_fits_8".into()),
is_leaf: true,
});
X86InstrPattern { patterns }
}
}
impl Default for X86InstrPattern {
fn default() -> Self {
Self::generate()
}
}
#[derive(Debug, Clone)]
pub struct X86ComplexPattern {
pub name: String,
pub select_func: String, pub root_nodes: Vec<String>,
pub num_operands: usize,
pub properties: Vec<String>,
}
impl X86InstrPattern {
pub fn generate_complex_patterns() -> Vec<X86ComplexPattern> {
vec![
X86ComplexPattern {
name: "Addr".into(),
select_func: "SelectAddr".into(),
root_nodes: vec!["addr".into()],
num_operands: 4,
properties: vec!["SDNPWantParent".into()],
},
X86ComplexPattern {
name: "LEAAddr".into(),
select_func: "SelectLEAAddr".into(),
root_nodes: vec!["X86lea_addr".into()],
num_operands: 4,
properties: vec!["SDNPWantParent".into()],
},
X86ComplexPattern {
name: "TLSAddr".into(),
select_func: "SelectTLSAddr".into(),
root_nodes: vec!["tls_addr".into()],
num_operands: 3,
properties: vec![],
},
X86ComplexPattern {
name: "GlobalBaseReg".into(),
select_func: "SelectGlobalBaseReg".into(),
root_nodes: vec!["global_base_reg".into()],
num_operands: 1,
properties: vec![],
},
]
}
}
impl X86TableGenFull {
fn gen_instructions(&mut self) {
self.gen_data_movement();
self.gen_arithmetic();
self.gen_logical();
self.gen_shift_rotate();
self.gen_string_ops();
self.gen_control_flow();
self.gen_sse();
self.gen_sse2();
self.gen_sse3_ssse3();
self.gen_sse41_sse42();
self.gen_avx_avx2();
if self.enable_avx512 {
self.gen_avx512();
}
self.gen_fma();
self.gen_bmi_bmi2();
self.gen_system();
}
fn make_instr(
mnemonic: &str,
opcode: X86Opcode,
num_operands: u8,
operands: Vec<OperandType>,
format: X86InstrFormat,
opcode_map: X86OpcodeMap,
opcode_byte: u8,
) -> X86InstrTableGenDef {
X86InstrTableGenDef {
mnemonic: mnemonic.to_string(),
intel_mnemonic: None,
opcode,
num_operands,
operand_types: operands,
format,
encoding_prefix: None,
opcode_map,
opcode_byte,
fixed_modrm: None,
requires_rex: false,
is_vex: false,
vex_l: None,
vex_w: None,
is_evex: false,
evex_tuple: None,
evex_broadcast: false,
evex_rounding: false,
evex_sae: false,
required_features: vec![],
fallback_opcode: None,
is_terminator: false,
is_branch: false,
is_conditional: false,
is_call: false,
is_return: false,
is_compare: false,
is_move_imm: false,
is_bitcast: false,
is_convert: false,
has_side_effects: false,
may_load: false,
may_store: false,
is_commutative: false,
is_three_address: false,
can_fold_load: true,
is_re_materializable: false,
is_barrier: false,
uses_custom_inserter: false,
is_code_gen_only: false,
is_pseudo: false,
implicit_defs: vec![],
implicit_uses: vec![],
sched_info: Some(X86SchedInfo::SIMPLE_ALU),
}
}
fn gen_data_movement(&mut self) {
let cmov_variants: [(&str, X86Opcode, &str); 16] = [
("CMOVO", X86Opcode::CMOVO, "overflow"),
("CMOVNO", X86Opcode::CMOVNO, "not overflow"),
("CMOVB", X86Opcode::CMOVB, "below"),
("CMOVAE", X86Opcode::CMOVAE, "above or equal"),
("CMOVE", X86Opcode::CMOVE, "equal / zero"),
("CMOVNE", X86Opcode::CMOVNE, "not equal"),
("CMOVBE", X86Opcode::CMOVBE, "below or equal"),
("CMOVA", X86Opcode::CMOVA, "above"),
("CMOVS", X86Opcode::CMOVS, "sign"),
("CMOVNS", X86Opcode::CMOVNS, "not sign"),
("CMOVP", X86Opcode::CMOVP, "parity even"),
("CMOVNP", X86Opcode::CMOVNP, "parity odd"),
("CMOVL", X86Opcode::CMOVL, "less"),
("CMOVGE", X86Opcode::CMOVGE, "greater or equal"),
("CMOVLE", X86Opcode::CMOVLE, "less or equal"),
("CMOVG", X86Opcode::CMOVG, "greater"),
];
let setcc_variants: [(&str, X86Opcode); 16] = [
("SETO", X86Opcode::SETO),
("SETNO", X86Opcode::SETNO),
("SETB", X86Opcode::SETB),
("SETAE", X86Opcode::SETAE),
("SETE", X86Opcode::SETE),
("SETNE", X86Opcode::SETNE),
("SETBE", X86Opcode::SETBE),
("SETA", X86Opcode::SETA),
("SETS", X86Opcode::SETS),
("SETNS", X86Opcode::SETNS),
("SETP", X86Opcode::SETP),
("SETNP", X86Opcode::SETNP),
("SETL", X86Opcode::SETL),
("SETGE", X86Opcode::SETGE),
("SETLE", X86Opcode::SETLE),
("SETG", X86Opcode::SETG),
];
let mut mov32rr = Self::make_instr(
"MOV32rr",
X86Opcode::MOV,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x89,
);
mov32rr.can_fold_load = false;
mov32rr.is_move_imm = false;
mov32rr.is_commutative = false;
self.instructions.push(mov32rr);
let mut mov32rm = Self::make_instr(
"MOV32rm",
X86Opcode::MOV,
2,
vec![OperandType::Reg32, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x8B,
);
mov32rm.may_load = true;
mov32rm.sched_info = Some(X86SchedInfo::LOAD);
self.instructions.push(mov32rm);
let mut mov32mr = Self::make_instr(
"MOV32mr",
X86Opcode::MOV,
2,
vec![OperandType::Mem32, OperandType::Reg32],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::OB,
0x89,
);
mov32mr.may_store = true;
mov32mr.sched_info = Some(X86SchedInfo::STORE);
self.instructions.push(mov32mr);
let mut mov32ri = Self::make_instr(
"MOV32ri",
X86Opcode::MOV,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xB8,
);
mov32ri.is_move_imm = true;
mov32ri.can_fold_load = false;
mov32ri.is_re_materializable = true;
self.instructions.push(mov32ri);
let mut mov64rr = Self::make_instr(
"MOV64rr",
X86Opcode::MOV,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x89,
);
mov64rr.requires_rex = true;
mov64rr.can_fold_load = false;
mov64rr.required_features = vec!["64bit".into()];
self.instructions.push(mov64rr);
let mut mov64rm = Self::make_instr(
"MOV64rm",
X86Opcode::MOV,
2,
vec![OperandType::Reg64, OperandType::Mem64],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x8B,
);
mov64rm.requires_rex = true;
mov64rm.may_load = true;
mov64rm.sched_info = Some(X86SchedInfo::LOAD);
mov64rm.required_features = vec!["64bit".into()];
self.instructions.push(mov64rm);
let mut mov64mr = Self::make_instr(
"MOV64mr",
X86Opcode::MOV,
2,
vec![OperandType::Mem64, OperandType::Reg64],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::OB,
0x89,
);
mov64mr.requires_rex = true;
mov64mr.may_store = true;
mov64mr.sched_info = Some(X86SchedInfo::STORE);
mov64mr.required_features = vec!["64bit".into()];
self.instructions.push(mov64mr);
let mut mov64ri = Self::make_instr(
"MOV64ri",
X86Opcode::MOV,
2,
vec![OperandType::Reg64, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xB8,
);
mov64ri.requires_rex = true;
mov64ri.is_move_imm = true;
mov64ri.can_fold_load = false;
mov64ri.is_re_materializable = true;
mov64ri.required_features = vec!["64bit".into()];
self.instructions.push(mov64ri);
let mut movsx32rr8 = Self::make_instr(
"MOVSX32rr8",
X86Opcode::MOVSX,
2,
vec![OperandType::Reg32, OperandType::Reg8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xBE,
);
movsx32rr8.is_convert = true;
self.instructions.push(movsx32rr8);
let mut movsx32rm8 = Self::make_instr(
"MOVSX32rm8",
X86Opcode::MOVSX,
2,
vec![OperandType::Reg32, OperandType::Mem8],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0xBE,
);
movsx32rm8.may_load = true;
movsx32rm8.is_convert = true;
self.instructions.push(movsx32rm8);
let mut movsx64rr32 = Self::make_instr(
"MOVSX64rr32",
X86Opcode::MOVSX,
2,
vec![OperandType::Reg64, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::OB,
0x63,
);
movsx64rr32.requires_rex = true;
movsx64rr32.is_convert = true;
movsx64rr32.required_features = vec!["64bit".into()];
self.instructions.push(movsx64rr32);
let mut movzx32rr8 = Self::make_instr(
"MOVZX32rr8",
X86Opcode::MOVZX,
2,
vec![OperandType::Reg32, OperandType::Reg8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xB6,
);
movzx32rr8.is_convert = true;
self.instructions.push(movzx32rr8);
let mut movzx32rm8 = Self::make_instr(
"MOVZX32rm8",
X86Opcode::MOVZX,
2,
vec![OperandType::Reg32, OperandType::Mem8],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0xB6,
);
movzx32rm8.may_load = true;
movzx32rm8.is_convert = true;
self.instructions.push(movzx32rm8);
let mut movabs64 = Self::make_instr(
"MOV64ri64",
X86Opcode::MOVABS,
2,
vec![OperandType::Reg64, OperandType::Imm64],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xB8,
);
movabs64.requires_rex = true;
movabs64.is_move_imm = true;
movabs64.can_fold_load = false;
movabs64.is_re_materializable = true;
movabs64.required_features = vec!["64bit".into()];
self.instructions.push(movabs64);
let mut xchg32rr = Self::make_instr(
"XCHG32rr",
X86Opcode::XCHG,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x87,
);
xchg32rr.is_commutative = true;
xchg32rr.can_fold_load = false;
self.instructions.push(xchg32rr);
let mut xchg64rr = Self::make_instr(
"XCHG64rr",
X86Opcode::XCHG,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x87,
);
xchg64rr.requires_rex = true;
xchg64rr.is_commutative = true;
xchg64rr.can_fold_load = false;
xchg64rr.required_features = vec!["64bit".into()];
self.instructions.push(xchg64rr);
let mut push32r = Self::make_instr(
"PUSH32r",
X86Opcode::PUSH,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x50,
);
push32r.may_store = true;
push32r.implicit_uses = vec![4]; push32r.implicit_defs = vec![4]; self.instructions.push(push32r);
let mut push64r = Self::make_instr(
"PUSH64r",
X86Opcode::PUSH,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x50,
);
push64r.requires_rex = false; push64r.may_store = true;
push64r.implicit_uses = vec![4]; push64r.implicit_defs = vec![4]; push64r.required_features = vec!["64bit".into()];
self.instructions.push(push64r);
let mut pop32r = Self::make_instr(
"POP32r",
X86Opcode::POP,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x58,
);
pop32r.may_load = true;
pop32r.implicit_defs = vec![4]; pop32r.implicit_uses = vec![4]; self.instructions.push(pop32r);
let mut pop64r = Self::make_instr(
"POP64r",
X86Opcode::POP,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x58,
);
pop64r.may_load = true;
pop64r.implicit_defs = vec![4]; pop64r.implicit_uses = vec![4]; pop64r.required_features = vec!["64bit".into()];
self.instructions.push(pop64r);
let mut lea32r = Self::make_instr(
"LEA32r",
X86Opcode::LEA,
2,
vec![OperandType::Reg32, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x8D,
);
lea32r.can_fold_load = false;
lea32r.is_re_materializable = true;
self.instructions.push(lea32r);
let mut lea64r = Self::make_instr(
"LEA64_32r",
X86Opcode::LEA,
2,
vec![OperandType::Reg64, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x8D,
);
lea64r.requires_rex = true;
lea64r.can_fold_load = false;
lea64r.is_re_materializable = true;
lea64r.required_features = vec!["64bit".into()];
self.instructions.push(lea64r);
for (i, (mnemonic, opcode, _desc)) in cmov_variants.iter().enumerate() {
let mut cmov32rr = Self::make_instr(
&format!("{}32rr", mnemonic),
*opcode,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x40 + i as u8,
);
cmov32rr.is_conditional = true;
cmov32rr.can_fold_load = false;
cmov32rr.required_features = vec!["cmov".into()];
self.instructions.push(cmov32rr);
let mut cmov32rm = Self::make_instr(
&format!("{}32rm", mnemonic),
*opcode,
2,
vec![OperandType::Reg32, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x40 + i as u8,
);
cmov32rm.may_load = true;
cmov32rm.is_conditional = true;
cmov32rm.required_features = vec!["cmov".into()];
self.instructions.push(cmov32rm);
let mut cmov64rr = Self::make_instr(
&format!("{}64rr", mnemonic),
*opcode,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x40 + i as u8,
);
cmov64rr.requires_rex = true;
cmov64rr.is_conditional = true;
cmov64rr.can_fold_load = false;
cmov64rr.required_features = vec!["cmov".into(), "64bit".into()];
self.instructions.push(cmov64rr);
let mut cmov64rm = Self::make_instr(
&format!("{}64rm", mnemonic),
*opcode,
2,
vec![OperandType::Reg64, OperandType::Mem64],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x40 + i as u8,
);
cmov64rm.requires_rex = true;
cmov64rm.may_load = true;
cmov64rm.is_conditional = true;
cmov64rm.required_features = vec!["cmov".into(), "64bit".into()];
self.instructions.push(cmov64rm);
}
for (i, (mnemonic, opcode)) in setcc_variants.iter().enumerate() {
let mut setccr = Self::make_instr(
&format!("{}r", mnemonic),
*opcode,
1,
vec![OperandType::Reg8],
X86InstrFormat::MRM0r,
X86OpcodeMap::TB,
0x90 + i as u8,
);
setccr.is_conditional = true;
setccr.can_fold_load = false;
setccr.required_features = vec!["cmov".into()];
self.instructions.push(setccr);
let mut setccm = Self::make_instr(
&format!("{}m", mnemonic),
*opcode,
1,
vec![OperandType::Mem8],
X86InstrFormat::MRM0m,
X86OpcodeMap::TB,
0x90 + i as u8,
);
setccm.may_store = true;
setccm.is_conditional = true;
setccm.required_features = vec!["cmov".into()];
self.instructions.push(setccm);
}
}
fn gen_arithmetic(&mut self) {
let mut add32rr = Self::make_instr(
"ADD32rr",
X86Opcode::ADD,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x01,
);
add32rr.is_commutative = true;
self.instructions.push(add32rr);
let mut add32rm = Self::make_instr(
"ADD32rm",
X86Opcode::ADD,
2,
vec![OperandType::Reg32, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x03,
);
add32rm.may_load = true;
add32rm.is_commutative = true;
self.instructions.push(add32rm);
let mut add32ri = Self::make_instr(
"ADD32ri",
X86Opcode::ADD,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x81,
);
add32ri.fixed_modrm = Some(0xC0);
add32ri.is_commutative = true;
self.instructions.push(add32ri);
let mut add64rr = Self::make_instr(
"ADD64rr",
X86Opcode::ADD,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x01,
);
add64rr.requires_rex = true;
add64rr.is_commutative = true;
add64rr.required_features = vec!["64bit".into()];
self.instructions.push(add64rr);
let mut add64ri8 = Self::make_instr(
"ADD64ri8",
X86Opcode::ADD,
2,
vec![OperandType::Reg64, OperandType::Imm8],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x83,
);
add64ri8.requires_rex = true;
add64ri8.is_commutative = true;
add64ri8.required_features = vec!["64bit".into()];
self.instructions.push(add64ri8);
let mut adc32rr = Self::make_instr(
"ADC32rr",
X86Opcode::ADC,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x11,
);
adc32rr.implicit_uses = vec![49]; adc32rr.implicit_defs = vec![49];
self.instructions.push(adc32rr);
let mut adc64rr = Self::make_instr(
"ADC64rr",
X86Opcode::ADC,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x11,
);
adc64rr.requires_rex = true;
adc64rr.implicit_uses = vec![49];
adc64rr.implicit_defs = vec![49];
adc64rr.required_features = vec!["64bit".into()];
self.instructions.push(adc64rr);
let sub32rr = Self::make_instr(
"SUB32rr",
X86Opcode::SUB,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x29,
);
self.instructions.push(sub32rr);
let mut sub32rm = Self::make_instr(
"SUB32rm",
X86Opcode::SUB,
2,
vec![OperandType::Reg32, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::OB,
0x2B,
);
sub32rm.may_load = true;
sub32rm.sched_info = Some(X86SchedInfo::LOAD);
self.instructions.push(sub32rm);
let mut sub32ri = Self::make_instr(
"SUB32ri",
X86Opcode::SUB,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x81,
);
sub32ri.fixed_modrm = Some(0xE8);
self.instructions.push(sub32ri);
let mut sub64rr = Self::make_instr(
"SUB64rr",
X86Opcode::SUB,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x29,
);
sub64rr.requires_rex = true;
sub64rr.required_features = vec!["64bit".into()];
self.instructions.push(sub64rr);
let mut sbb32rr = Self::make_instr(
"SBB32rr",
X86Opcode::SBB,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x19,
);
sbb32rr.implicit_uses = vec![49];
sbb32rr.implicit_defs = vec![49];
self.instructions.push(sbb32rr);
let mut sbb64rr = Self::make_instr(
"SBB64rr",
X86Opcode::SBB,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x19,
);
sbb64rr.requires_rex = true;
sbb64rr.implicit_uses = vec![49];
sbb64rr.implicit_defs = vec![49];
sbb64rr.required_features = vec!["64bit".into()];
self.instructions.push(sbb64rr);
let mut mul32r = Self::make_instr(
"MUL32r",
X86Opcode::MUL,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xF7,
);
mul32r.implicit_defs = vec![0, 2]; mul32r.implicit_uses = vec![0]; mul32r.sched_info = Some(X86SchedInfo::IMUL);
self.instructions.push(mul32r);
let mut mul64r = Self::make_instr(
"MUL64r",
X86Opcode::MUL,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xF7,
);
mul64r.requires_rex = true;
mul64r.implicit_defs = vec![0, 2]; mul64r.implicit_uses = vec![0];
mul64r.sched_info = Some(X86SchedInfo::IMUL);
mul64r.required_features = vec!["64bit".into()];
self.instructions.push(mul64r);
let mut imul32rri = Self::make_instr(
"IMUL32rri",
X86Opcode::IMUL,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::OB,
0x69,
);
imul32rri.is_three_address = true;
imul32rri.sched_info = Some(X86SchedInfo::IMUL);
self.instructions.push(imul32rri);
let mut imul64rri = Self::make_instr(
"IMUL64rri",
X86Opcode::IMUL,
3,
vec![OperandType::Reg64, OperandType::Reg64, OperandType::Imm32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::OB,
0x69,
);
imul64rri.requires_rex = true;
imul64rri.is_three_address = true;
imul64rri.sched_info = Some(X86SchedInfo::IMUL);
imul64rri.required_features = vec!["64bit".into()];
self.instructions.push(imul64rri);
let mut div32r = Self::make_instr(
"DIV32r",
X86Opcode::DIV,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM6r,
X86OpcodeMap::OB,
0xF7,
);
div32r.implicit_defs = vec![0, 2];
div32r.implicit_uses = vec![0, 2];
div32r.sched_info = Some(X86SchedInfo::IDIV);
self.instructions.push(div32r);
let mut div64r = Self::make_instr(
"DIV64r",
X86Opcode::DIV,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM6r,
X86OpcodeMap::OB,
0xF7,
);
div64r.requires_rex = true;
div64r.implicit_defs = vec![0, 2];
div64r.implicit_uses = vec![0, 2];
div64r.sched_info = Some(X86SchedInfo::IDIV);
div64r.required_features = vec!["64bit".into()];
self.instructions.push(div64r);
let mut idiv32r = Self::make_instr(
"IDIV32r",
X86Opcode::IDIV,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM7r,
X86OpcodeMap::OB,
0xF7,
);
idiv32r.implicit_defs = vec![0, 2];
idiv32r.implicit_uses = vec![0, 2];
idiv32r.sched_info = Some(X86SchedInfo::IDIV);
self.instructions.push(idiv32r);
let mut idiv64r = Self::make_instr(
"IDIV64r",
X86Opcode::IDIV,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM7r,
X86OpcodeMap::OB,
0xF7,
);
idiv64r.requires_rex = true;
idiv64r.implicit_defs = vec![0, 2];
idiv64r.implicit_uses = vec![0, 2];
idiv64r.sched_info = Some(X86SchedInfo::IDIV);
idiv64r.required_features = vec!["64bit".into()];
self.instructions.push(idiv64r);
let inc32r = Self::make_instr(
"INC32r",
X86Opcode::INC,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x40,
);
self.instructions.push(inc32r);
let mut inc64r = Self::make_instr(
"INC64r",
X86Opcode::INC,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM0r,
X86OpcodeMap::TB,
0xFF,
);
inc64r.fixed_modrm = Some(0xC0);
inc64r.requires_rex = true;
inc64r.required_features = vec!["64bit".into()];
self.instructions.push(inc64r);
let dec32r = Self::make_instr(
"DEC32r",
X86Opcode::DEC,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM1r,
X86OpcodeMap::OB,
0x48,
);
self.instructions.push(dec32r);
let neg32r = Self::make_instr(
"NEG32r",
X86Opcode::NEG,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM3r,
X86OpcodeMap::OB,
0xF7,
);
self.instructions.push(neg32r);
let mut neg64r = Self::make_instr(
"NEG64r",
X86Opcode::NEG,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM3r,
X86OpcodeMap::OB,
0xF7,
);
neg64r.requires_rex = true;
neg64r.required_features = vec!["64bit".into()];
self.instructions.push(neg64r);
}
fn gen_logical(&mut self) {
let mut and32rr = Self::make_instr(
"AND32rr",
X86Opcode::AND,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x21,
);
and32rr.is_commutative = true;
self.instructions.push(and32rr);
let mut and32ri = Self::make_instr(
"AND32ri",
X86Opcode::AND,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x81,
);
and32ri.fixed_modrm = Some(0xE0);
and32ri.is_commutative = true;
self.instructions.push(and32ri);
let mut and64rr = Self::make_instr(
"AND64rr",
X86Opcode::AND,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x21,
);
and64rr.requires_rex = true;
and64rr.is_commutative = true;
and64rr.required_features = vec!["64bit".into()];
self.instructions.push(and64rr);
let mut and64ri8 = Self::make_instr(
"AND64ri8",
X86Opcode::AND,
2,
vec![OperandType::Reg64, OperandType::Imm8],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x83,
);
and64ri8.requires_rex = true;
and64ri8.fixed_modrm = Some(0xE0);
and64ri8.is_commutative = true;
and64ri8.required_features = vec!["64bit".into()];
self.instructions.push(and64ri8);
let mut or32rr = Self::make_instr(
"OR32rr",
X86Opcode::OR,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x09,
);
or32rr.is_commutative = true;
self.instructions.push(or32rr);
let mut or32ri = Self::make_instr(
"OR32ri",
X86Opcode::OR,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0x81,
);
or32ri.fixed_modrm = Some(0xC8);
or32ri.is_commutative = true;
self.instructions.push(or32ri);
let mut or64rr = Self::make_instr(
"OR64rr",
X86Opcode::OR,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x09,
);
or64rr.requires_rex = true;
or64rr.is_commutative = true;
or64rr.required_features = vec!["64bit".into()];
self.instructions.push(or64rr);
let mut xor32rr = Self::make_instr(
"XOR32rr",
X86Opcode::XOR,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x31,
);
xor32rr.is_commutative = true;
self.instructions.push(xor32rr);
let mut xor64rr = Self::make_instr(
"XOR64rr",
X86Opcode::XOR,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x31,
);
xor64rr.requires_rex = true;
xor64rr.is_commutative = true;
xor64rr.required_features = vec!["64bit".into()];
self.instructions.push(xor64rr);
let not32r = Self::make_instr(
"NOT32r",
X86Opcode::NOT,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM2r,
X86OpcodeMap::OB,
0xF7,
);
self.instructions.push(not32r);
let mut not64r = Self::make_instr(
"NOT64r",
X86Opcode::NOT,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM2r,
X86OpcodeMap::OB,
0xF7,
);
not64r.requires_rex = true;
not64r.required_features = vec!["64bit".into()];
self.instructions.push(not64r);
let mut test32rr = Self::make_instr(
"TEST32rr",
X86Opcode::TEST,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x85,
);
test32rr.is_commutative = true;
test32rr.is_compare = true;
test32rr.can_fold_load = false;
self.instructions.push(test32rr);
let mut test32ri = Self::make_instr(
"TEST32ri",
X86Opcode::TEST,
2,
vec![OperandType::Reg32, OperandType::Imm32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xF7,
);
test32ri.is_compare = true;
test32ri.can_fold_load = false;
self.instructions.push(test32ri);
let mut test64rr = Self::make_instr(
"TEST64rr",
X86Opcode::TEST,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::OB,
0x85,
);
test64rr.requires_rex = true;
test64rr.is_commutative = true;
test64rr.is_compare = true;
test64rr.can_fold_load = false;
test64rr.required_features = vec!["64bit".into()];
self.instructions.push(test64rr);
}
fn gen_shift_rotate(&mut self) {
let mut shl32rcl = Self::make_instr(
"SHL32rCL",
X86Opcode::SHL,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xD3,
);
shl32rcl.implicit_uses = vec![1]; self.instructions.push(shl32rcl);
let shl32ri = Self::make_instr(
"SHL32ri",
X86Opcode::SHL,
2,
vec![OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xC1,
);
self.instructions.push(shl32ri);
let mut shl64rcl = Self::make_instr(
"SHL64rCL",
X86Opcode::SHL,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xD3,
);
shl64rcl.requires_rex = true;
shl64rcl.implicit_uses = vec![1];
shl64rcl.required_features = vec!["64bit".into()];
self.instructions.push(shl64rcl);
let mut shl64ri = Self::make_instr(
"SHL64ri",
X86Opcode::SHL,
2,
vec![OperandType::Reg64, OperandType::Imm8],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xC1,
);
shl64ri.requires_rex = true;
shl64ri.required_features = vec!["64bit".into()];
self.instructions.push(shl64ri);
let mut shr32rcl = Self::make_instr(
"SHR32rCL",
X86Opcode::SHR,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM5r,
X86OpcodeMap::OB,
0xD3,
);
shr32rcl.implicit_uses = vec![1]; self.instructions.push(shr32rcl);
let shr32ri = Self::make_instr(
"SHR32ri",
X86Opcode::SHR,
2,
vec![OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRM5r,
X86OpcodeMap::OB,
0xC1,
);
self.instructions.push(shr32ri);
let mut shr64rcl = Self::make_instr(
"SHR64rCL",
X86Opcode::SHR,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM5r,
X86OpcodeMap::OB,
0xD3,
);
shr64rcl.requires_rex = true;
shr64rcl.implicit_uses = vec![1];
shr64rcl.required_features = vec!["64bit".into()];
self.instructions.push(shr64rcl);
let mut sar32rcl = Self::make_instr(
"SAR32rCL",
X86Opcode::SAR,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM7r,
X86OpcodeMap::OB,
0xD3,
);
sar32rcl.implicit_uses = vec![1]; self.instructions.push(sar32rcl);
let sar32ri = Self::make_instr(
"SAR32ri",
X86Opcode::SAR,
2,
vec![OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRM7r,
X86OpcodeMap::OB,
0xC1,
);
self.instructions.push(sar32ri);
let mut sar64rcl = Self::make_instr(
"SAR64rCL",
X86Opcode::SAR,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM7r,
X86OpcodeMap::OB,
0xD3,
);
sar64rcl.requires_rex = true;
sar64rcl.implicit_uses = vec![1];
sar64rcl.required_features = vec!["64bit".into()];
self.instructions.push(sar64rcl);
let mut rol32rcl = Self::make_instr(
"ROL32rCL",
X86Opcode::ROL,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xD3,
);
rol32rcl.implicit_uses = vec![1];
self.instructions.push(rol32rcl);
let rol32ri = Self::make_instr(
"ROL32ri",
X86Opcode::ROL,
2,
vec![OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRM0r,
X86OpcodeMap::OB,
0xC1,
);
self.instructions.push(rol32ri);
let mut ror32rcl = Self::make_instr(
"ROR32rCL",
X86Opcode::ROR,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM1r,
X86OpcodeMap::OB,
0xD3,
);
ror32rcl.implicit_uses = vec![1];
self.instructions.push(ror32rcl);
let ror32ri = Self::make_instr(
"ROR32ri",
X86Opcode::ROR,
2,
vec![OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRM1r,
X86OpcodeMap::OB,
0xC1,
);
self.instructions.push(ror32ri);
let mut rcl32rcl = Self::make_instr(
"RCL32rCL",
X86Opcode::RCL,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM2r,
X86OpcodeMap::OB,
0xD3,
);
rcl32rcl.implicit_uses = vec![1];
self.instructions.push(rcl32rcl);
let mut rcr32rcl = Self::make_instr(
"RCR32rCL",
X86Opcode::RCR,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM3r,
X86OpcodeMap::OB,
0xD3,
);
rcr32rcl.implicit_uses = vec![1];
self.instructions.push(rcr32rcl);
let mut shld32rri8 = Self::make_instr(
"SHLD32rri8",
X86Opcode::SHLD,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TB,
0xA4,
);
shld32rri8.is_three_address = true;
self.instructions.push(shld32rri8);
let mut shrd32rri8 = Self::make_instr(
"SHRD32rri8",
X86Opcode::SHRD,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TB,
0xAC,
);
shrd32rri8.is_three_address = true;
self.instructions.push(shrd32rri8);
let mut shrd64rri8 = Self::make_instr(
"SHRD64rri8",
X86Opcode::SHRD,
3,
vec![OperandType::Reg64, OperandType::Reg64, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TB,
0xAC,
);
shrd64rri8.requires_rex = true;
shrd64rri8.is_three_address = true;
shrd64rri8.required_features = vec!["64bit".into()];
self.instructions.push(shrd64rri8);
}
fn gen_string_ops(&mut self) {
let mut movsb = Self::make_instr(
"MOVSB",
X86Opcode::MOVSB,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xA4,
);
movsb.may_load = true;
movsb.may_store = true;
movsb.implicit_uses = vec![6, 7]; movsb.implicit_defs = vec![6, 7]; movsb.encoding_prefix = Some(X86EncodingPrefix::None);
self.instructions.push(movsb);
let mut movsw = Self::make_instr(
"MOVSW",
X86Opcode::MOVSW,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xA5,
);
movsw.encoding_prefix = Some(X86EncodingPrefix::OpSize);
movsw.may_load = true;
movsw.may_store = true;
movsw.implicit_uses = vec![6, 7];
movsw.implicit_defs = vec![6, 7];
self.instructions.push(movsw);
let mut movsd_str = Self::make_instr(
"MOVSDstr",
X86Opcode::MOVSD_STR,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xA5,
);
movsd_str.may_load = true;
movsd_str.may_store = true;
movsd_str.implicit_uses = vec![6, 7];
movsd_str.implicit_defs = vec![6, 7];
self.instructions.push(movsd_str);
let mut movsq = Self::make_instr(
"MOVSQ",
X86Opcode::MOVSQ,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xA5,
);
movsq.requires_rex = true;
movsq.may_load = true;
movsq.may_store = true;
movsq.implicit_uses = vec![6, 7];
movsq.implicit_defs = vec![6, 7];
movsq.required_features = vec!["64bit".into()];
self.instructions.push(movsq);
let mut stosb = Self::make_instr(
"STOSB",
X86Opcode::STOSB,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAA,
);
stosb.may_store = true;
stosb.implicit_uses = vec![7]; stosb.implicit_defs = vec![7];
self.instructions.push(stosb);
let mut stosw = Self::make_instr(
"STOSW",
X86Opcode::STOSW,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAB,
);
stosw.encoding_prefix = Some(X86EncodingPrefix::OpSize);
stosw.may_store = true;
stosw.implicit_uses = vec![7];
stosw.implicit_defs = vec![7];
self.instructions.push(stosw);
let mut stosd = Self::make_instr(
"STOSD",
X86Opcode::STOSD_STR,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAB,
);
stosd.may_store = true;
stosd.implicit_uses = vec![7];
stosd.implicit_defs = vec![7];
self.instructions.push(stosd);
let mut stosq = Self::make_instr(
"STOSQ",
X86Opcode::STOSQ,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAB,
);
stosq.requires_rex = true;
stosq.may_store = true;
stosq.implicit_uses = vec![7];
stosq.implicit_defs = vec![7];
stosq.required_features = vec!["64bit".into()];
self.instructions.push(stosq);
let mut lodsb = Self::make_instr(
"LODSB",
X86Opcode::LODSB,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAC,
);
lodsb.may_load = true;
lodsb.implicit_uses = vec![6];
lodsb.implicit_defs = vec![6]; self.instructions.push(lodsb);
let mut scasb = Self::make_instr(
"SCASB",
X86Opcode::SCASB,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xAE,
);
scasb.is_compare = true;
scasb.implicit_uses = vec![7];
scasb.implicit_defs = vec![7];
self.instructions.push(scasb);
let mut cmpsb = Self::make_instr(
"CMPSB",
X86Opcode::CMPSB,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xA6,
);
cmpsb.is_compare = true;
cmpsb.implicit_uses = vec![6, 7];
cmpsb.implicit_defs = vec![6, 7];
self.instructions.push(cmpsb);
}
fn gen_control_flow(&mut self) {
let jcc_variants: [(&str, X86Opcode, u8); 16] = [
("JO", X86Opcode::JO, 0x80),
("JNO", X86Opcode::JNO, 0x81),
("JB", X86Opcode::JB, 0x82),
("JAE", X86Opcode::JAE, 0x83),
("JE", X86Opcode::JE, 0x84),
("JNE", X86Opcode::JNE, 0x85),
("JBE", X86Opcode::JBE, 0x86),
("JA", X86Opcode::JA, 0x87),
("JS", X86Opcode::JS, 0x88),
("JNS", X86Opcode::JNS, 0x89),
("JP", X86Opcode::JP, 0x8A),
("JNP", X86Opcode::JNP, 0x8B),
("JL", X86Opcode::JL, 0x8C),
("JGE", X86Opcode::JGE, 0x8D),
("JLE", X86Opcode::JLE, 0x8E),
("JG", X86Opcode::JG, 0x8F),
];
let mut jmp32r = Self::make_instr(
"JMP32r",
X86Opcode::JMP,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xFF,
);
jmp32r.is_terminator = true;
jmp32r.is_branch = true;
jmp32r.is_barrier = true;
jmp32r.can_fold_load = false;
self.instructions.push(jmp32r);
let mut jmp64r = Self::make_instr(
"JMP64r",
X86Opcode::JMP,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM4r,
X86OpcodeMap::OB,
0xFF,
);
jmp64r.requires_rex = true;
jmp64r.is_terminator = true;
jmp64r.is_branch = true;
jmp64r.is_barrier = true;
jmp64r.can_fold_load = false;
jmp64r.required_features = vec!["64bit".into()];
self.instructions.push(jmp64r);
for (mnemonic, opcode, op_byte) in jcc_variants.iter() {
let mut jcc1 = Self::make_instr(
&format!("{}_1", mnemonic),
*opcode,
1,
vec![OperandType::Label],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
*op_byte,
);
jcc1.is_terminator = true;
jcc1.is_branch = true;
jcc1.is_conditional = true;
jcc1.can_fold_load = false;
self.instructions.push(jcc1);
}
let mut call32r = Self::make_instr(
"CALL32r",
X86Opcode::CALL,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM2r,
X86OpcodeMap::OB,
0xFF,
);
call32r.is_call = true;
call32r.implicit_defs = vec![4]; call32r.implicit_uses = vec![4];
call32r.can_fold_load = false;
self.instructions.push(call32r);
let mut call64r = Self::make_instr(
"CALL64r",
X86Opcode::CALL,
1,
vec![OperandType::Reg64],
X86InstrFormat::MRM2r,
X86OpcodeMap::OB,
0xFF,
);
call64r.requires_rex = true;
call64r.is_call = true;
call64r.implicit_defs = vec![4];
call64r.implicit_uses = vec![4];
call64r.can_fold_load = false;
call64r.required_features = vec!["64bit".into()];
self.instructions.push(call64r);
let mut ret = Self::make_instr(
"RET",
X86Opcode::RET,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xC3,
);
ret.is_terminator = true;
ret.is_return = true;
ret.is_barrier = true;
ret.implicit_uses = vec![4]; ret.implicit_defs = vec![4];
ret.can_fold_load = false;
ret.sched_info = Some(X86SchedInfo {
latency: 1,
throughput: 1.0,
micro_ops: 1,
port_usage: 0x01,
});
self.instructions.push(ret);
let mut reti = Self::make_instr(
"RETI",
X86Opcode::RET,
1,
vec![OperandType::Imm16],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xC2,
);
reti.is_terminator = true;
reti.is_return = true;
reti.implicit_uses = vec![4];
reti.implicit_defs = vec![4];
reti.can_fold_load = false;
self.instructions.push(reti);
let mut loop_ = Self::make_instr(
"LOOP",
X86Opcode::LOOP,
1,
vec![OperandType::Label],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xE2,
);
loop_.is_branch = true;
loop_.is_conditional = true;
loop_.implicit_uses = vec![1]; loop_.implicit_defs = vec![1];
loop_.can_fold_load = false;
self.instructions.push(loop_);
let mut loope = Self::make_instr(
"LOOPE",
X86Opcode::LOOPE,
1,
vec![OperandType::Label],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xE1,
);
loope.is_branch = true;
loope.is_conditional = true;
loope.implicit_uses = vec![1];
loope.implicit_defs = vec![1];
loope.can_fold_load = false;
self.instructions.push(loope);
let mut loopne = Self::make_instr(
"LOOPNE",
X86Opcode::LOOPNE,
1,
vec![OperandType::Label],
X86InstrFormat::RawFrm,
X86OpcodeMap::OB,
0xE0,
);
loopne.is_branch = true;
loopne.is_conditional = true;
loopne.implicit_uses = vec![1];
loopne.implicit_defs = vec![1];
loopne.can_fold_load = false;
self.instructions.push(loopne);
}
fn gen_sse(&mut self) {
let sse_pd_feat = vec!["sse2".into()];
let sse_feat = vec!["sse".into()];
let mut movssrr = Self::make_instr(
"MOVSSrr",
X86Opcode::MOVSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x10,
);
movssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
self.instructions.push(movssrr);
let mut movssrm = Self::make_instr(
"MOVSSrm",
X86Opcode::MOVSS,
2,
vec![OperandType::XmmReg, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x10,
);
movssrm.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movssrm.may_load = true;
movssrm.required_features = sse_feat.clone();
self.instructions.push(movssrm);
let mut movssmr = Self::make_instr(
"MOVSSmr",
X86Opcode::MOVSS,
2,
vec![OperandType::Mem32, OperandType::XmmReg],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::TB,
0x11,
);
movssmr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movssmr.may_store = true;
movssmr.required_features = sse_feat.clone();
self.instructions.push(movssmr);
let mut movsdrr = Self::make_instr(
"MOVSDrr",
X86Opcode::MOVSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x10,
);
movsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
self.instructions.push(movsdrr);
let mut movsdrm = Self::make_instr(
"MOVSDrm",
X86Opcode::MOVSD,
2,
vec![OperandType::XmmReg, OperandType::Mem64],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x10,
);
movsdrm.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movsdrm.may_load = true;
movsdrm.required_features = sse_pd_feat.clone();
self.instructions.push(movsdrm);
let mut movsdmr = Self::make_instr(
"MOVSDmr",
X86Opcode::MOVSD,
2,
vec![OperandType::Mem64, OperandType::XmmReg],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::TB,
0x11,
);
movsdmr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movsdmr.may_store = true;
movsdmr.required_features = sse_pd_feat.clone();
self.instructions.push(movsdmr);
let mut addssrr = Self::make_instr(
"ADDSSrr",
X86Opcode::ADDSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
addssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
addssrr.required_features = sse_feat.clone();
self.instructions.push(addssrr);
let mut addsdrr = Self::make_instr(
"ADDSDrr",
X86Opcode::ADDSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
addsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
addsdrr.required_features = sse_pd_feat.clone();
self.instructions.push(addsdrr);
let mut subssrr = Self::make_instr(
"SUBSSrr",
X86Opcode::SUBSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5C,
);
subssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
subssrr.required_features = sse_feat.clone();
self.instructions.push(subssrr);
let mut subsdrr = Self::make_instr(
"SUBSDrr",
X86Opcode::SUBSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5C,
);
subsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
subsdrr.required_features = sse_pd_feat.clone();
self.instructions.push(subsdrr);
let mut mulssrr = Self::make_instr(
"MULSSrr",
X86Opcode::MULSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
mulssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
mulssrr.required_features = sse_feat.clone();
self.instructions.push(mulssrr);
let mut mulsdrr = Self::make_instr(
"MULSDrr",
X86Opcode::MULSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
mulsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
mulsdrr.required_features = sse_pd_feat.clone();
self.instructions.push(mulsdrr);
let mut divssrr = Self::make_instr(
"DIVSSrr",
X86Opcode::DIVSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5E,
);
divssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
divssrr.required_features = sse_feat.clone();
self.instructions.push(divssrr);
let mut divsdrr = Self::make_instr(
"DIVSDrr",
X86Opcode::DIVSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5E,
);
divsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
divsdrr.required_features = sse_pd_feat.clone();
self.instructions.push(divsdrr);
let mut sqrtssr = Self::make_instr(
"SQRTSSr",
X86Opcode::SQRTSS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x51,
);
sqrtssr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
sqrtssr.required_features = sse_feat.clone();
self.instructions.push(sqrtssr);
let mut sqrtsdr = Self::make_instr(
"SQRTSDr",
X86Opcode::SQRTSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x51,
);
sqrtsdr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
sqrtsdr.required_features = sse_pd_feat.clone();
self.instructions.push(sqrtsdr);
let mut cmpsrr = Self::make_instr(
"CMPSSrr",
X86Opcode::CMPSS,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xC2,
);
cmpsrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cmpsrr.is_compare = true;
cmpsrr.required_features = sse_feat.clone();
self.instructions.push(cmpsrr);
let mut cmpsdrr = Self::make_instr(
"CMPSDrr",
X86Opcode::CMPSD,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xC2,
);
cmpsdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cmpsdrr.is_compare = true;
cmpsdrr.required_features = sse_pd_feat.clone();
self.instructions.push(cmpsdrr);
let mut cvtsi2ssrr = Self::make_instr(
"CVTSI2SSrr",
X86Opcode::CVTSI2SS,
2,
vec![OperandType::XmmReg, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x2A,
);
cvtsi2ssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cvtsi2ssrr.is_convert = true;
cvtsi2ssrr.required_features = sse_feat.clone();
self.instructions.push(cvtsi2ssrr);
let mut cvtsi2ssrr64 = Self::make_instr(
"CVTSI2SSrr64",
X86Opcode::CVTSI2SS,
2,
vec![OperandType::XmmReg, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x2A,
);
cvtsi2ssrr64.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cvtsi2ssrr64.requires_rex = true;
cvtsi2ssrr64.is_convert = true;
cvtsi2ssrr64.required_features = vec!["sse".into(), "64bit".into()];
self.instructions.push(cvtsi2ssrr64);
let mut cvtsi2sdrr = Self::make_instr(
"CVTSI2SDrr",
X86Opcode::CVTSI2SD,
2,
vec![OperandType::XmmReg, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x2A,
);
cvtsi2sdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cvtsi2sdrr.is_convert = true;
cvtsi2sdrr.required_features = sse_pd_feat.clone();
self.instructions.push(cvtsi2sdrr);
let mut ucomissrr = Self::make_instr(
"UCOMISSrr",
X86Opcode::UCOMISS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x2E,
);
ucomissrr.is_compare = true;
ucomissrr.required_features = sse_feat.clone();
self.instructions.push(ucomissrr);
let mut ucomisdrr = Self::make_instr(
"UCOMISDrr",
X86Opcode::UCOMISD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x2E,
);
ucomisdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
ucomisdrr.is_compare = true;
ucomisdrr.required_features = sse_pd_feat.clone();
self.instructions.push(ucomisdrr);
let mut cvtss2sdrr = Self::make_instr(
"CVTSS2SDrr",
X86Opcode::CVTSS2SD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5A,
);
cvtss2sdrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cvtss2sdrr.is_convert = true;
cvtss2sdrr.required_features = sse_pd_feat.clone();
self.instructions.push(cvtss2sdrr);
let mut cvtsd2ssrr = Self::make_instr(
"CVTSD2SSrr",
X86Opcode::CVTSD2SS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5A,
);
cvtsd2ssrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
cvtsd2ssrr.is_convert = true;
cvtsd2ssrr.required_features = sse_pd_feat.clone();
self.instructions.push(cvtsd2ssrr);
let mut movdrr = Self::make_instr(
"MOVDrr",
X86Opcode::MOVD,
2,
vec![OperandType::XmmReg, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x6E,
);
movdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
movdrr.is_bitcast = true;
self.instructions.push(movdrr);
let mut movdrm = Self::make_instr(
"MOVDrm",
X86Opcode::MOVD,
2,
vec![OperandType::XmmReg, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x6E,
);
movdrm.encoding_prefix = Some(X86EncodingPrefix::OpSize);
movdrm.may_load = true;
movdrm.is_bitcast = true;
self.instructions.push(movdrm);
let mut movqrr = Self::make_instr(
"MOVQrr",
X86Opcode::MOVQ,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x7E,
);
movqrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movqrr.required_features = sse_pd_feat.clone();
self.instructions.push(movqrr);
}
fn gen_sse2(&mut self) {
let sse2_feat = vec!["sse2".into()];
let mut addpdrr = Self::make_instr(
"ADDPDrr",
X86Opcode::ADDPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
addpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
addpdrr.is_commutative = true;
addpdrr.required_features = sse2_feat.clone();
self.instructions.push(addpdrr);
let mut subpdrr = Self::make_instr(
"SUBPDrr",
X86Opcode::SUBPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5C,
);
subpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
subpdrr.required_features = sse2_feat.clone();
self.instructions.push(subpdrr);
let mut mulpdrr = Self::make_instr(
"MULPDrr",
X86Opcode::MULPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
mulpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
mulpdrr.is_commutative = true;
mulpdrr.required_features = sse2_feat.clone();
self.instructions.push(mulpdrr);
let mut divpdrr = Self::make_instr(
"DIVPDrr",
X86Opcode::DIVPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5E,
);
divpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
divpdrr.required_features = sse2_feat.clone();
self.instructions.push(divpdrr);
let mut addpsrr = Self::make_instr(
"ADDPSrr",
X86Opcode::ADDPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
addpsrr.is_commutative = true;
addpsrr.required_features = sse2_feat.clone();
self.instructions.push(addpsrr);
let mut mulpsrr = Self::make_instr(
"MULPSrr",
X86Opcode::MULPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
mulpsrr.is_commutative = true;
mulpsrr.required_features = sse2_feat.clone();
self.instructions.push(mulpsrr);
let mut paddbrr = Self::make_instr(
"PADDBrr",
X86Opcode::VPADDB,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xFC,
);
paddbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
paddbrr.is_commutative = true;
paddbrr.required_features = sse2_feat.clone();
self.instructions.push(paddbrr);
let mut paddwrr = Self::make_instr(
"PADDWrr",
X86Opcode::VPADDW,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xFD,
);
paddwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
paddwrr.is_commutative = true;
paddwrr.required_features = sse2_feat.clone();
self.instructions.push(paddwrr);
let mut padddrr = Self::make_instr(
"PADDDrr",
X86Opcode::VPADDD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xFE,
);
padddrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
padddrr.is_commutative = true;
padddrr.required_features = sse2_feat.clone();
self.instructions.push(padddrr);
let mut paddqrr = Self::make_instr(
"PADDQrr",
X86Opcode::VPADDQ,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xD4,
);
paddqrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
paddqrr.is_commutative = true;
paddqrr.required_features = sse2_feat.clone();
self.instructions.push(paddqrr);
let mut andpsrr = Self::make_instr(
"ANDPSrr",
X86Opcode::ANDPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x54,
);
andpsrr.is_commutative = true;
self.instructions.push(andpsrr);
let mut andnpsrr = Self::make_instr(
"ANDNPSrr",
X86Opcode::ANDNPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x55,
);
self.instructions.push(andnpsrr);
let mut orpsrr = Self::make_instr(
"ORPSrr",
X86Opcode::ORPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x56,
);
orpsrr.is_commutative = true;
self.instructions.push(orpsrr);
let mut xorpsrr = Self::make_instr(
"XORPSrr",
X86Opcode::XORPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x57,
);
xorpsrr.is_commutative = true;
self.instructions.push(xorpsrr);
let mut sqrtpsr = Self::make_instr(
"SQRTPSr",
X86Opcode::SQRTPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x51,
);
sqrtpsr.required_features = sse2_feat.clone();
self.instructions.push(sqrtpsr);
let mut rcppsr = Self::make_instr(
"RCPPSr",
X86Opcode::RCPPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x53,
);
rcppsr.required_features = sse2_feat.clone();
self.instructions.push(rcppsr);
let mut cvtdq2psrr = Self::make_instr(
"CVTDQ2PSrr",
X86Opcode::CVTDQ2PS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5B,
);
cvtdq2psrr.is_convert = true;
cvtdq2psrr.required_features = sse2_feat.clone();
self.instructions.push(cvtdq2psrr);
let mut cvtps2dqrr = Self::make_instr(
"CVTPS2DQrr",
X86Opcode::CVTPS2DQ,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5B,
);
cvtps2dqrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
cvtps2dqrr.is_convert = true;
cvtps2dqrr.required_features = sse2_feat.clone();
self.instructions.push(cvtps2dqrr);
let mut pshufdrri = Self::make_instr(
"PSHUFDri",
X86Opcode::PSHUFD,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x70,
);
pshufdrri.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pshufdrri.required_features = sse2_feat.clone();
self.instructions.push(pshufdrri);
let mut pshufhwrri = Self::make_instr(
"PSHUFHWri",
X86Opcode::PSHUFHW,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x70,
);
pshufhwrri.encoding_prefix = Some(X86EncodingPrefix::RepNE);
pshufhwrri.required_features = sse2_feat.clone();
self.instructions.push(pshufhwrri);
let mut pshuflwrri = Self::make_instr(
"PSHUFLWri",
X86Opcode::PSHUFLW,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x70,
);
pshuflwrri.encoding_prefix = Some(X86EncodingPrefix::RepNE);
pshuflwrri.required_features = sse2_feat.clone();
self.instructions.push(pshuflwrri);
let mut andpdrr = Self::make_instr(
"ANDPDrr",
X86Opcode::ANDPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x54,
);
andpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
andpdrr.is_commutative = true;
self.instructions.push(andpdrr);
}
fn gen_sse3_ssse3(&mut self) {
let sse3_feat = vec!["sse3".into()];
let ssse3_feat = vec!["ssse3".into()];
let mut addsubpsrr = Self::make_instr(
"ADDSUBPSrr",
X86Opcode::ADDSUBPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xD0,
);
addsubpsrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
addsubpsrr.required_features = sse3_feat.clone();
self.instructions.push(addsubpsrr);
let mut addsubpdrr = Self::make_instr(
"ADDSUBPDrr",
X86Opcode::ADDSUBPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xD0,
);
addsubpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
addsubpdrr.required_features = sse3_feat.clone();
self.instructions.push(addsubpdrr);
let mut haddpsrr = Self::make_instr(
"HADDPSrr",
X86Opcode::HADDPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x7C,
);
haddpsrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
haddpsrr.required_features = sse3_feat.clone();
self.instructions.push(haddpsrr);
let mut haddpdrr = Self::make_instr(
"HADDPDrr",
X86Opcode::HADDPD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x7C,
);
haddpdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
haddpdrr.required_features = sse3_feat.clone();
self.instructions.push(haddpdrr);
let mut hsubpsrr = Self::make_instr(
"HSUBPSrr",
X86Opcode::HSUBPS,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x7D,
);
hsubpsrr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
hsubpsrr.required_features = sse3_feat.clone();
self.instructions.push(hsubpsrr);
let mut movslduprr = Self::make_instr(
"MOVSLDUPrr",
X86Opcode::MOVSLDUP,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x12,
);
movslduprr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movslduprr.required_features = sse3_feat.clone();
self.instructions.push(movslduprr);
let mut movshduprr = Self::make_instr(
"MOVSHDUPrr",
X86Opcode::MOVSHDUP,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x16,
);
movshduprr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movshduprr.required_features = sse3_feat.clone();
self.instructions.push(movshduprr);
let mut movdduprr = Self::make_instr(
"MOVDDUPrr",
X86Opcode::MOVDDUP,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x12,
);
movdduprr.encoding_prefix = Some(X86EncodingPrefix::RepNE);
movdduprr.required_features = sse3_feat.clone();
self.instructions.push(movdduprr);
let mut phaddwrr = Self::make_instr(
"PHADDWrr",
X86Opcode::PHADDW,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x01,
);
phaddwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
phaddwrr.required_features = ssse3_feat.clone();
self.instructions.push(phaddwrr);
let mut phadddrr = Self::make_instr(
"PHADDDrr",
X86Opcode::PHADDD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x02,
);
phadddrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
phadddrr.required_features = ssse3_feat.clone();
self.instructions.push(phadddrr);
let mut phsubwrr = Self::make_instr(
"PHSUBWrr",
X86Opcode::PHSUBW,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x05,
);
phsubwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
phsubwrr.required_features = ssse3_feat.clone();
self.instructions.push(phsubwrr);
let mut phsubdrr = Self::make_instr(
"PHSUBDrr",
X86Opcode::PHSUBD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x06,
);
phsubdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
phsubdrr.required_features = ssse3_feat.clone();
self.instructions.push(phsubdrr);
let mut psignbrr = Self::make_instr(
"PSIGNBrr",
X86Opcode::PSIGNB,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x08,
);
psignbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
psignbrr.required_features = ssse3_feat.clone();
self.instructions.push(psignbrr);
let mut pabsbrr = Self::make_instr(
"PABSBrr",
X86Opcode::PABSB,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x1C,
);
pabsbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pabsbrr.required_features = ssse3_feat.clone();
self.instructions.push(pabsbrr);
}
fn gen_sse41_sse42(&mut self) {
let sse41_feat = vec!["sse4.1".into()];
let sse42_feat = vec!["sse4.2".into()];
let mut blendpsrri = Self::make_instr(
"BLENDPSrri",
X86Opcode::BLENDPS,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x0C,
);
blendpsrri.encoding_prefix = Some(X86EncodingPrefix::OpSize);
blendpsrri.required_features = sse41_feat.clone();
self.instructions.push(blendpsrri);
let mut blendvpsrr = Self::make_instr(
"BLENDVPSrr",
X86Opcode::BLENDVPS,
3,
vec![
OperandType::XmmReg,
OperandType::XmmReg,
OperandType::XmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x14,
);
blendvpsrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
blendvpsrr.implicit_uses = vec![16]; blendvpsrr.required_features = sse41_feat.clone();
self.instructions.push(blendvpsrr);
let mut dppsrri = Self::make_instr(
"DPPSrri",
X86Opcode::DPPS,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x40,
);
dppsrri.encoding_prefix = Some(X86EncodingPrefix::OpSize);
dppsrri.required_features = sse41_feat.clone();
self.instructions.push(dppsrri);
let mut dppdrri = Self::make_instr(
"DPPDrri",
X86Opcode::DPPD,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x41,
);
dppdrri.encoding_prefix = Some(X86EncodingPrefix::OpSize);
dppdrri.required_features = sse41_feat.clone();
self.instructions.push(dppdrri);
let mut extractpsrr = Self::make_instr(
"EXTRACTPSrr",
X86Opcode::EXTRACTPS,
3,
vec![OperandType::Reg32, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TA,
0x17,
);
extractpsrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
extractpsrr.required_features = sse41_feat.clone();
self.instructions.push(extractpsrr);
let mut insertpsrr = Self::make_instr(
"INSERTPSrr",
X86Opcode::INSERTPS,
3,
vec![OperandType::XmmReg, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x21,
);
insertpsrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
insertpsrr.required_features = sse41_feat.clone();
self.instructions.push(insertpsrr);
let mut pmulldrr = Self::make_instr(
"PMULLDrr",
X86Opcode::PMULLD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x40,
);
pmulldrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pmulldrr.required_features = sse41_feat.clone();
self.instructions.push(pmulldrr);
let mut pminsbrr = Self::make_instr(
"PMINSBrr",
X86Opcode::PMINSB,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x38,
);
pminsbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pminsbrr.required_features = sse41_feat.clone();
self.instructions.push(pminsbrr);
let mut pminsdrr = Self::make_instr(
"PMINSDrr",
X86Opcode::PMINSD,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x39,
);
pminsdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pminsdrr.required_features = sse41_feat.clone();
self.instructions.push(pminsdrr);
let mut pcmpeqqrr = Self::make_instr(
"PCMPEQQrr",
X86Opcode::PCMPEQQ,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x29,
);
pcmpeqqrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pcmpeqqrr.is_compare = true;
pcmpeqqrr.required_features = sse41_feat.clone();
self.instructions.push(pcmpeqqrr);
let mut packusdwrr = Self::make_instr(
"PACKUSDWrr",
X86Opcode::PACKUSDW,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x2B,
);
packusdwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
packusdwrr.required_features = sse41_feat.clone();
self.instructions.push(packusdwrr);
let mut pextrbrr = Self::make_instr(
"PEXTRBrr",
X86Opcode::PEXTRB,
3,
vec![OperandType::Reg32, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TA,
0x14,
);
pextrbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pextrbrr.required_features = sse41_feat.clone();
self.instructions.push(pextrbrr);
let mut pextrwrr = Self::make_instr(
"PEXTRWrr",
X86Opcode::PEXTRW,
3,
vec![OperandType::Reg32, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TB,
0xC5,
);
pextrwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pextrwrr.required_features = sse41_feat.clone();
self.instructions.push(pextrwrr);
let mut pextrdrr = Self::make_instr(
"PEXTRDrr",
X86Opcode::PEXTRD,
3,
vec![OperandType::Reg32, OperandType::XmmReg, OperandType::Imm8],
X86InstrFormat::MRMDestReg,
X86OpcodeMap::TA,
0x16,
);
pextrdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pextrdrr.required_features = sse41_feat.clone();
self.instructions.push(pextrdrr);
let mut pinsrbrr = Self::make_instr(
"PINSRBrr",
X86Opcode::PINSRB,
3,
vec![OperandType::XmmReg, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x20,
);
pinsrbrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pinsrbrr.required_features = sse41_feat.clone();
self.instructions.push(pinsrbrr);
let mut pinsrwrr = Self::make_instr(
"PINSRWrr",
X86Opcode::PINSRW,
3,
vec![OperandType::XmmReg, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xC4,
);
pinsrwrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pinsrwrr.required_features = sse41_feat.clone();
self.instructions.push(pinsrwrr);
let mut pinsrdrr = Self::make_instr(
"PINSRDrr",
X86Opcode::PINSRD,
3,
vec![OperandType::XmmReg, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x22,
);
pinsrdrr.encoding_prefix = Some(X86EncodingPrefix::OpSize);
pinsrdrr.required_features = sse41_feat.clone();
self.instructions.push(pinsrdrr);
let mut crc32b = Self::make_instr(
"CRC32r32r8",
X86Opcode::CRC32,
2,
vec![OperandType::Reg32, OperandType::Reg8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF0,
);
crc32b.encoding_prefix = Some(X86EncodingPrefix::RepNE);
crc32b.required_features = sse42_feat.clone();
self.instructions.push(crc32b);
let mut crc32r = Self::make_instr(
"CRC32r32r32",
X86Opcode::CRC32,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF1,
);
crc32r.encoding_prefix = Some(X86EncodingPrefix::RepNE);
crc32r.required_features = sse42_feat.clone();
self.instructions.push(crc32r);
}
fn gen_avx_avx2(&mut self) {
let avx_feat = vec!["avx".into()];
let avx2_feat = vec!["avx2".into()];
let mut vaddpsrr = Self::make_instr(
"VADDPSrr",
X86Opcode::VADDPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
vaddpsrr.is_vex = true;
vaddpsrr.vex_l = Some(true);
vaddpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vaddpsrr.is_three_address = true;
vaddpsrr.is_commutative = true;
vaddpsrr.required_features = avx_feat.clone();
self.instructions.push(vaddpsrr);
let mut vaddpdrm = Self::make_instr(
"VADDPDrm",
X86Opcode::VADDPD,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::Mem256,
],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x58,
);
vaddpdrm.is_vex = true;
vaddpdrm.vex_l = Some(true);
vaddpdrm.vex_w = Some(false);
vaddpdrm.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vaddpdrm.may_load = true;
vaddpdrm.is_three_address = true;
vaddpdrm.is_commutative = true;
vaddpdrm.required_features = avx_feat.clone();
self.instructions.push(vaddpdrm);
let mut vmulpsrr = Self::make_instr(
"VMULPSrr",
X86Opcode::VMULPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
vmulpsrr.is_vex = true;
vmulpsrr.vex_l = Some(true);
vmulpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vmulpsrr.is_three_address = true;
vmulpsrr.is_commutative = true;
vmulpsrr.required_features = avx_feat.clone();
self.instructions.push(vmulpsrr);
let mut vmulpdrm = Self::make_instr(
"VMULPDrm",
X86Opcode::VMULPD,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::Mem256,
],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x59,
);
vmulpdrm.is_vex = true;
vmulpdrm.vex_l = Some(true);
vmulpdrm.vex_w = Some(false);
vmulpdrm.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vmulpdrm.may_load = true;
vmulpdrm.is_three_address = true;
vmulpdrm.is_commutative = true;
vmulpdrm.required_features = avx_feat.clone();
self.instructions.push(vmulpdrm);
let mut vdivpsrr = Self::make_instr(
"VDIVPSrr",
X86Opcode::VDIVPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5E,
);
vdivpsrr.is_vex = true;
vdivpsrr.vex_l = Some(true);
vdivpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vdivpsrr.is_three_address = true;
vdivpsrr.required_features = avx_feat.clone();
self.instructions.push(vdivpsrr);
let mut vandpsrr = Self::make_instr(
"VANDPSrr",
X86Opcode::VANDPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x54,
);
vandpsrr.is_vex = true;
vandpsrr.vex_l = Some(true);
vandpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vandpsrr.is_three_address = true;
vandpsrr.is_commutative = true;
vandpsrr.required_features = avx_feat.clone();
self.instructions.push(vandpsrr);
let mut vandnpsrr = Self::make_instr(
"VANDNPSrr",
X86Opcode::VANDNPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x55,
);
vandnpsrr.is_vex = true;
vandnpsrr.vex_l = Some(true);
vandnpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vandnpsrr.is_three_address = true;
vandnpsrr.required_features = avx_feat.clone();
self.instructions.push(vandnpsrr);
let mut vorpsrr = Self::make_instr(
"VORPSrr",
X86Opcode::VORPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x56,
);
vorpsrr.is_vex = true;
vorpsrr.vex_l = Some(true);
vorpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vorpsrr.is_three_address = true;
vorpsrr.is_commutative = true;
vorpsrr.required_features = avx_feat.clone();
self.instructions.push(vorpsrr);
let mut vxorpsrr = Self::make_instr(
"VXORPSrr",
X86Opcode::VXORPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x57,
);
vxorpsrr.is_vex = true;
vxorpsrr.vex_l = Some(true);
vxorpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vxorpsrr.is_three_address = true;
vxorpsrr.is_commutative = true;
vxorpsrr.required_features = avx_feat.clone();
self.instructions.push(vxorpsrr);
let mut vbroadcastssrm = Self::make_instr(
"VBROADCASTSSrm",
X86Opcode::VBROADCASTSS,
2,
vec![OperandType::YmmReg, OperandType::Mem32],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TA,
0x18,
);
vbroadcastssrm.is_vex = true;
vbroadcastssrm.vex_l = Some(true);
vbroadcastssrm.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vbroadcastssrm.may_load = true;
vbroadcastssrm.required_features = avx_feat.clone();
self.instructions.push(vbroadcastssrm);
let mut vbroadcastsdrr = Self::make_instr(
"VBROADCASTSDrr",
X86Opcode::VBROADCASTSD,
2,
vec![OperandType::YmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x19,
);
vbroadcastsdrr.is_vex = true;
vbroadcastsdrr.vex_l = Some(true);
vbroadcastsdrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vbroadcastsdrr.required_features = avx_feat.clone();
self.instructions.push(vbroadcastsdrr);
let mut vpermilpsrr = Self::make_instr(
"VPERMILPSrr",
X86Opcode::VPERMILPS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x0C,
);
vpermilpsrr.is_vex = true;
vpermilpsrr.vex_l = Some(true);
vpermilpsrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpermilpsrr.is_three_address = true;
vpermilpsrr.required_features = avx_feat.clone();
self.instructions.push(vpermilpsrr);
let mut vperm2f128rr = Self::make_instr(
"VPERM2F128rr",
X86Opcode::VPERM2F128,
4,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x06,
);
vperm2f128rr.is_vex = true;
vperm2f128rr.vex_l = Some(true);
vperm2f128rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vperm2f128rr.is_three_address = true;
vperm2f128rr.required_features = avx_feat.clone();
self.instructions.push(vperm2f128rr);
let mut vzeroall = Self::make_instr(
"VZEROALL",
X86Opcode::VZEROALL,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
0x77,
);
vzeroall.is_vex = true;
vzeroall.vex_l = Some(true);
vzeroall.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vzeroall.has_side_effects = true;
vzeroall.can_fold_load = false;
vzeroall.required_features = avx_feat.clone();
self.instructions.push(vzeroall);
let mut vzeroupper = Self::make_instr(
"VZEROUPPER",
X86Opcode::VZEROUPPER,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
0x77,
);
vzeroupper.is_vex = true;
vzeroupper.vex_l = Some(false);
vzeroupper.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vzeroupper.has_side_effects = true;
vzeroupper.can_fold_load = false;
vzeroupper.required_features = avx_feat.clone();
self.instructions.push(vzeroupper);
let mut vpbroadcastbrrm = Self::make_instr(
"VPBROADCASTBrm",
X86Opcode::VPBROADCASTB,
2,
vec![OperandType::YmmReg, OperandType::Mem8],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::T8,
0x78,
);
vpbroadcastbrrm.is_vex = true;
vpbroadcastbrrm.vex_l = Some(true);
vpbroadcastbrrm.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpbroadcastbrrm.may_load = true;
vpbroadcastbrrm.required_features = avx2_feat.clone();
self.instructions.push(vpbroadcastbrrm);
let mut vpbroadcastdrr = Self::make_instr(
"VPBROADCASTDrr",
X86Opcode::VPBROADCASTD,
2,
vec![OperandType::YmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x58,
);
vpbroadcastdrr.is_vex = true;
vpbroadcastdrr.vex_l = Some(true);
vpbroadcastdrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpbroadcastdrr.required_features = avx2_feat.clone();
self.instructions.push(vpbroadcastdrr);
let mut vpbroadcastqrr = Self::make_instr(
"VPBROADCASTQrr",
X86Opcode::VPBROADCASTQ,
2,
vec![OperandType::YmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x59,
);
vpbroadcastqrr.is_vex = true;
vpbroadcastqrr.vex_l = Some(true);
vpbroadcastqrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpbroadcastqrr.required_features = avx2_feat.clone();
self.instructions.push(vpbroadcastqrr);
let mut vpermqrr = Self::make_instr(
"VPERMQrr",
X86Opcode::VPERMQ,
3,
vec![OperandType::YmmReg, OperandType::YmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x00,
);
vpermqrr.is_vex = true;
vpermqrr.vex_l = Some(true);
vpermqrr.vex_w = Some(true);
vpermqrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpermqrr.required_features = avx2_feat.clone();
self.instructions.push(vpermqrr);
let mut vpermpdrr = Self::make_instr(
"VPERMPDrr",
X86Opcode::VPERMPD,
3,
vec![OperandType::YmmReg, OperandType::YmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x01,
);
vpermpdrr.is_vex = true;
vpermpdrr.vex_l = Some(true);
vpermpdrr.vex_w = Some(true);
vpermpdrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpermpdrr.required_features = avx2_feat.clone();
self.instructions.push(vpermpdrr);
let mut vpgatherddrm = Self::make_instr(
"VPGATHERDDrm",
X86Opcode::VPGATHERDD,
3,
vec![
OperandType::XmmReg,
OperandType::XmmReg,
OperandType::Mem128,
],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::T8,
0x90,
);
vpgatherddrm.is_vex = true;
vpgatherddrm.vex_l = Some(false);
vpgatherddrm.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vpgatherddrm.may_load = true;
vpgatherddrm.has_side_effects = true;
vpgatherddrm.required_features = avx2_feat.clone();
self.instructions.push(vpgatherddrm);
}
fn gen_avx512(&mut self) {
let avx512f_feat: Vec<String> = vec!["avx512f".into()];
let avx512bw_feat: Vec<String> = vec!["avx512bw".into()];
let avx512dq_feat: Vec<String> = vec!["avx512dq".into()];
let mut vpadddz128rr = Self::make_instr(
"VPADDDZ128rr",
X86Opcode::VPADDD_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xFE,
);
vpadddz128rr.is_evex = true;
vpadddz128rr.evex_tuple = Some(X86EvexTuple::FV);
vpadddz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpadddz128rr.is_three_address = true;
vpadddz128rr.is_commutative = true;
vpadddz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vpadddz128rr);
let mut vpadddz128rrkz = Self::make_instr(
"VPADDDZ128rrkz",
X86Opcode::VPADDD_Z_MASK,
4,
vec![
OperandType::ZmmReg,
OperandType::VK,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xFE,
);
vpadddz128rrkz.is_evex = true;
vpadddz128rrkz.evex_tuple = Some(X86EvexTuple::FV);
vpadddz128rrkz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpadddz128rrkz.is_three_address = true;
vpadddz128rrkz.is_commutative = true;
vpadddz128rrkz.required_features = avx512f_feat.clone();
self.instructions.push(vpadddz128rrkz);
let mut vaddpsz128rr = Self::make_instr(
"VADDPSZ128rr",
X86Opcode::VADDPS_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
vaddpsz128rr.is_evex = true;
vaddpsz128rr.evex_tuple = Some(X86EvexTuple::FV);
vaddpsz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vaddpsz128rr.is_three_address = true;
vaddpsz128rr.is_commutative = true;
vaddpsz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vaddpsz128rr);
let mut vaddpsz128rrb = Self::make_instr(
"VADDPSZ128rrb",
X86Opcode::VADDPS_Z_RND,
4,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
vaddpsz128rrb.is_evex = true;
vaddpsz128rrb.evex_tuple = Some(X86EvexTuple::FV);
vaddpsz128rrb.evex_rounding = true;
vaddpsz128rrb.encoding_prefix = Some(X86EncodingPrefix::Evex);
vaddpsz128rrb.is_three_address = true;
vaddpsz128rrb.is_commutative = true;
vaddpsz128rrb.required_features = avx512f_feat.clone();
self.instructions.push(vaddpsz128rrb);
let mut vaddpdz128rr = Self::make_instr(
"VADDPDZ128rr",
X86Opcode::VADDPD_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x58,
);
vaddpdz128rr.is_evex = true;
vaddpdz128rr.evex_tuple = Some(X86EvexTuple::FV);
vaddpdz128rr.vex_w = Some(true);
vaddpdz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vaddpdz128rr.is_three_address = true;
vaddpdz128rr.is_commutative = true;
vaddpdz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vaddpdz128rr);
let mut vmulpsz128rr = Self::make_instr(
"VMULPSZ128rr",
X86Opcode::VMULPS_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x59,
);
vmulpsz128rr.is_evex = true;
vmulpsz128rr.evex_tuple = Some(X86EvexTuple::FV);
vmulpsz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmulpsz128rr.is_three_address = true;
vmulpsz128rr.is_commutative = true;
vmulpsz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vmulpsz128rr);
let mut vandpsz128rr = Self::make_instr(
"VANDPSZ128rr",
X86Opcode::VANDPS_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x54,
);
vandpsz128rr.is_evex = true;
vandpsz128rr.evex_tuple = Some(X86EvexTuple::FV);
vandpsz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vandpsz128rr.is_three_address = true;
vandpsz128rr.is_commutative = true;
vandpsz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vandpsz128rr);
let mut vandnpsz128rr = Self::make_instr(
"VANDNPSZ128rr",
X86Opcode::VANDNPS_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x55,
);
vandnpsz128rr.is_evex = true;
vandnpsz128rr.evex_tuple = Some(X86EvexTuple::FV);
vandnpsz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vandnpsz128rr.is_three_address = true;
vandnpsz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vandnpsz128rr);
let mut vpanddz128rr = Self::make_instr(
"VPANDDZ128rr",
X86Opcode::VPANDD_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xDB,
);
vpanddz128rr.is_evex = true;
vpanddz128rr.evex_tuple = Some(X86EvexTuple::FV);
vpanddz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpanddz128rr.is_three_address = true;
vpanddz128rr.is_commutative = true;
vpanddz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vpanddz128rr);
let mut vcvtdq2psz128rr = Self::make_instr(
"VCVTDQ2PSZ128rr",
X86Opcode::VCVTDQ2PS_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x5B,
);
vcvtdq2psz128rr.is_evex = true;
vcvtdq2psz128rr.evex_tuple = Some(X86EvexTuple::FV);
vcvtdq2psz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcvtdq2psz128rr.is_convert = true;
vcvtdq2psz128rr.required_features = avx512f_feat.clone();
self.instructions.push(vcvtdq2psz128rr);
let mut vprolvdzz = Self::make_instr(
"VPROLVDZrr",
X86Opcode::VPROLVD_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x15,
);
vprolvdzz.is_evex = true;
vprolvdzz.evex_tuple = Some(X86EvexTuple::FV);
vprolvdzz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vprolvdzz.required_features = avx512f_feat.clone();
self.instructions.push(vprolvdzz);
let mut vmovdqa32zrr = Self::make_instr(
"VMOVDQA32Zrr",
X86Opcode::VMOVDQA32_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x6F,
);
vmovdqa32zrr.is_evex = true;
vmovdqa32zrr.evex_tuple = Some(X86EvexTuple::FV);
vmovdqa32zrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmovdqa32zrr.required_features = avx512f_feat.clone();
self.instructions.push(vmovdqa32zrr);
let mut vmovdqu32zrm = Self::make_instr(
"VMOVDQU32Zrm",
X86Opcode::VMOVDQU32_Z,
2,
vec![OperandType::ZmmReg, OperandType::Mem512],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::TB,
0x6F,
);
vmovdqu32zrm.is_evex = true;
vmovdqu32zrm.evex_tuple = Some(X86EvexTuple::FV);
vmovdqu32zrm.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmovdqu32zrm.may_load = true;
vmovdqu32zrm.required_features = avx512f_feat.clone();
self.instructions.push(vmovdqu32zrm);
let mut kaddwrr = Self::make_instr(
"KADDWrr",
X86Opcode::KADDW_Z,
3,
vec![OperandType::VK, OperandType::VK, OperandType::VK],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x4A,
);
kaddwrr.is_vex = true;
kaddwrr.vex_l = Some(false);
kaddwrr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
kaddwrr.required_features = avx512bw_feat.clone();
self.instructions.push(kaddwrr);
let mut kshiftlwri = Self::make_instr(
"KSHIFTLWri",
X86Opcode::KSHIFTLW_Z,
3,
vec![OperandType::VK, OperandType::VK, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x32,
);
kshiftlwri.is_vex = true;
kshiftlwri.vex_l = Some(false);
kshiftlwri.encoding_prefix = Some(X86EncodingPrefix::Vex3);
kshiftlwri.required_features = avx512bw_feat.clone();
self.instructions.push(kshiftlwri);
let mut vpbroadcastdzr = Self::make_instr(
"VPBROADCASTDZrr",
X86Opcode::VPBROADCASTD_Z,
2,
vec![OperandType::ZmmReg, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x7C,
);
vpbroadcastdzr.is_evex = true;
vpbroadcastdzr.evex_tuple = Some(X86EvexTuple::T1S);
vpbroadcastdzr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpbroadcastdzr.required_features = avx512f_feat.clone();
self.instructions.push(vpbroadcastdzr);
let mut vbroadcastsszr = Self::make_instr(
"VBROADCASTSSZrr",
X86Opcode::VBROADCASTSS_Z,
2,
vec![OperandType::ZmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x18,
);
vbroadcastsszr.is_evex = true;
vbroadcastsszr.evex_tuple = Some(X86EvexTuple::T1S);
vbroadcastsszr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vbroadcastsszr.required_features = avx512f_feat.clone();
self.instructions.push(vbroadcastsszr);
let mut vcompresspsz = Self::make_instr(
"VCOMPRESSPSZrr",
X86Opcode::VCOMPRESSPS_Z,
3,
vec![OperandType::ZmmReg, OperandType::VK, OperandType::ZmmReg],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::T8,
0x8A,
);
vcompresspsz.is_evex = true;
vcompresspsz.evex_tuple = Some(X86EvexTuple::FV);
vcompresspsz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcompresspsz.may_store = true;
vcompresspsz.required_features = avx512f_feat.clone();
self.instructions.push(vcompresspsz);
let mut vexpandpsz = Self::make_instr(
"VEXPANDPSZrr",
X86Opcode::VEXPANDPS_Z,
3,
vec![OperandType::ZmmReg, OperandType::VK, OperandType::ZmmReg],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::T8,
0x88,
);
vexpandpsz.is_evex = true;
vexpandpsz.evex_tuple = Some(X86EvexTuple::FV);
vexpandpsz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vexpandpsz.may_load = true;
vexpandpsz.required_features = avx512f_feat.clone();
self.instructions.push(vexpandpsz);
let mut vpgatherddz = Self::make_instr(
"VPGATHERDDZrm",
X86Opcode::VPGATHERDD_Z,
3,
vec![OperandType::ZmmReg, OperandType::VK, OperandType::Mem256],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::T8,
0x90,
);
vpgatherddz.is_evex = true;
vpgatherddz.evex_tuple = Some(X86EvexTuple::T1S);
vpgatherddz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpgatherddz.may_load = true;
vpgatherddz.has_side_effects = true;
vpgatherddz.required_features = avx512f_feat.clone();
self.instructions.push(vpgatherddz);
let mut vp2intersectd = Self::make_instr(
"VP2INTERSECTDrr",
X86Opcode::VP2INTERSECTD,
3,
vec![OperandType::VK, OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x68,
);
vp2intersectd.is_evex = true;
vp2intersectd.evex_tuple = Some(X86EvexTuple::FV);
vp2intersectd.encoding_prefix = Some(X86EncodingPrefix::Evex);
vp2intersectd.required_features = vec!["avx512vp2intersect".into()];
self.instructions.push(vp2intersectd);
let bf16_feat = vec!["avx512bf16".into()];
let mut vcvtneps2bf16z = Self::make_instr(
"VCVTNEPS2BF16Zrr",
X86Opcode::VCVTNE2PS2BF16_Z,
2,
vec![OperandType::YmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x72,
);
vcvtneps2bf16z.is_evex = true;
vcvtneps2bf16z.evex_tuple = Some(X86EvexTuple::FV);
vcvtneps2bf16z.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcvtneps2bf16z.is_convert = true;
vcvtneps2bf16z.required_features = bf16_feat.clone();
self.instructions.push(vcvtneps2bf16z);
let mut vdpbf16psz = Self::make_instr(
"VDPBF16PSZrr",
X86Opcode::VDPBF16PS_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x52,
);
vdpbf16psz.is_evex = true;
vdpbf16psz.evex_tuple = Some(X86EvexTuple::FV);
vdpbf16psz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vdpbf16psz.required_features = bf16_feat.clone();
self.instructions.push(vdpbf16psz);
let avx512vnni_feat = vec!["avx512vnni".into()];
let mut vpdpbssdz = Self::make_instr(
"VPDPBSSDZrr",
X86Opcode::VPDPBUSD,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x50,
);
vpdpbssdz.is_evex = true;
vpdpbssdz.evex_tuple = Some(X86EvexTuple::FV);
vpdpbssdz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpdpbssdz.required_features = avx512vnni_feat.clone();
self.instructions.push(vpdpbssdz);
let avx512vl_feat: Vec<String> = vec!["avx512vl".into()];
let mut vpabsbz128rr = Self::make_instr(
"VPABSBZ128rr",
X86Opcode::VPABSB_Z,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x1C,
);
vpabsbz128rr.is_evex = true;
vpabsbz128rr.evex_tuple = Some(X86EvexTuple::FV);
vpabsbz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpabsbz128rr.required_features = avx512vl_feat.clone();
self.instructions.push(vpabsbz128rr);
let mut vpabswz128rr = Self::make_instr(
"VPABSWZ128rr",
X86Opcode::VPABSW_Z,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x1D,
);
vpabswz128rr.is_evex = true;
vpabswz128rr.evex_tuple = Some(X86EvexTuple::FV);
vpabswz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpabswz128rr.required_features = avx512vl_feat.clone();
self.instructions.push(vpabswz128rr);
let avx512bitalg_feat: Vec<String> = vec!["avx512bitalg".into()];
let mut vpopcntbz128rr = Self::make_instr(
"VPOPCNTBZ128rr",
X86Opcode::VPOPCNTB_Z,
2,
vec![OperandType::XmmReg, OperandType::XmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x54,
);
vpopcntbz128rr.is_evex = true;
vpopcntbz128rr.evex_tuple = Some(X86EvexTuple::FV);
vpopcntbz128rr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpopcntbz128rr.required_features = avx512bitalg_feat.clone();
self.instructions.push(vpopcntbz128rr);
let mut vpermqzrr = Self::make_instr(
"VPERMQZrr",
X86Opcode::VPERMQ_Z,
3,
vec![OperandType::ZmmReg, OperandType::ZmmReg, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x00,
);
vpermqzrr.is_evex = true;
vpermqzrr.evex_tuple = Some(X86EvexTuple::FV);
vpermqzrr.vex_w = Some(true);
vpermqzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpermqzrr.required_features = avx512f_feat.clone();
self.instructions.push(vpermqzrr);
let mut vshuff32x4zrri = Self::make_instr(
"VSHUFF32X4Zrri",
X86Opcode::VSHUFF32X4_Z,
4,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x23,
);
vshuff32x4zrri.is_evex = true;
vshuff32x4zrri.evex_tuple = Some(X86EvexTuple::FV);
vshuff32x4zrri.encoding_prefix = Some(X86EncodingPrefix::Evex);
vshuff32x4zrri.required_features = avx512f_feat.clone();
self.instructions.push(vshuff32x4zrri);
let mut valigndzrri = Self::make_instr(
"VALIGNDZrri",
X86Opcode::VALIGND_Z,
4,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0x03,
);
valigndzrri.is_evex = true;
valigndzrri.evex_tuple = Some(X86EvexTuple::FV);
valigndzrri.encoding_prefix = Some(X86EncodingPrefix::Evex);
valigndzrri.required_features = avx512f_feat.clone();
self.instructions.push(valigndzrri);
let mut vpscatterddz = Self::make_instr(
"VPSCATTERDDZmr",
X86Opcode::VPSCATTERDD_Z,
3,
vec![OperandType::Mem256, OperandType::VK, OperandType::ZmmReg],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::T8,
0xA0,
);
vpscatterddz.is_evex = true;
vpscatterddz.evex_tuple = Some(X86EvexTuple::T1S);
vpscatterddz.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpscatterddz.may_store = true;
vpscatterddz.has_side_effects = true;
vpscatterddz.required_features = avx512f_feat.clone();
self.instructions.push(vpscatterddz);
let mut vcmppszrri = Self::make_instr(
"VCMPPSZrri",
X86Opcode::VCMPPS_Z,
4,
vec![
OperandType::VK,
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xC2,
);
vcmppszrri.is_evex = true;
vcmppszrri.evex_tuple = Some(X86EvexTuple::FV);
vcmppszrri.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcmppszrri.is_compare = true;
vcmppszrri.required_features = avx512f_feat.clone();
self.instructions.push(vcmppszrri);
let mut vcmppdzrri = Self::make_instr(
"VCMPPDZrri",
X86Opcode::VCMPPD_Z,
4,
vec![
OperandType::VK,
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::Imm8,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xC2,
);
vcmppdzrri.is_evex = true;
vcmppdzrri.evex_tuple = Some(X86EvexTuple::FV);
vcmppdzrri.vex_w = Some(true);
vcmppdzrri.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcmppdzrri.is_compare = true;
vcmppdzrri.required_features = avx512f_feat.clone();
self.instructions.push(vcmppdzrri);
let mut vpcmpeqbzrr = Self::make_instr(
"VPCMPEQBZrr",
X86Opcode::VPCMPEQB_Z,
3,
vec![OperandType::VK, OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x74,
);
vpcmpeqbzrr.is_evex = true;
vpcmpeqbzrr.evex_tuple = Some(X86EvexTuple::FV);
vpcmpeqbzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpcmpeqbzrr.is_compare = true;
vpcmpeqbzrr.required_features = avx512bw_feat.clone();
self.instructions.push(vpcmpeqbzrr);
let mut vpcmpgtbzrr = Self::make_instr(
"VPCMPGTBZrr",
X86Opcode::VPCMPGTB_Z,
3,
vec![OperandType::VK, OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x64,
);
vpcmpgtbzrr.is_evex = true;
vpcmpgtbzrr.evex_tuple = Some(X86EvexTuple::FV);
vpcmpgtbzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vpcmpgtbzrr.is_compare = true;
vpcmpgtbzrr.required_features = avx512bw_feat.clone();
self.instructions.push(vpcmpgtbzrr);
let mut vmovdqu8zrr = Self::make_instr(
"VMOVDQU8Zrr",
X86Opcode::VMOVDQU8_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x6F,
);
vmovdqu8zrr.is_evex = true;
vmovdqu8zrr.evex_tuple = Some(X86EvexTuple::FV);
vmovdqu8zrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmovdqu8zrr.required_features = avx512bw_feat.clone();
self.instructions.push(vmovdqu8zrr);
let mut vmovdqu16zrr = Self::make_instr(
"VMOVDQU16Zrr",
X86Opcode::VMOVDQU16_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0x6F,
);
vmovdqu16zrr.is_evex = true;
vmovdqu16zrr.evex_tuple = Some(X86EvexTuple::FV);
vmovdqu16zrr.vex_w = Some(true);
vmovdqu16zrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmovdqu16zrr.required_features = avx512bw_feat.clone();
self.instructions.push(vmovdqu16zrr);
let avx512fp16_feat: Vec<String> = vec!["avx512fp16".into()];
let mut vaddphzrr = Self::make_instr(
"VADDPHZrr",
X86Opcode::VADDPH_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x58,
);
vaddphzrr.is_evex = true;
vaddphzrr.evex_tuple = Some(X86EvexTuple::FV);
vaddphzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vaddphzrr.is_commutative = true;
vaddphzrr.required_features = avx512fp16_feat.clone();
self.instructions.push(vaddphzrr);
let mut vmulphzrr = Self::make_instr(
"VMULPHZrr",
X86Opcode::VMULPH_Z,
3,
vec![
OperandType::ZmmReg,
OperandType::ZmmReg,
OperandType::ZmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x59,
);
vmulphzrr.is_evex = true;
vmulphzrr.evex_tuple = Some(X86EvexTuple::FV);
vmulphzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vmulphzrr.is_commutative = true;
vmulphzrr.required_features = avx512fp16_feat.clone();
self.instructions.push(vmulphzrr);
let mut vsqrtphzrr = Self::make_instr(
"VSQRTPHZrr",
X86Opcode::VSQRTPH_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x51,
);
vsqrtphzrr.is_evex = true;
vsqrtphzrr.evex_tuple = Some(X86EvexTuple::FV);
vsqrtphzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vsqrtphzrr.required_features = avx512fp16_feat.clone();
self.instructions.push(vsqrtphzrr);
let mut vcvtph2wzrr = Self::make_instr(
"VCVTPH2WZrr",
X86Opcode::VCVTPH2W_Z,
2,
vec![OperandType::ZmmReg, OperandType::ZmmReg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x7D,
);
vcvtph2wzrr.is_evex = true;
vcvtph2wzrr.evex_tuple = Some(X86EvexTuple::FV);
vcvtph2wzrr.encoding_prefix = Some(X86EncodingPrefix::Evex);
vcvtph2wzrr.is_convert = true;
vcvtph2wzrr.required_features = avx512fp16_feat.clone();
self.instructions.push(vcvtph2wzrr);
if self.enable_amx {
let mut tdpbssdz = Self::make_instr(
"TDPBSSDZrr",
X86Opcode::TDPBSSD_Z,
3,
vec![OperandType::Reg, OperandType::Reg, OperandType::Reg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x5E,
);
tdpbssdz.is_evex = true;
tdpbssdz.evex_tuple = Some(X86EvexTuple::FV);
tdpbssdz.encoding_prefix = Some(X86EncodingPrefix::Evex);
tdpbssdz.required_features = vec!["amx-int8".into()];
self.instructions.push(tdpbssdz);
let mut tdpbf16psz = Self::make_instr(
"TDPBF16PSZrr",
X86Opcode::TDPBF16PS_Z,
3,
vec![OperandType::Reg, OperandType::Reg, OperandType::Reg],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x5C,
);
tdpbf16psz.is_evex = true;
tdpbf16psz.evex_tuple = Some(X86EvexTuple::FV);
tdpbf16psz.encoding_prefix = Some(X86EncodingPrefix::Evex);
tdpbf16psz.required_features = vec!["amx-bf16".into()];
self.instructions.push(tdpbf16psz);
let mut tileloaddz = Self::make_instr(
"TILELOADDZ",
X86Opcode::TILELOADD_Z,
2,
vec![OperandType::Reg, OperandType::Mem256],
X86InstrFormat::MRMSrcMem,
X86OpcodeMap::T8,
0x4B,
);
tileloaddz.is_evex = true;
tileloaddz.evex_tuple = Some(X86EvexTuple::T1S);
tileloaddz.encoding_prefix = Some(X86EncodingPrefix::Evex);
tileloaddz.may_load = true;
tileloaddz.required_features = vec!["amx-tile".into()];
self.instructions.push(tileloaddz);
let mut tilestoredz = Self::make_instr(
"TILESTOREDZ",
X86Opcode::TILESTORED_Z,
2,
vec![OperandType::Mem256, OperandType::Reg],
X86InstrFormat::MRMDestMem,
X86OpcodeMap::T8,
0x4A,
);
tilestoredz.is_evex = true;
tilestoredz.evex_tuple = Some(X86EvexTuple::T1S);
tilestoredz.encoding_prefix = Some(X86EncodingPrefix::Evex);
tilestoredz.may_store = true;
tilestoredz.required_features = vec!["amx-tile".into()];
self.instructions.push(tilestoredz);
}
}
fn gen_fma(&mut self) {
let fma_feat = vec!["fma".into()];
let fma_variants: [(&str, X86Opcode, u8); 3] = [
("VFMADD", X86Opcode::VFMADD132PD, 0x98),
("VFMSUB", X86Opcode::VFMSUB132PD, 0x9A),
("VFNMADD", X86Opcode::VFNMADD132PD, 0x9C),
];
let fma_orders: [(&str, u8); 3] = [
("132", 0x98), ("213", 0xA8), ("231", 0xB8), ];
for (order_suffix, base_op_byte) in fma_orders.iter() {
let mut fmaddpd = Self::make_instr(
&format!("VFMADD{}PDr", order_suffix),
match order_suffix {
&"132" => X86Opcode::VFMADD132PD,
&"213" => X86Opcode::VFMADD213PD,
_ => X86Opcode::VFMADD231PD,
},
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
base_op_byte + 4,
);
fmaddpd.is_vex = true;
fmaddpd.vex_l = Some(true);
fmaddpd.vex_w = Some(true);
fmaddpd.encoding_prefix = Some(X86EncodingPrefix::Vex3);
fmaddpd.is_three_address = true;
fmaddpd.required_features = fma_feat.clone();
self.instructions.push(fmaddpd);
let mut fmaddps = Self::make_instr(
&format!("VFMADD{}PSr", order_suffix),
match order_suffix {
&"132" => X86Opcode::VFMADD132PS,
&"213" => X86Opcode::VFMADD213PS,
_ => X86Opcode::VFMADD231PS,
},
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
*base_op_byte,
);
fmaddps.is_vex = true;
fmaddps.vex_l = Some(true);
fmaddps.vex_w = Some(false);
fmaddps.encoding_prefix = Some(X86EncodingPrefix::Vex3);
fmaddps.is_three_address = true;
fmaddps.required_features = fma_feat.clone();
self.instructions.push(fmaddps);
let mut fmaddsd = Self::make_instr(
&format!("VFMADD{}SDr", order_suffix),
match order_suffix {
&"132" => X86Opcode::VFMADD132SD,
&"213" => X86Opcode::VFMADD213SD,
_ => X86Opcode::VFMADD231SD,
},
3,
vec![
OperandType::XmmReg,
OperandType::XmmReg,
OperandType::XmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
base_op_byte + 5,
);
fmaddsd.is_vex = true;
fmaddsd.vex_l = Some(false);
fmaddsd.vex_w = Some(true);
fmaddsd.encoding_prefix = Some(X86EncodingPrefix::Vex3);
fmaddsd.is_three_address = true;
fmaddsd.required_features = fma_feat.clone();
self.instructions.push(fmaddsd);
let mut fmaddss = Self::make_instr(
&format!("VFMADD{}SSr", order_suffix),
match order_suffix {
&"132" => X86Opcode::VFMADD132SS,
&"213" => X86Opcode::VFMADD213SS,
_ => X86Opcode::VFMADD231SS,
},
3,
vec![
OperandType::XmmReg,
OperandType::XmmReg,
OperandType::XmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
base_op_byte + 1,
);
fmaddss.is_vex = true;
fmaddss.vex_l = Some(false);
fmaddss.vex_w = Some(false);
fmaddss.encoding_prefix = Some(X86EncodingPrefix::Vex3);
fmaddss.is_three_address = true;
fmaddss.required_features = fma_feat.clone();
self.instructions.push(fmaddss);
let msub_pd_op = match order_suffix {
&"132" => X86Opcode::VFMSUB132PD,
&"213" => X86Opcode::VFMSUB213PD,
_ => X86Opcode::VFMSUB231PD,
};
let mut fmsubpd = Self::make_instr(
&format!("VFMSUB{}PDr", order_suffix),
msub_pd_op,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
base_op_byte + 6,
);
fmsubpd.is_vex = true;
fmsubpd.vex_l = Some(true);
fmsubpd.vex_w = Some(true);
fmsubpd.encoding_prefix = Some(X86EncodingPrefix::Vex3);
fmsubpd.is_three_address = true;
fmsubpd.required_features = fma_feat.clone();
self.instructions.push(fmsubpd);
}
let mut vfmaddsub132psr = Self::make_instr(
"VFMADDSUB132PSr",
X86Opcode::VFMADDSUB132PS,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x96,
);
vfmaddsub132psr.is_vex = true;
vfmaddsub132psr.vex_l = Some(true);
vfmaddsub132psr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vfmaddsub132psr.is_three_address = true;
vfmaddsub132psr.required_features = fma_feat.clone();
self.instructions.push(vfmaddsub132psr);
let mut vfmaddsub132pdr = Self::make_instr(
"VFMADDSUB132PDr",
X86Opcode::VFMADDSUB132PD,
3,
vec![
OperandType::YmmReg,
OperandType::YmmReg,
OperandType::YmmReg,
],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0x96,
);
vfmaddsub132pdr.is_vex = true;
vfmaddsub132pdr.vex_l = Some(true);
vfmaddsub132pdr.vex_w = Some(true);
vfmaddsub132pdr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
vfmaddsub132pdr.is_three_address = true;
vfmaddsub132pdr.required_features = fma_feat.clone();
self.instructions.push(vfmaddsub132pdr);
}
fn gen_bmi_bmi2(&mut self) {
let bmi_feat = vec!["bmi".into()];
let bmi2_feat = vec!["bmi2".into()];
let mut andn32rr = Self::make_instr(
"ANDN32rr",
X86Opcode::ANDN,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF2,
);
andn32rr.is_vex = true;
andn32rr.vex_l = Some(false);
andn32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
andn32rr.is_three_address = true;
andn32rr.required_features = bmi_feat.clone();
self.instructions.push(andn32rr);
let mut andn64rr = Self::make_instr(
"ANDN64rr",
X86Opcode::ANDN,
3,
vec![OperandType::Reg64, OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF2,
);
andn64rr.is_vex = true;
andn64rr.vex_l = Some(false);
andn64rr.vex_w = Some(true);
andn64rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
andn64rr.is_three_address = true;
andn64rr.required_features = vec!["bmi".into(), "64bit".into()];
self.instructions.push(andn64rr);
let mut bextr32rr = Self::make_instr(
"BEXTR32rr",
X86Opcode::BEXTR,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF7,
);
bextr32rr.is_vex = true;
bextr32rr.vex_l = Some(false);
bextr32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
bextr32rr.is_three_address = true;
bextr32rr.required_features = bmi_feat.clone();
self.instructions.push(bextr32rr);
let mut bextr64rr = Self::make_instr(
"BEXTR64rr",
X86Opcode::BEXTR,
3,
vec![OperandType::Reg64, OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF7,
);
bextr64rr.is_vex = true;
bextr64rr.vex_l = Some(false);
bextr64rr.vex_w = Some(true);
bextr64rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
bextr64rr.is_three_address = true;
bextr64rr.required_features = vec!["bmi".into(), "64bit".into()];
self.instructions.push(bextr64rr);
let mut blsi32r = Self::make_instr(
"BLSI32rr",
X86Opcode::BLSI,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF3,
);
blsi32r.is_vex = true;
blsi32r.vex_l = Some(false);
blsi32r.encoding_prefix = Some(X86EncodingPrefix::Vex3);
blsi32r.required_features = bmi_feat.clone();
self.instructions.push(blsi32r);
let mut blsmsk32r = Self::make_instr(
"BLSMSK32rr",
X86Opcode::BLSMSK,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF3,
);
blsmsk32r.is_vex = true;
blsmsk32r.vex_l = Some(false);
blsmsk32r.encoding_prefix = Some(X86EncodingPrefix::Vex3);
blsmsk32r.required_features = bmi_feat.clone();
self.instructions.push(blsmsk32r);
let mut blsr32r = Self::make_instr(
"BLSR32rr",
X86Opcode::BLSR,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF3,
);
blsr32r.is_vex = true;
blsr32r.vex_l = Some(false);
blsr32r.encoding_prefix = Some(X86EncodingPrefix::Vex3);
blsr32r.required_features = bmi_feat.clone();
self.instructions.push(blsr32r);
let mut bzhi32rr = Self::make_instr(
"BZHI32rr",
X86Opcode::BZHI,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF5,
);
bzhi32rr.is_vex = true;
bzhi32rr.vex_l = Some(false);
bzhi32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
bzhi32rr.is_three_address = true;
bzhi32rr.required_features = bmi2_feat.clone();
self.instructions.push(bzhi32rr);
let mut mulx32rr = Self::make_instr(
"MULX32rr",
X86Opcode::MULX,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xF6,
);
mulx32rr.is_vex = true;
mulx32rr.vex_l = Some(false);
mulx32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
mulx32rr.is_three_address = true;
mulx32rr.required_features = bmi2_feat.clone();
self.instructions.push(mulx32rr);
let mut pdep32rr = Self::make_instr(
"PDEP32rr",
X86Opcode::PDEP,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF5,
);
pdep32rr.is_vex = true;
pdep32rr.vex_l = Some(false);
pdep32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
pdep32rr.is_three_address = true;
pdep32rr.required_features = bmi2_feat.clone();
self.instructions.push(pdep32rr);
let mut pext32rr = Self::make_instr(
"PEXT32rr",
X86Opcode::PEXT,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF5,
);
pext32rr.is_vex = true;
pext32rr.vex_l = Some(false);
pext32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
pext32rr.is_three_address = true;
pext32rr.required_features = bmi2_feat.clone();
self.instructions.push(pext32rr);
let mut rorx32ri = Self::make_instr(
"RORX32ri",
X86Opcode::RORX,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Imm8],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TA,
0xF0,
);
rorx32ri.is_vex = true;
rorx32ri.vex_l = Some(false);
rorx32ri.encoding_prefix = Some(X86EncodingPrefix::Vex3);
rorx32ri.is_three_address = true;
rorx32ri.required_features = bmi2_feat.clone();
self.instructions.push(rorx32ri);
let mut sarx32rr = Self::make_instr(
"SARX32rr",
X86Opcode::SARX,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF7,
);
sarx32rr.is_vex = true;
sarx32rr.vex_l = Some(false);
sarx32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
sarx32rr.is_three_address = true;
sarx32rr.required_features = bmi2_feat.clone();
self.instructions.push(sarx32rr);
let mut shlx32rr = Self::make_instr(
"SHLX32rr",
X86Opcode::SHLX,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF7,
);
shlx32rr.is_vex = true;
shlx32rr.vex_l = Some(false);
shlx32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
shlx32rr.is_three_address = true;
shlx32rr.required_features = bmi2_feat.clone();
self.instructions.push(shlx32rr);
let mut shrx32rr = Self::make_instr(
"SHRX32rr",
X86Opcode::SHRX,
3,
vec![OperandType::Reg32, OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::T8,
0xF7,
);
shrx32rr.is_vex = true;
shrx32rr.vex_l = Some(false);
shrx32rr.encoding_prefix = Some(X86EncodingPrefix::Vex3);
shrx32rr.is_three_address = true;
shrx32rr.required_features = bmi2_feat.clone();
self.instructions.push(shrx32rr);
let mut tzcnt32r = Self::make_instr(
"TZCNT32rr",
X86Opcode::TZCNT,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xBC,
);
tzcnt32r.encoding_prefix = Some(X86EncodingPrefix::RepNE);
tzcnt32r.required_features = bmi_feat.clone();
self.instructions.push(tzcnt32r);
let mut tzcnt64r = Self::make_instr(
"TZCNT64rr",
X86Opcode::TZCNT,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xBC,
);
tzcnt64r.requires_rex = true;
tzcnt64r.encoding_prefix = Some(X86EncodingPrefix::RepNE);
tzcnt64r.required_features = vec!["bmi".into(), "64bit".into()];
self.instructions.push(tzcnt64r);
let mut lzcnt32r = Self::make_instr(
"LZCNT32rr",
X86Opcode::LZCNT,
2,
vec![OperandType::Reg32, OperandType::Reg32],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xBD,
);
lzcnt32r.encoding_prefix = Some(X86EncodingPrefix::RepNE);
lzcnt32r.required_features = vec!["lzcnt".into()];
self.instructions.push(lzcnt32r);
let mut lzcnt64r = Self::make_instr(
"LZCNT64rr",
X86Opcode::LZCNT,
2,
vec![OperandType::Reg64, OperandType::Reg64],
X86InstrFormat::MRMSrcReg,
X86OpcodeMap::TB,
0xBD,
);
lzcnt64r.requires_rex = true;
lzcnt64r.encoding_prefix = Some(X86EncodingPrefix::RepNE);
lzcnt64r.required_features = vec!["lzcnt".into(), "64bit".into()];
self.instructions.push(lzcnt64r);
}
fn gen_system(&mut self) {
let mut syscall = Self::make_instr(
"SYSCALL",
X86Opcode::SYSCALL,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
0x05,
);
syscall.has_side_effects = true;
syscall.is_call = true;
syscall.is_barrier = true;
syscall.can_fold_load = false;
syscall.implicit_defs = vec![0, 1, 2, 3, 5, 6, 8, 9, 10, 11]; syscall.required_features = vec!["64bit".into()];
self.instructions.push(syscall);
let mut sysenter = Self::make_instr(
"SYSENTER",
X86Opcode::SYSENTER,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
0x34,
);
sysenter.has_side_effects = true;
sysenter.is_call = true;
sysenter.can_fold_load = false;
self.instructions.push(sysenter);
let mut rdrand32r = Self::make_instr(
"RDRAND32r",
X86Opcode::RDRAND,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM6r,
X86OpcodeMap::TB,
0xC7,
);
rdrand32r.has_side_effects = true;
rdrand32r.implicit_defs = vec![49]; rdrand32r.required_features = vec!["rdrnd".into()];
self.instructions.push(rdrand32r);
let mut rdseed32r = Self::make_instr(
"RDSEED32r",
X86Opcode::RDSEED,
1,
vec![OperandType::Reg32],
X86InstrFormat::MRM7r,
X86OpcodeMap::TB,
0xC7,
);
rdseed32r.has_side_effects = true;
rdseed32r.implicit_defs = vec![49];
rdseed32r.required_features = vec!["rdseed".into()];
self.instructions.push(rdseed32r);
let mut rdtsc = Self::make_instr(
"RDTSC",
X86Opcode::RDTSC,
0,
vec![],
X86InstrFormat::RawFrm,
X86OpcodeMap::TB,
0x31,
);
rdtsc.has_side_effects = true;
rdtsc.implicit_defs = vec![0, 2]; self.instructions.push(rdtsc);
let mut lfence = Self::make_instr(
"LFENCE",
X86Opcode::LFENCE,
0,
vec![],
X86InstrFormat::MRM5m,
X86OpcodeMap::TB,
0xAE,
);
lfence.has_side_effects = true;
lfence.is_barrier = true;
lfence.can_fold_load = false;
self.instructions.push(lfence);
let mut mfence = Self::make_instr(
"MFENCE",
X86Opcode::MFENCE,
0,
vec![],
X86InstrFormat::MRM6m,
X86OpcodeMap::TB,
0xAE,
);
mfence.has_side_effects = true;
mfence.is_barrier = true;
mfence.can_fold_load = false;
self.instructions.push(mfence);
let mut sfence = Self::make_instr(
"SFENCE",
X86Opcode::SFENCE,
0,
vec![],
X86InstrFormat::MRM7m,
X86OpcodeMap::TB,
0xAE,
);
sfence.has_side_effects = true;
sfence.is_barrier = true;
sfence.can_fold_load = false;
self.instructions.push(sfence);
}
fn gen_register_classes(&mut self) {
let defs = X86RegisterDefs::generate();
let all_regs: Vec<&X86RegisterDef> = [
defs.gr8.iter().collect::<Vec<_>>(),
defs.gr16.iter().collect(),
defs.gr32.iter().collect(),
defs.gr64.iter().collect(),
defs.fr32.iter().collect(),
defs.fr64.iter().collect(),
defs.vr128.iter().collect(),
defs.vr256.iter().collect(),
defs.vr512.iter().collect(),
defs.mask_regs.iter().collect(),
defs.segment_regs.iter().collect(),
defs.control_regs.iter().collect(),
defs.debug_regs.iter().collect(),
defs.rflags.iter().collect(),
defs.eflags.iter().collect(),
defs.x87_regs.iter().collect(),
defs.mmx_regs.iter().collect(),
defs.bound_regs.iter().collect(),
defs.tile_regs.iter().collect(),
]
.concat();
self.registers = all_regs.iter().map(|r| (*r).clone()).collect();
self.register_classes.push(X86RegisterClassDef {
name: "GR8".into(),
reg_names: defs.gr8.iter().map(|r| r.name.clone()).collect(),
spill_size: 1,
spill_alignment: 1,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "i8".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "GR16".into(),
reg_names: defs.gr16.iter().map(|r| r.name.clone()).collect(),
spill_size: 2,
spill_alignment: 2,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "i16".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "GR32".into(),
reg_names: defs.gr32.iter().map(|r| r.name.clone()).collect(),
spill_size: 4,
spill_alignment: 4,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "i32".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "GR64".into(),
reg_names: defs.gr64.iter().map(|r| r.name.clone()).collect(),
spill_size: 8,
spill_alignment: 8,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "i64".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "FR32".into(),
reg_names: defs.fr32.iter().map(|r| r.name.clone()).collect(),
spill_size: 4,
spill_alignment: 4,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "f32".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "FR64".into(),
reg_names: defs.fr64.iter().map(|r| r.name.clone()).collect(),
spill_size: 8,
spill_alignment: 8,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "f64".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "VR128".into(),
reg_names: defs.vr128.iter().map(|r| r.name.clone()).collect(),
spill_size: 16,
spill_alignment: 16,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "v16i8".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "VR256".into(),
reg_names: defs.vr256.iter().map(|r| r.name.clone()).collect(),
spill_size: 32,
spill_alignment: 32,
copy_cost: 2,
is_allocatable: true,
is_virtual: false,
value_type: "v32i8".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "VR512".into(),
reg_names: defs.vr512.iter().map(|r| r.name.clone()).collect(),
spill_size: 64,
spill_alignment: 64,
copy_cost: 4,
is_allocatable: true,
is_virtual: false,
value_type: "v64i8".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "VK64".into(),
reg_names: defs.mask_regs.iter().map(|r| r.name.clone()).collect(),
spill_size: 8,
spill_alignment: 8,
copy_cost: 1,
is_allocatable: true,
is_virtual: false,
value_type: "i64".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "RFLAGS".into(),
reg_names: defs.rflags.iter().map(|r| r.name.clone()).collect(),
spill_size: 8,
spill_alignment: 8,
copy_cost: 1,
is_allocatable: false,
is_virtual: false,
value_type: "i64".into(),
});
self.register_classes.push(X86RegisterClassDef {
name: "RFP80".into(),
reg_names: defs.x87_regs.iter().map(|r| r.name.clone()).collect(),
spill_size: 10,
spill_alignment: 4,
copy_cost: 3,
is_allocatable: true,
is_virtual: false,
value_type: "f80".into(),
});
}
fn gen_registers(&mut self) {
}
fn gen_patterns(&mut self) {
self.patterns = X86InstrPattern::generate().patterns;
}
fn gen_complex_patterns(&mut self) {
self.complex_patterns = X86InstrPattern::generate_complex_patterns();
}
fn gen_calling_conventions(&mut self) {
self.calling_conventions.push(X86CallingConvRule {
name: "SysV_AMD64".into(),
argument_regs_64: vec![
"RDI".into(),
"RSI".into(),
"RDX".into(),
"RCX".into(),
"R8".into(),
"R9".into(),
],
return_reg_64: "RAX".into(),
callee_saved_regs: vec![
"RBX".into(),
"RBP".into(),
"R12".into(),
"R13".into(),
"R14".into(),
"R15".into(),
],
stack_alignment: 16,
red_zone_size: 128,
});
self.calling_conventions.push(X86CallingConvRule {
name: "SysV_i386".into(),
argument_regs_64: vec![], return_reg_64: "EAX".into(),
callee_saved_regs: vec!["EBX".into(), "EBP".into(), "ESI".into(), "EDI".into()],
stack_alignment: 16,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Win64".into(),
argument_regs_64: vec!["RCX".into(), "RDX".into(), "R8".into(), "R9".into()],
return_reg_64: "RAX".into(),
callee_saved_regs: vec![
"RBX".into(),
"RBP".into(),
"RDI".into(),
"RSI".into(),
"R12".into(),
"R13".into(),
"R14".into(),
"R15".into(),
],
stack_alignment: 16,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Vectorcall".into(),
argument_regs_64: vec!["RCX".into(), "RDX".into(), "R8".into(), "R9".into()],
return_reg_64: "RAX".into(),
callee_saved_regs: vec![
"RBX".into(),
"RBP".into(),
"RDI".into(),
"RSI".into(),
"R12".into(),
"R13".into(),
"R14".into(),
"R15".into(),
],
stack_alignment: 16,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Fastcall".into(),
argument_regs_64: vec![],
return_reg_64: "EAX".into(),
callee_saved_regs: vec!["EBX".into(), "EBP".into(), "ESI".into(), "EDI".into()],
stack_alignment: 4,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Thiscall".into(),
argument_regs_64: vec![],
return_reg_64: "EAX".into(),
callee_saved_regs: vec!["EBX".into(), "EBP".into(), "ESI".into(), "EDI".into()],
stack_alignment: 4,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Cdecl".into(),
argument_regs_64: vec![],
return_reg_64: "EAX".into(),
callee_saved_regs: vec!["EBX".into(), "EBP".into(), "ESI".into(), "EDI".into()],
stack_alignment: 4,
red_zone_size: 0,
});
self.calling_conventions.push(X86CallingConvRule {
name: "Stdcall".into(),
argument_regs_64: vec![],
return_reg_64: "EAX".into(),
callee_saved_regs: vec!["EBX".into(), "EBP".into(), "ESI".into(), "EDI".into()],
stack_alignment: 4,
red_zone_size: 0,
});
}
fn gen_scheduling_info(&mut self) {
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteALU".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0xFF, });
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteLoad".into(),
latency: 4,
throughput: 1,
micro_ops: 1,
port_usage: 0x04, });
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteStore".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x08, });
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteIMul".into(),
latency: 3,
throughput: 1,
micro_ops: 1,
port_usage: 0x01,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteIDiv".into(),
latency: 25,
throughput: 6,
micro_ops: 36,
port_usage: 0x03,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFAdd".into(),
latency: 3,
throughput: 1,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFMul".into(),
latency: 4,
throughput: 1,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFDiv".into(),
latency: 14,
throughput: 5,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecALU".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x30,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecFAdd".into(),
latency: 3,
throughput: 1,
micro_ops: 1,
port_usage: 0x30,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecFMul".into(),
latency: 4,
throughput: 1,
micro_ops: 1,
port_usage: 0x30,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecFDiv".into(),
latency: 14,
throughput: 6,
micro_ops: 2,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecShift".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVecLogic".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x30,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteShuffle".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteBlend".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVarShuffle".into(),
latency: 1,
throughput: 2,
micro_ops: 2,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteVarVecShift".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteMPSAD".into(),
latency: 7,
throughput: 2,
micro_ops: 3,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFShuffle".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFBlend".into(),
latency: 1,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteCvtF2I".into(),
latency: 3,
throughput: 1,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteCvtI2F".into(),
latency: 4,
throughput: 1,
micro_ops: 2,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteCvtF2F".into(),
latency: 2,
throughput: 1,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFMA".into(),
latency: 4,
throughput: 1,
micro_ops: 1,
port_usage: 0x10,
});
self.scheduling_records.push(X86SchedWriteRecord {
name: "WriteFShuffle256".into(),
latency: 3,
throughput: 1,
micro_ops: 1,
port_usage: 0x20,
});
}
}
#[derive(Debug, Clone)]
pub struct X86CallingConvRule {
pub name: String,
pub argument_regs_64: Vec<String>,
pub return_reg_64: String,
pub callee_saved_regs: Vec<String>,
pub stack_alignment: u32,
pub red_zone_size: u32,
}
#[derive(Debug, Clone)]
pub struct X86SchedWriteRecord {
pub name: String,
pub latency: u32,
pub throughput: u32,
pub micro_ops: u32,
pub port_usage: u64, }
#[derive(Debug, Clone)]
pub struct X86ISelDAGPatterns {
pub entries: Vec<ISelTableEntry>,
pub custom_inserters: Vec<X86CustomInserter>,
pub complex_pattern_handlers: Vec<X86ComplexPatternHandler>,
pub type_inference: Vec<X86TypeInferenceEntry>,
}
#[derive(Debug, Clone)]
pub struct X86CustomInserter {
pub opcode: X86Opcode,
pub handler_name: String,
}
#[derive(Debug, Clone)]
pub struct X86ComplexPatternHandler {
pub name: String,
pub select_fn: String,
pub opcode_filter: Vec<X86Opcode>,
}
#[derive(Debug, Clone)]
pub struct X86TypeInferenceEntry {
pub pattern_name: String,
pub src_types: Vec<String>,
pub dst_type: String,
}
impl X86ISelDAGPatterns {
pub fn generate() -> Self {
let mut entries = Vec::new();
let mk_entry = |name: &'static str,
pattern: PatNode,
condition: PatCondition,
opcode: X86Opcode,
num_ops: u8,
cost: u32,
priority: u16,
desc: &'static str,
feature: Option<&'static str>|
-> ISelTableEntry {
ISelTableEntry {
name,
pattern,
condition,
result: PatResult {
opcode,
num_operands: num_ops,
sets_flags: false,
is_conditional: false,
cost,
requires_feature: feature,
},
priority,
desc,
}
};
let cond_isel = PatCondition::HasFeature("isel".into());
entries.push(mk_entry(
"ADD32rr",
PatNode::BinOp("add".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::ADD,
2,
1,
100,
"ADD32rr: r32 = add r32, r32",
None,
));
entries.push(mk_entry(
"ADD32rm",
PatNode::Tree(
Box::new(PatNode::BinOp("add".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::MemRef)],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::ADD,
2,
1,
90,
"ADD32rm: r32 = add r32, [mem32]",
None,
));
entries.push(mk_entry(
"ADD32ri",
PatNode::Tree(
Box::new(PatNode::BinOp("add".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::ConstInt(0))],
),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::ImmFits(32),
]),
X86Opcode::ADD,
2,
1,
95,
"ADD32ri: r32 = add r32, imm32",
None,
));
entries.push(mk_entry(
"SUB32rr",
PatNode::BinOp("sub".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::SUB,
2,
1,
100,
"SUB32rr: r32 = sub r32, r32",
None,
));
entries.push(mk_entry(
"SUB64rr",
PatNode::BinOp("sub".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i64".into()),
PatCondition::Is64Bit,
]),
X86Opcode::SUB,
2,
1,
100,
"SUB64rr: r64 = sub r64, r64",
None,
));
entries.push(mk_entry(
"IMUL32rr",
PatNode::BinOp("mul".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::IMUL,
2,
2,
100,
"IMUL32rr: r32 = mul r32, r32",
None,
));
entries.push(mk_entry(
"AND32rr",
PatNode::BinOp("and".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::AND,
2,
1,
100,
"AND32rr: r32 = and r32, r32",
None,
));
entries.push(mk_entry(
"AND32ri",
PatNode::Tree(
Box::new(PatNode::BinOp("and".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::ConstInt(0))],
),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::ImmFits(32),
]),
X86Opcode::AND,
2,
1,
95,
"AND32ri: r32 = and r32, imm32",
None,
));
entries.push(mk_entry(
"OR32rr",
PatNode::BinOp("or".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::OR,
2,
1,
100,
"OR32rr: r32 = or r32, r32",
None,
));
entries.push(mk_entry(
"XOR32rr",
PatNode::BinOp("xor".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::XOR,
2,
1,
100,
"XOR32rr: r32 = xor r32, r32",
None,
));
entries.push(mk_entry(
"SHL32rCL",
PatNode::Tree(
Box::new(PatNode::BinOp("shl".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::Reg)],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::SHL,
1,
1,
90,
"SHL32rCL: r32 = shl r32, CL",
None,
));
entries.push(mk_entry(
"SHL32ri",
PatNode::Tree(
Box::new(PatNode::BinOp("shl".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::ConstInt(0))],
),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::ImmFits(8),
]),
X86Opcode::SHL,
2,
1,
95,
"SHL32ri: r32 = shl r32, imm8",
None,
));
entries.push(mk_entry(
"SHR32rCL",
PatNode::Tree(
Box::new(PatNode::BinOp("srl".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::Reg)],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::SHR,
1,
1,
90,
"SHR32rCL: r32 = srl r32, CL",
None,
));
entries.push(mk_entry(
"SAR32rCL",
PatNode::Tree(
Box::new(PatNode::BinOp("sra".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::Reg)],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::SAR,
1,
1,
90,
"SAR32rCL: r32 = sra r32, CL",
None,
));
entries.push(mk_entry(
"MOV32rm",
PatNode::MemRef,
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
cond_isel.clone(),
]),
X86Opcode::MOV,
2,
1,
100,
"MOV32rm: r32 = load [addr]",
None,
));
entries.push(mk_entry(
"MOV8rm",
PatNode::MemRef,
PatCondition::All(vec![
PatCondition::TypeMatches("i8".into()),
cond_isel.clone(),
]),
X86Opcode::MOV,
2,
1,
100,
"MOV8rm: r8 = load [addr]",
None,
));
entries.push(mk_entry(
"MOV32mr",
PatNode::Tree(
Box::new(PatNode::BinOp("st".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::MemRef)],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::MOV,
2,
1,
100,
"MOV32mr: store r32, [addr]",
None,
));
entries.push(mk_entry(
"LEA32r",
PatNode::AddrMode(AddressPattern::Any),
PatCondition::TypeMatches("i32".into()),
X86Opcode::LEA,
2,
1,
100,
"LEA32r: r32 = lea addr",
None,
));
entries.push(mk_entry(
"MOVSX32rr8",
PatNode::UnaryOp("sext".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::MOVSX,
2,
1,
100,
"MOVSX32rr8: r32 = sext i8 -> i32",
None,
));
entries.push(mk_entry(
"MOVZX32rr8",
PatNode::UnaryOp("zext".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::MOVZX,
2,
1,
100,
"MOVZX32rr8: r32 = zext i8 -> i32",
None,
));
entries.push(mk_entry(
"CMOVE32rr",
PatNode::Tree(
Box::new(PatNode::BinOp("select".into())),
vec![
Box::new(PatNode::Any),
Box::new(PatNode::Any),
Box::new(PatNode::Any),
],
),
PatCondition::TypeMatches("i32".into()),
X86Opcode::CMOVE,
2,
1,
85,
"CMOVE32rr: select -> cmove",
Some("cmov"),
));
entries.push(mk_entry(
"SETE",
PatNode::BinOp("setcc".into()),
PatCondition::TypeMatches("i8".into()),
X86Opcode::SETE,
1,
1,
90,
"SETE: setcc eq -> sete r8",
Some("cmov"),
));
entries.push(mk_entry(
"ADDSSrr",
PatNode::BinOp("fadd".into()),
PatCondition::TypeMatches("f32".into()),
X86Opcode::ADDSS,
2,
2,
100,
"ADDSSrr: f32 = fadd f32, f32",
Some("sse"),
));
entries.push(mk_entry(
"ADDSDrr",
PatNode::BinOp("fadd".into()),
PatCondition::TypeMatches("f64".into()),
X86Opcode::ADDSD,
2,
2,
100,
"ADDSDrr: f64 = fadd f64, f64",
Some("sse2"),
));
entries.push(mk_entry(
"MULSSrr",
PatNode::BinOp("fmul".into()),
PatCondition::TypeMatches("f32".into()),
X86Opcode::MULSS,
2,
2,
100,
"MULSSrr: f32 = fmul f32, f32",
Some("sse"),
));
entries.push(mk_entry(
"MULSDrr",
PatNode::BinOp("fmul".into()),
PatCondition::TypeMatches("f64".into()),
X86Opcode::MULSD,
2,
2,
100,
"MULSDrr: f64 = fmul f64, f64",
Some("sse2"),
));
entries.push(mk_entry(
"SQRTSSr",
PatNode::UnaryOp("fsqrt".into()),
PatCondition::TypeMatches("f32".into()),
X86Opcode::SQRTSS,
2,
2,
100,
"SQRTSSr: r = sqrt f32",
Some("sse"),
));
entries.push(mk_entry(
"SQRTSDr",
PatNode::UnaryOp("fsqrt".into()),
PatCondition::TypeMatches("f64".into()),
X86Opcode::SQRTSD,
2,
2,
100,
"SQRTSDr: r = sqrt f64",
Some("sse2"),
));
entries.push(mk_entry(
"ADDPSrr",
PatNode::BinOp("fadd".into()),
PatCondition::TypeMatches("v4f32".into()),
X86Opcode::ADDPS,
2,
2,
100,
"ADDPSrr: v4f32 = fadd v4f32, v4f32",
Some("sse"),
));
entries.push(mk_entry(
"ADDPDrr",
PatNode::BinOp("fadd".into()),
PatCondition::TypeMatches("v2f64".into()),
X86Opcode::ADDPD,
2,
2,
100,
"ADDPDrr: v2f64 = fadd v2f64, v2f64",
Some("sse2"),
));
entries.push(mk_entry(
"PADDBrr",
PatNode::BinOp("add".into()),
PatCondition::TypeMatches("v16i8".into()),
X86Opcode::VPADDB,
2,
2,
100,
"PADDBrr: v16i8 = add v16i8, v16i8",
Some("sse2"),
));
entries.push(mk_entry(
"PADDWrr",
PatNode::BinOp("add".into()),
PatCondition::TypeMatches("v8i16".into()),
X86Opcode::VPADDW,
2,
2,
100,
"PADDWrr: v8i16 = add v8i16, v8i16",
Some("sse2"),
));
entries.push(mk_entry(
"PADDDrr",
PatNode::BinOp("add".into()),
PatCondition::TypeMatches("v4i32".into()),
X86Opcode::VPADDD,
2,
2,
100,
"PADDDrr: v4i32 = add v4i32, v4i32",
Some("sse2"),
));
entries.push(mk_entry(
"VADDPSrr",
PatNode::BinOp("fadd".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v8f32".into()),
PatCondition::HasFeature("avx".into()),
]),
X86Opcode::VADDPS,
3,
2,
100,
"VADDPSrr: v8f32 = fadd v8f32, v8f32",
Some("avx"),
));
entries.push(mk_entry(
"VMULPDrm",
PatNode::Tree(
Box::new(PatNode::BinOp("fmul".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::MemRef)],
),
PatCondition::All(vec![
PatCondition::TypeMatches("v4f64".into()),
PatCondition::HasFeature("avx".into()),
]),
X86Opcode::VMULPD,
3,
2,
100,
"VMULPDrm: load folding",
Some("avx"),
));
entries.push(mk_entry(
"VADDPSZrr",
PatNode::BinOp("fadd".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16f32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VADDPS_Z,
3,
2,
100,
"VADDPSZrr: v16f32 = fadd v16f32, v16f32",
Some("avx512f"),
));
entries.push(mk_entry(
"VPADDDZrr",
PatNode::BinOp("add".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16i32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VPADDD_Z,
3,
2,
100,
"VPADDDZrr: v16i32 = add v16i32, v16i32",
Some("avx512f"),
));
entries.push(mk_entry(
"VMULPSZrr",
PatNode::BinOp("fmul".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16f32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VMULPS_Z,
3,
2,
100,
"VMULPSZrr: v16f32 = fmul v16f32, v16f32",
Some("avx512f"),
));
entries.push(mk_entry(
"VANDPSZrr",
PatNode::BinOp("and".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16i32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VANDPS_Z,
3,
2,
100,
"VANDPSZrr: bitwise AND",
Some("avx512f"),
));
entries.push(mk_entry(
"VMOVDQA32Zrr",
PatNode::UnaryOp("bitconvert".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16i32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VMOVDQA32_Z,
2,
1,
100,
"VMOVDQA32Zrr: aligned load",
Some("avx512f"),
));
entries.push(mk_entry(
"VPGATHERDDZrm",
PatNode::MemRef,
PatCondition::All(vec![
PatCondition::TypeMatches("v16i32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VPGATHERDD_Z,
3,
3,
90,
"VPGATHERDDZrm: indexed gather",
Some("avx512f"),
));
entries.push(mk_entry(
"VCOMPRESSPSZrr",
PatNode::BinOp("st".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16f32".into()),
PatCondition::HasFeature("avx512f".into()),
]),
X86Opcode::VCOMPRESSPS_Z,
3,
2,
95,
"VCOMPRESSPSZrr: compress store",
Some("avx512f"),
));
entries.push(mk_entry(
"VBROADCASTSSZrr",
PatNode::UnaryOp("broadcast".into()),
PatCondition::All(vec![PatCondition::HasFeature("avx512f".into())]),
X86Opcode::VBROADCASTSS_Z,
2,
1,
95,
"VBROADCASTSSZrr: broadcast scalar to vector",
Some("avx512f"),
));
entries.push(mk_entry(
"VADDPHZrr",
PatNode::BinOp("fadd".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v32f16".into()),
PatCondition::HasFeature("avx512fp16".into()),
]),
X86Opcode::VADDPH_Z,
3,
2,
100,
"VADDPHZrr: v32f16 = fadd v32f16, v32f16",
Some("avx512fp16"),
));
entries.push(mk_entry(
"VFMADD132PDr",
PatNode::Tree(
Box::new(PatNode::BinOp("fadd".into())),
vec![
Box::new(PatNode::Tree(
Box::new(PatNode::BinOp("fmul".into())),
vec![Box::new(PatNode::Any), Box::new(PatNode::Any)],
)),
Box::new(PatNode::Any),
],
),
PatCondition::All(vec![
PatCondition::TypeMatches("v4f64".into()),
PatCondition::HasFeature("fma".into()),
]),
X86Opcode::VFMADD132PD,
3,
3,
100,
"VFMADD132PDr: fused multiply-add",
Some("fma"),
));
entries.push(mk_entry(
"ANDN32rr",
PatNode::Tree(
Box::new(PatNode::BinOp("and".into())),
vec![
Box::new(PatNode::UnaryOp("not".into())),
Box::new(PatNode::Any),
],
),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::HasFeature("bmi".into()),
]),
X86Opcode::ANDN,
3,
1,
95,
"ANDN32rr: r = and (not a), b => andn r, a, b",
Some("bmi"),
));
entries.push(mk_entry(
"SHLX32rr",
PatNode::BinOp("shl".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::HasFeature("bmi2".into()),
]),
X86Opcode::SHLX,
3,
1,
95,
"SHLX32rr: r = shlx a, b",
Some("bmi2"),
));
entries.push(mk_entry(
"RORX32ri",
PatNode::BinOp("ror".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::HasFeature("bmi2".into()),
PatCondition::ImmFits(8),
]),
X86Opcode::RORX,
3,
1,
95,
"RORX32ri: r = rorx a, imm8",
Some("bmi2"),
));
entries.push(mk_entry(
"JE",
PatNode::BinOp("brcond".into()),
PatCondition::Always,
X86Opcode::JE,
1,
1,
100,
"JE: branch if equal/zero",
None,
));
entries.push(mk_entry(
"RET",
PatNode::BinOp("ret".into()),
PatCondition::Always,
X86Opcode::RET,
0,
1,
100,
"RET: return",
None,
));
entries.push(mk_entry(
"AESENCrr",
PatNode::UnaryOp("aes_enc".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v16i8".into()),
PatCondition::HasFeature("aes".into()),
]),
X86Opcode::AESENC,
2,
3,
90,
"AESENCrr: AES encrypt round",
Some("aes"),
));
entries.push(mk_entry(
"FADD32m",
PatNode::MemRef,
PatCondition::All(vec![PatCondition::TypeMatches("f32".into())]),
X86Opcode::FADD_MEM,
1,
2,
85,
"FADD32m: x87 float add from memory",
None,
));
entries.push(mk_entry(
"FSQRT_x87",
PatNode::UnaryOp("fsqrt".into()),
PatCondition::TypeMatches("f80".into()),
X86Opcode::FSQRT,
0,
3,
80,
"FSQRT: x87 sqrt ST0",
None,
));
entries.push(mk_entry(
"MMX_PADDBrr",
PatNode::BinOp("add".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("v8i8".into()),
PatCondition::HasFeature("mmx".into()),
]),
X86Opcode::MMX_PADDB,
2,
1,
80,
"MMX_PADDBrr: mmx add bytes",
Some("mmx"),
));
entries.push(mk_entry(
"POPCNT32rr",
PatNode::UnaryOp("ctpop".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::HasFeature("popcnt".into()),
]),
X86Opcode::POPCNT32,
2,
2,
90,
"POPCNT32rr: population count",
Some("popcnt"),
));
entries.push(mk_entry(
"BSWAP32r",
PatNode::UnaryOp("bswap".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::BSWAP,
1,
1,
95,
"BSWAP32r: byte swap",
None,
));
entries.push(mk_entry(
"NEG32r",
PatNode::UnaryOp("neg".into()),
PatCondition::TypeMatches("i32".into()),
X86Opcode::NEG,
1,
1,
95,
"NEG32r: negate register",
None,
));
entries.push(mk_entry(
"INC32r_isel",
PatNode::BinOp("add".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::ImmFits(1),
]),
X86Opcode::INC,
1,
1,
98,
"INC32r: increment by 1",
None,
));
entries.push(mk_entry(
"DEC32r_isel",
PatNode::BinOp("sub".into()),
PatCondition::All(vec![
PatCondition::TypeMatches("i32".into()),
PatCondition::ImmFits(1),
]),
X86Opcode::DEC,
1,
1,
98,
"DEC32r: decrement by 1",
None,
));
entries.push(mk_entry(
"TEST32rr",
PatNode::BinOp("and".into()),
PatCondition::All(vec![PatCondition::TypeMatches("i32".into())]),
X86Opcode::TEST,
2,
1,
100,
"TEST32rr: test (and) setting flags",
None,
));
entries.push(mk_entry(
"CVTSI2SSrr",
PatNode::BinOp("sint_to_fp".into()),
PatCondition::TypeMatches("f32".into()),
X86Opcode::CVTSI2SS,
2,
2,
100,
"CVTSI2SSrr: f32 = sint_to_fp i32",
Some("sse"),
));
entries.push(mk_entry(
"CVTDQ2PSrr",
PatNode::BinOp("sint_to_fp".into()),
PatCondition::TypeMatches("v4f32".into()),
X86Opcode::CVTDQ2PS,
2,
2,
100,
"CVTDQ2PSrr: v4f32 = sint_to_fp v4i32",
Some("sse2"),
));
let custom_inserters = vec![
X86CustomInserter {
opcode: X86Opcode::CMOVO,
handler_name: "InsertCMOV".into(),
},
X86CustomInserter {
opcode: X86Opcode::SETE,
handler_name: "InsertSETCC".into(),
},
X86CustomInserter {
opcode: X86Opcode::JE,
handler_name: "InsertJCC".into(),
},
];
let complex_pattern_handlers = vec![
X86ComplexPatternHandler {
name: "Addr".into(),
select_fn: "selectAddr".into(),
opcode_filter: vec![
X86Opcode::MOV,
X86Opcode::ADD,
X86Opcode::SUB,
X86Opcode::LEA,
X86Opcode::AND,
X86Opcode::OR,
X86Opcode::XOR,
X86Opcode::CMP,
],
},
X86ComplexPatternHandler {
name: "LEAAddr".into(),
select_fn: "selectLEAAddr".into(),
opcode_filter: vec![X86Opcode::LEA],
},
];
let type_inference = vec![
X86TypeInferenceEntry {
pattern_name: "ADD32rr".into(),
src_types: vec!["i32".into(), "i32".into()],
dst_type: "i32".into(),
},
X86TypeInferenceEntry {
pattern_name: "ADDSSrr".into(),
src_types: vec!["f32".into(), "f32".into()],
dst_type: "f32".into(),
},
X86TypeInferenceEntry {
pattern_name: "PADDBrr".into(),
src_types: vec!["v16i8".into(), "v16i8".into()],
dst_type: "v16i8".into(),
},
X86TypeInferenceEntry {
pattern_name: "VADDPSrr".into(),
src_types: vec!["v8f32".into(), "v8f32".into()],
dst_type: "v8f32".into(),
},
X86TypeInferenceEntry {
pattern_name: "VADDPSZrr".into(),
src_types: vec!["v16f32".into(), "v16f32".into()],
dst_type: "v16f32".into(),
},
X86TypeInferenceEntry {
pattern_name: "VMULPSZrr".into(),
src_types: vec!["v16f32".into(), "v16f32".into()],
dst_type: "v16f32".into(),
},
X86TypeInferenceEntry {
pattern_name: "VFMADD132PDr".into(),
src_types: vec!["v4f64".into(), "v4f64".into(), "v4f64".into()],
dst_type: "v4f64".into(),
},
X86TypeInferenceEntry {
pattern_name: "ANDN32rr".into(),
src_types: vec!["i32".into(), "i32".into(), "i32".into()],
dst_type: "i32".into(),
},
X86TypeInferenceEntry {
pattern_name: "MULX32rr".into(),
src_types: vec!["i32".into(), "i32".into(), "i32".into()],
dst_type: "i32".into(),
},
X86TypeInferenceEntry {
pattern_name: "AESENCrr".into(),
src_types: vec!["v16i8".into(), "v16i8".into()],
dst_type: "v16i8".into(),
},
X86TypeInferenceEntry {
pattern_name: "POPCNT32rr".into(),
src_types: vec!["i32".into()],
dst_type: "i32".into(),
},
X86TypeInferenceEntry {
pattern_name: "VADDPHZrr".into(),
src_types: vec!["v32f16".into(), "v32f16".into()],
dst_type: "v32f16".into(),
},
];
X86ISelDAGPatterns {
entries,
custom_inserters,
complex_pattern_handlers,
type_inference,
}
}
}
impl Default for X86ISelDAGPatterns {
fn default() -> Self {
Self::generate()
}
}
impl ISelTable {
pub fn from_entries(entries: Vec<ISelTableEntry>) -> Self {
let mut table = ISelTable::new();
table.patterns = entries;
table.build_index();
table
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::x86::X86Opcode;
#[test]
fn test_x86_tablegen_full_new() {
let backend = X86TableGenFull::new();
assert_eq!(backend.target, "x86_64-unknown-linux-gnu");
assert!(backend.enable_avx512);
assert!(!backend.enable_avx10);
assert!(backend.enable_amx);
}
#[test]
fn test_x86_tablegen_full_i386() {
let backend = X86TableGenFull::new_i386();
assert_eq!(backend.target, "i386-unknown-linux-gnu");
assert!(!backend.enable_avx512);
}
#[test]
fn test_generate_all_does_not_panic() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
!backend.instructions.is_empty(),
"Should have generated instructions"
);
}
#[test]
fn test_generate_instructions_count() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
backend.instructions.len() >= 200,
"Expected >= 200 instruction definitions, got {}",
backend.instructions.len()
);
}
#[test]
fn test_data_movement_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("MOV32rr"), "MOV32rr missing");
assert!(has("MOV64rr"), "MOV64rr missing");
assert!(has("MOVSX"), "MOVSX missing");
assert!(has("MOVZX"), "MOVZX missing");
assert!(has("LEA"), "LEA missing");
assert!(has("CMOVO"), "CMOVO missing");
for cmov in &[
"CMOVO", "CMOVNO", "CMOVB", "CMOVAE", "CMOVE", "CMOVNE", "CMOVBE", "CMOVA", "CMOVS",
"CMOVNS", "CMOVP", "CMOVNP", "CMOVL", "CMOVGE", "CMOVLE", "CMOVG",
] {
assert!(has(cmov), "{} missing", cmov);
}
for setcc in &[
"SETOr", "SETNOr", "SETBr", "SETAEr", "SETEr", "SETNEr", "SETBEr", "SETAr", "SETSr",
"SETNSr", "SETPr", "SETNPr", "SETLr", "SETGEr", "SETLEr", "SETGr",
] {
assert!(has(setcc), "{} missing", setcc);
}
}
#[test]
fn test_arithmetic_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("ADD32"), "ADD missing");
assert!(has("ADC32"), "ADC missing");
assert!(has("SUB32"), "SUB missing");
assert!(has("SBB32"), "SBB missing");
assert!(has("MUL32"), "MUL missing");
assert!(has("IMUL"), "IMUL missing");
assert!(has("DIV32"), "DIV missing");
assert!(has("IDIV32"), "IDIV missing");
assert!(has("INC32"), "INC missing");
assert!(has("DEC32"), "DEC missing");
assert!(has("NEG32"), "NEG missing");
}
#[test]
fn test_logical_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("AND"), "AND missing");
assert!(has("OR"), "OR missing");
assert!(has("XOR"), "XOR missing");
assert!(has("NOT"), "NOT missing");
assert!(has("TEST"), "TEST missing");
}
#[test]
fn test_shift_rotate_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("SHL"), "SHL missing");
assert!(has("SHR"), "SHR missing");
assert!(has("SAR"), "SAR missing");
assert!(has("ROL"), "ROL missing");
assert!(has("ROR"), "ROR missing");
assert!(has("RCL"), "RCL missing");
assert!(has("RCR"), "RCR missing");
assert!(has("SHLD"), "SHLD missing");
assert!(has("SHRD"), "SHRD missing");
}
#[test]
fn test_string_ops_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("MOVSB"), "MOVSB missing");
assert!(has("MOVSW"), "MOVSW missing");
assert!(has("CMPSB"), "CMPSB missing");
assert!(has("STOSB"), "STOSB missing");
assert!(has("LODSB"), "LODSB missing");
assert!(has("SCASB"), "SCASB missing");
}
#[test]
fn test_control_flow_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("JMP"), "JMP missing");
assert!(has("CALL"), "CALL missing");
assert!(has("RET"), "RET missing");
assert!(has("LOOP"), "LOOP missing");
for jcc in &[
"JO", "JNO", "JB", "JAE", "JE", "JNE", "JBE", "JA", "JS", "JNS", "JP", "JNP", "JL",
"JGE", "JLE", "JG",
] {
assert!(has(jcc), "{} missing", jcc);
}
}
#[test]
fn test_sse_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("MOVSS"), "MOVSS missing");
assert!(has("MOVSD"), "MOVSD missing");
assert!(has("ADDSS"), "ADDSS missing");
assert!(has("ADDSD"), "ADDSD missing");
assert!(has("SUBSS"), "SUBSS missing");
assert!(has("SUBSD"), "SUBSD missing");
assert!(has("MULSS"), "MULSS missing");
assert!(has("MULSD"), "MULSD missing");
assert!(has("DIVSS"), "DIVSS missing");
assert!(has("DIVSD"), "DIVSD missing");
assert!(has("SQRT"), "SQRT missing");
assert!(has("CMPSS"), "CMPSS missing");
assert!(has("CMPSD"), "CMPSD missing");
assert!(has("UCOMISS"), "UCOMISS missing");
assert!(has("UCOMISD"), "UCOMISD missing");
assert!(has("CVTSS2SD"), "CVTSS2SD missing");
assert!(has("CVTSD2SS"), "CVTSD2SS missing");
assert!(has("CVTSI2SS"), "CVTSI2SS missing");
assert!(has("CVTSI2SD"), "CVTSI2SD missing");
}
#[test]
fn test_sse2_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("ADDPD"), "ADDPD missing");
assert!(has("SUBPD"), "SUBPD missing");
assert!(has("MULPD"), "MULPD missing");
assert!(has("DIVPD"), "DIVPD missing");
assert!(has("ADDPS"), "ADDPS missing");
assert!(has("MULPS"), "MULPS missing");
assert!(has("PADDB"), "PADDB missing");
assert!(has("PADDW"), "PADDW missing");
assert!(has("PADDD"), "PADDD missing");
assert!(has("PADDQ"), "PADDQ missing");
assert!(has("ANDPS"), "ANDPS missing");
assert!(has("ANDNPS"), "ANDNPS missing");
assert!(has("ORPS"), "ORPS missing");
assert!(has("XORPS"), "XORPS missing");
assert!(has("CVTDQ2PS"), "CVTDQ2PS missing");
assert!(has("PSHUFD"), "PSHUFD missing");
assert!(has("PSHUFHW"), "PSHUFHW missing");
assert!(has("PSHUFLW"), "PSHUFLW missing");
}
#[test]
fn test_sse3_ssse3_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("ADDSUBPS"), "ADDSUBPS missing");
assert!(has("ADDSUBPD"), "ADDSUBPD missing");
assert!(has("HADDPS"), "HADDPS missing");
assert!(has("HADDPD"), "HADDPD missing");
assert!(has("HSUBPS"), "HSUBPS missing");
assert!(has("MOVSLDUP"), "MOVSLDUP missing");
assert!(has("MOVSHDUP"), "MOVSHDUP missing");
assert!(has("MOVDDUP"), "MOVDDUP missing");
assert!(has("PHADDW"), "PHADDW missing");
assert!(has("PHADDD"), "PHADDD missing");
assert!(has("PHSUBW"), "PHSUBW missing");
assert!(has("PHSUBD"), "PHSUBD missing");
assert!(has("PSIGN"), "PSIGN missing");
assert!(has("PABS"), "PABS missing");
}
#[test]
fn test_sse41_sse42_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("BLENDPS"), "BLENDPS missing");
assert!(has("BLENDVPS"), "BLENDVPS missing");
assert!(has("DPPS"), "DPPS missing");
assert!(has("DPPD"), "DPPD missing");
assert!(has("EXTRACTPS"), "EXTRACTPS missing");
assert!(has("INSERTPS"), "INSERTPS missing");
assert!(has("PMULLD"), "PMULLD missing");
assert!(has("PMINSB"), "PMINSB missing");
assert!(has("PMINSD"), "PMINSD missing");
assert!(has("PCMPEQQ"), "PCMPEQQ missing");
assert!(has("PACKUSDW"), "PACKUSDW missing");
assert!(has("PEXTR"), "PEXTR missing");
assert!(has("PINSR"), "PINSR missing");
assert!(has("CRC32"), "CRC32 missing");
}
#[test]
fn test_avx_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("VADDPS"), "VADDPS missing");
assert!(has("VADDPD"), "VADDPD missing");
assert!(has("VMULPS"), "VMULPS missing");
assert!(has("VMULPD"), "VMULPD missing");
assert!(has("VDIVPS"), "VDIVPS missing");
assert!(has("VANDPS"), "VANDPS missing");
assert!(has("VANDNPS"), "VANDNPS missing");
assert!(has("VORPS"), "VORPS missing");
assert!(has("VXORPS"), "VXORPS missing");
assert!(has("VBROADCAST"), "VBROADCAST missing");
assert!(has("VPERMIL"), "VPERMIL missing");
assert!(has("VPERM2F128"), "VPERM2F128 missing");
assert!(has("VZEROALL"), "VZEROALL missing");
assert!(has("VZEROUPPER"), "VZEROUPPER missing");
assert!(has("VPBROADCAST"), "VPBROADCAST missing");
assert!(has("VPERMQ"), "VPERMQ missing");
assert!(has("VPERMPD"), "VPERMPD missing");
assert!(has("VPGATHER"), "VPGATHER missing");
}
#[test]
fn test_avx512_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("VPADDDZ"), "VPADDD_Z missing");
assert!(has("VADDPSZ"), "VADDPS_Z missing");
assert!(has("VADDPDZ"), "VADDPD_Z missing");
assert!(has("VMULPSZ"), "VMULPS_Z missing");
assert!(has("VANDPSZ"), "VANDPS_Z missing");
assert!(has("VANDNPSZ"), "VANDNPS_Z missing");
assert!(has("VPANDDZ"), "VPANDD_Z missing");
assert!(has("VCVTDQ2PSZ"), "VCVTDQ2PS_Z missing");
assert!(has("VPROLVDZ"), "VPROLVD_Z missing");
assert!(has("VMOVDQA32Z"), "VMOVDQA32_Z missing");
assert!(has("VMOVDQU32Z"), "VMOVDQU32_Z missing");
assert!(has("KADDW"), "KADDW missing");
assert!(has("KSHIFTLW"), "KSHIFTLW missing");
assert!(has("VPBROADCASTDZ"), "VPBROADCASTD_Z missing");
assert!(has("VBROADCASTSSZ"), "VBROADCASTSS_Z missing");
assert!(has("VCOMPRESSPSZ"), "VCOMPRESSPS_Z missing");
assert!(has("VEXPANDPSZ"), "VEXPANDPS_Z missing");
assert!(has("VPGATHERDDZ"), "VPGATHERDD_Z missing");
assert!(has("VP2INTERSECTD"), "VP2INTERSECTD missing");
assert!(has("VCVTNEPS2BF16Z"), "VCVTNEPS2BF16_Z missing");
assert!(has("VDPBF16PSZ"), "VDPBF16PS_Z missing");
assert!(has("VPDPBSSDZ"), "VPDPBSSD_Z missing");
}
#[test]
fn test_fma_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("VFMADD132PD"), "VFMADD132PD missing");
assert!(has("VFMADD213PD"), "VFMADD213PD missing");
assert!(has("VFMADD231PD"), "VFMADD231PD missing");
assert!(has("VFMSUB132PD"), "VFMSUB132PD missing");
assert!(has("VFMADD132PS"), "VFMADD132PS missing");
assert!(has("VFMADD132SS"), "VFMADD132SS missing");
assert!(has("VFMADD132SD"), "VFMADD132SD missing");
assert!(has("VFMADDSUB132PS"), "VFMADDSUB132PS missing");
assert!(has("VFMADDSUB132PD"), "VFMADDSUB132PD missing");
}
#[test]
fn test_bmi_bmi2_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("ANDN32"), "ANDN missing");
assert!(has("BEXTR32"), "BEXTR missing");
assert!(has("BLSI32"), "BLSI missing");
assert!(has("BLSMSK32"), "BLSMSK missing");
assert!(has("BLSR32"), "BLSR missing");
assert!(has("BZHI32"), "BZHI missing");
assert!(has("MULX32"), "MULX missing");
assert!(has("PDEP32"), "PDEP missing");
assert!(has("PEXT32"), "PEXT missing");
assert!(has("RORX32"), "RORX missing");
assert!(has("SARX32"), "SARX missing");
assert!(has("SHLX32"), "SHLX missing");
assert!(has("SHRX32"), "SHRX missing");
assert!(has("TZCNT"), "TZCNT missing");
assert!(has("LZCNT"), "LZCNT missing");
}
#[test]
fn test_register_defs_generation() {
let defs = X86RegisterDefs::generate();
assert_eq!(defs.gr8.len(), 20);
assert_eq!(defs.gr16.len(), 16);
assert_eq!(defs.gr32.len(), 16);
assert_eq!(defs.gr64.len(), 16);
assert_eq!(defs.vr128.len(), 32, "Should have 32 XMM registers");
assert_eq!(defs.vr256.len(), 32, "Should have 32 YMM registers");
assert_eq!(defs.vr512.len(), 32, "Should have 32 ZMM registers");
assert_eq!(defs.mask_regs.len(), 8);
assert_eq!(defs.segment_regs.len(), 6);
assert_eq!(defs.control_regs.len(), 16);
assert_eq!(defs.debug_regs.len(), 16);
assert_eq!(defs.x87_regs.len(), 8);
assert_eq!(defs.mmx_regs.len(), 8);
assert_eq!(defs.bound_regs.len(), 4);
assert_eq!(defs.tile_regs.len(), 8);
}
#[test]
fn test_register_class_generation() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let class_names: Vec<&str> = backend
.register_classes
.iter()
.map(|c| c.name.as_str())
.collect();
assert!(class_names.contains(&"GR8"));
assert!(class_names.contains(&"GR16"));
assert!(class_names.contains(&"GR32"));
assert!(class_names.contains(&"GR64"));
assert!(class_names.contains(&"FR32"));
assert!(class_names.contains(&"FR64"));
assert!(class_names.contains(&"VR128"));
assert!(class_names.contains(&"VR256"));
assert!(class_names.contains(&"VR512"));
assert!(class_names.contains(&"VK64"));
assert!(class_names.contains(&"RFLAGS"));
assert!(class_names.contains(&"RFP80"));
}
#[test]
fn test_pattern_generation() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
!backend.patterns.is_empty(),
"Should have pattern fragments"
);
let names: Vec<&str> = backend.patterns.iter().map(|p| p.name.as_str()).collect();
assert!(names.contains(&"load"), "load pattern missing");
assert!(names.contains(&"store"), "store pattern missing");
assert!(names.contains(&"add"), "add pattern missing");
assert!(names.contains(&"sub"), "sub pattern missing");
assert!(names.contains(&"mul"), "mul pattern missing");
assert!(names.contains(&"fadd"), "fadd pattern missing");
assert!(names.contains(&"zext"), "zext pattern missing");
assert!(names.contains(&"sext"), "sext pattern missing");
assert!(names.contains(&"lea_addr"), "lea_addr pattern missing");
assert!(names.contains(&"setcc"), "setcc pattern missing");
}
#[test]
fn test_complex_patterns() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
!backend.complex_patterns.is_empty(),
"Should have complex patterns"
);
let names: Vec<&str> = backend
.complex_patterns
.iter()
.map(|p| p.name.as_str())
.collect();
assert!(names.contains(&"Addr"));
assert!(names.contains(&"LEAAddr"));
assert!(names.contains(&"TLSAddr"));
assert!(names.contains(&"GlobalBaseReg"));
}
#[test]
fn test_isel_dag_patterns_generation() {
let dag = X86ISelDAGPatterns::generate();
assert!(!dag.entries.is_empty(), "Should have DAG pattern entries");
let names: Vec<&str> = dag.entries.iter().map(|e| e.name).collect();
assert!(names.contains(&"ADD32rr"));
assert!(names.contains(&"SUB32rr"));
assert!(names.contains(&"IMUL32rr"));
assert!(names.contains(&"AND32rr"));
assert!(names.contains(&"OR32rr"));
assert!(names.contains(&"XOR32rr"));
assert!(names.contains(&"SHL32rCL"));
assert!(names.contains(&"ADDSSrr"));
assert!(names.contains(&"ADDSDrr"));
assert!(names.contains(&"ADDPSrr"));
assert!(names.contains(&"ADDPDrr"));
assert!(names.contains(&"PADDBrr"));
assert!(names.contains(&"VADDPSrr"));
assert!(names.contains(&"VADDPSZrr"));
assert!(names.contains(&"VFMADD132PDr"));
assert!(names.contains(&"ANDN32rr"));
assert!(names.contains(&"SHLX32rr"));
}
#[test]
fn test_calling_conventions() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let names: Vec<&str> = backend
.calling_conventions
.iter()
.map(|c| c.name.as_str())
.collect();
assert!(names.contains(&"SysV_AMD64"));
assert!(names.contains(&"SysV_i386"));
assert!(names.contains(&"Win64"));
}
#[test]
fn test_scheduling_records() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
!backend.scheduling_records.is_empty(),
"Should have scheduling records"
);
let names: Vec<&str> = backend
.scheduling_records
.iter()
.map(|s| s.name.as_str())
.collect();
assert!(names.contains(&"WriteALU"));
assert!(names.contains(&"WriteLoad"));
assert!(names.contains(&"WriteStore"));
assert!(names.contains(&"WriteIMul"));
assert!(names.contains(&"WriteIDiv"));
}
#[test]
fn test_export_instr_info() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let defs = backend.export_instr_defs();
assert!(defs.len() >= 200);
assert!(backend.instr_count() >= 200);
}
#[test]
fn test_export_register_info() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let info = backend.export_register_info();
let _ = info;
}
#[test]
fn test_build_isel_table() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let table = backend.build_isel_table();
assert!(
!table.patterns.is_empty(),
"ISel table should have patterns"
);
}
#[test]
fn test_isel_dag_type_inference() {
let dag = X86ISelDAGPatterns::generate();
assert!(!dag.type_inference.is_empty());
let names: Vec<&str> = dag
.type_inference
.iter()
.map(|t| t.pattern_name.as_str())
.collect();
assert!(names.contains(&"ADD32rr"));
assert!(names.contains(&"ADDSSrr"));
assert!(names.contains(&"PADDBrr"));
}
#[test]
fn test_isel_dag_custom_inserters() {
let dag = X86ISelDAGPatterns::generate();
let handlers: Vec<&str> = dag
.custom_inserters
.iter()
.map(|c| c.handler_name.as_str())
.collect();
assert!(handlers.contains(&"InsertCMOV"));
assert!(handlers.contains(&"InsertSETCC"));
assert!(handlers.contains(&"InsertJCC"));
}
#[test]
fn test_isel_dag_complex_pattern_handlers() {
let dag = X86ISelDAGPatterns::generate();
let names: Vec<&str> = dag
.complex_pattern_handlers
.iter()
.map(|c| c.name.as_str())
.collect();
assert!(names.contains(&"Addr"));
assert!(names.contains(&"LEAAddr"));
}
#[test]
fn test_instruction_required_features() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let vaddps = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VADDPSrr");
assert!(vaddps.is_some(), "VADDPSrr should exist");
assert!(vaddps
.unwrap()
.required_features
.contains(&"avx".to_string()));
let andn = backend
.instructions
.iter()
.find(|i| i.mnemonic == "ANDN32rr");
assert!(andn.is_some(), "ANDN32rr should exist");
assert!(andn.unwrap().required_features.contains(&"bmi".to_string()));
}
#[test]
fn test_avx_vex_encoding_flag() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let vaddps = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VADDPSrr")
.expect("VADDPSrr should exist");
assert!(vaddps.is_vex, "VADDPSrr should be VEX-encoded");
assert_eq!(vaddps.vex_l, Some(true), "VADDPSrr L=1 for 256-bit");
assert!(vaddps.is_three_address, "VADDPSrr is three-address");
let add32 = backend
.instructions
.iter()
.find(|i| i.mnemonic == "ADD32rr")
.expect("ADD32rr should exist");
assert!(!add32.is_vex, "ADD32rr should NOT be VEX-encoded");
}
#[test]
fn test_evex_encoding_flag() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let vpaddd_z = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VPADDDZ128rr")
.expect("VPADDDZ128rr should exist");
assert!(vpaddd_z.is_evex, "VPADDDZ128rr should be EVEX-encoded");
assert_eq!(vpaddd_z.evex_tuple, Some(X86EvexTuple::FV));
assert!(vpaddd_z.required_features.contains(&"avx512f".to_string()));
}
#[test]
fn test_evex_rounding_support() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let vaddps_rnd = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VADDPSZ128rrb")
.expect("VADDPSZ128rrb should exist");
assert!(
vaddps_rnd.evex_rounding,
"VADDPSZ128rrb should support rounding"
);
}
#[test]
fn test_evex_broadcast_and_sae() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let vgather = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VPGATHERDDrm" || i.mnemonic == "VPGATHERDDZrm")
.expect("Gather instruction should exist");
assert!(vgather.has_side_effects, "Gather should have side effects");
assert!(vgather.may_load, "Gather should may_load");
}
#[test]
fn test_instruction_operand_types() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let add32rr = backend
.instructions
.iter()
.find(|i| i.mnemonic == "ADD32rr")
.expect("ADD32rr missing");
assert_eq!(add32rr.operand_types.len(), 2);
assert_eq!(add32rr.operand_types[0], OperandType::Reg32);
assert_eq!(add32rr.operand_types[1], OperandType::Reg32);
let movssrm = backend
.instructions
.iter()
.find(|i| i.mnemonic == "MOVSSrm")
.expect("MOVSSrm missing");
assert_eq!(movssrm.operand_types[0], OperandType::XmmReg);
assert_eq!(movssrm.operand_types[1], OperandType::Mem32);
assert!(movssrm.may_load);
}
#[test]
fn test_implicit_defs_and_uses() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mul32 = backend
.instructions
.iter()
.find(|i| i.mnemonic == "MUL32r")
.expect("MUL32r missing");
assert!(
mul32.implicit_defs.contains(&0),
"Should define EAX (RAX=0)"
);
assert!(
mul32.implicit_defs.contains(&2),
"Should define EDX (RDX=2)"
);
let syscall = backend
.instructions
.iter()
.find(|i| i.mnemonic == "SYSCALL")
.expect("SYSCALL missing");
assert!(
syscall.implicit_defs.len() > 5,
"SYSCALL should define many regs"
);
}
#[test]
fn test_is_barrier_property() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let ret = backend
.instructions
.iter()
.find(|i| i.mnemonic == "RET")
.expect("RET missing");
assert!(ret.is_barrier, "RET should be a barrier");
let jmp = backend
.instructions
.iter()
.find(|i| i.mnemonic == "JMP32r")
.expect("JMP32r missing");
assert!(jmp.is_barrier, "JMP should be a barrier");
}
#[test]
fn test_re_materializable() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mov32ri = backend
.instructions
.iter()
.find(|i| i.mnemonic == "MOV32ri")
.expect("MOV32ri missing");
assert!(mov32ri.is_re_materializable);
let lea32 = backend
.instructions
.iter()
.find(|i| i.mnemonic == "LEA32r")
.expect("LEA32r missing");
assert!(lea32.is_re_materializable);
}
#[test]
fn test_default_isel_table_construction() {
let table = ISelTable::new();
assert!(table.patterns.is_empty());
let entries = X86ISelDAGPatterns::generate().entries;
let table = ISelTable::from_entries(entries);
assert!(!table.patterns.is_empty());
}
#[test]
fn test_all_instruction_formats_used() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mut formats = std::collections::HashSet::new();
for instr in &backend.instructions {
formats.insert(format!("{:?}", instr.format));
}
assert!(
formats.len() >= 5,
"Should use at least 5 different instruction formats, got {}: {:?}",
formats.len(),
formats
);
}
#[test]
fn test_all_opcode_maps_used() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mut maps = std::collections::HashSet::new();
for instr in &backend.instructions {
maps.insert(format!("{:?}", instr.opcode_map));
}
assert!(
maps.len() >= 3,
"Should use at least OB, TB, and T8 maps, got {}: {:?}",
maps.len(),
maps
);
}
#[test]
fn test_aes_sha_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("AESENC"), "AESENC missing");
assert!(has("AESENCLAST"), "AESENCLAST missing");
assert!(has("AESDEC"), "AESDEC missing");
assert!(has("AESDECLAST"), "AESDECLAST missing");
assert!(has("AESKEYGENASSIST"), "AESKEYGENASSIST missing");
assert!(has("PCLMULQDQ"), "PCLMULQDQ missing");
assert!(has("SHA1RNDS4"), "SHA1RNDS4 missing");
assert!(has("SHA1NEXTE"), "SHA1NEXTE missing");
assert!(has("SHA256RNDS2"), "SHA256RNDS2 missing");
assert!(has("SHA256MSG1"), "SHA256MSG1 missing");
assert!(has("SHA256MSG2"), "SHA256MSG2 missing");
}
#[test]
fn test_x87_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("FLD"), "FLD missing");
assert!(has("FST"), "FST missing");
assert!(has("FSTP"), "FSTP missing");
assert!(has("FADD_ST0"), "FADD_ST0 missing");
assert!(has("FSUB_ST0"), "FSUB_ST0 missing");
assert!(has("FMUL_ST0"), "FMUL_ST0 missing");
assert!(has("FDIV_ST0"), "FDIV_ST0 missing");
assert!(has("FCHS"), "FCHS missing");
assert!(has("FABS"), "FABS missing");
assert!(has("FSQRT"), "FSQRT missing");
assert!(has("FSIN"), "FSIN missing");
assert!(has("FCOS"), "FCOS missing");
assert!(has("FPTAN"), "FPTAN missing");
assert!(has("FPATAN"), "FPATAN missing");
assert!(has("FYL2X"), "FYL2X missing");
assert!(has("F2XM1"), "F2XM1 missing");
assert!(has("FRNDINT"), "FRNDINT missing");
assert!(has("FILD"), "FILD missing");
assert!(has("FISTP"), "FISTP missing");
assert!(has("FCOM"), "FCOM missing");
assert!(has("FTST"), "FTST missing");
assert!(has("FXAM"), "FXAM missing");
assert!(has("FLDCW"), "FLDCW missing");
assert!(has("FNSTCW"), "FNSTCW missing");
assert!(has("FXCH"), "FXCH missing");
}
#[test]
fn test_mmx_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("MMX_MOVD"), "MMX MOVD missing");
assert!(has("MMX_MOVQ"), "MMX MOVQ missing");
assert!(has("MMX_PADDB"), "MMX PADDB missing");
assert!(has("MMX_PADDW"), "MMX PADDW missing");
assert!(has("MMX_PADDD"), "MMX PADDD missing");
assert!(has("MMX_PSUBB"), "MMX PSUBB missing");
assert!(has("MMX_PMULLW"), "MMX PMULLW missing");
assert!(has("MMX_PAND"), "MMX PAND missing");
assert!(has("MMX_POR"), "MMX POR missing");
assert!(has("MMX_PXOR"), "MMX PXOR missing");
assert!(has("MMX_PSLLW"), "MMX PSLLW missing");
assert!(has("MMX_PSLLD"), "MMX PSLLD missing");
assert!(has("MMX_PSRLW"), "MMX PSRLW missing");
assert!(has("MMX_PSRLD"), "MMX PSRLD missing");
assert!(has("MMX_PSRAW"), "MMX PSRAW missing");
assert!(has("MMX_PSRAD"), "MMX PSRAD missing");
assert!(has("MMX_PCMPEQB"), "MMX PCMPEQB missing");
assert!(has("MMX_PCMPEQW"), "MMX PCMPEQW missing");
assert!(has("MMX_PCMPEQD"), "MMX PCMPEQD missing");
assert!(has("MMX_PACKSSWB"), "MMX PACKSSWB missing");
assert!(has("MMX_PACKSSDW"), "MMX PACKSSDW missing");
assert!(has("MMX_PUNPCKLBW"), "MMX PUNPCKLBW missing");
assert!(has("MMX_EMMS"), "MMX EMMS missing");
}
#[test]
fn test_additional_instructions_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("BSWAP"), "BSWAP missing");
assert!(has("BT"), "BT missing");
assert!(has("BTS"), "BTS missing");
assert!(has("BTR"), "BTR missing");
assert!(has("BTC"), "BTC missing");
assert!(has("BSF"), "BSF missing");
assert!(has("BSR"), "BSR missing");
assert!(has("MOVSXD"), "MOVSXD missing");
assert!(has("POPCNT"), "POPCNT missing");
assert!(has("PAUSE"), "PAUSE missing");
assert!(has("ROUNDPS"), "ROUNDPS missing");
assert!(has("ROUNDPD"), "ROUNDPD missing");
assert!(has("CLFLUSH"), "CLFLUSH missing");
assert!(has("PREFETCH"), "PREFETCH missing");
assert!(has("MOVNTI"), "MOVNTI missing");
assert!(has("ADCX"), "ADCX missing");
assert!(has("ADOX"), "ADOX missing");
}
#[test]
fn test_avx512_vl_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("VPABSBZ128"), "VPABSB_Z VL missing");
assert!(has("VPABSWZ128"), "VPABSW_Z VL missing");
assert!(has("VPOPCNTBZ128"), "VPOPCNTB_Z VL missing");
assert!(has("VPERMQZ"), "VPERMQ_Z missing");
assert!(has("VSHUFF32X4Z"), "VSHUFF32X4_Z missing");
assert!(has("VALIGNDZ"), "VALIGND_Z missing");
assert!(has("VPSCATTERDDZ"), "VPSCATTERDD_Z missing");
assert!(has("VCMPPSZ"), "VCMPPS_Z missing");
assert!(has("VCMPPDZ"), "VCMPPD_Z missing");
assert!(has("VPCMPEQBZ"), "VPCMPEQB_Z missing");
assert!(has("VPCMPGTBZ"), "VPCMPGTB_Z missing");
assert!(has("VMOVDQU8Z"), "VMOVDQU8_Z missing");
assert!(has("VMOVDQU16Z"), "VMOVDQU16_Z missing");
assert!(has("VADDPHZ"), "VADDPH_Z missing");
assert!(has("VMULPHZ"), "VMULPH_Z missing");
assert!(has("VSQRTPHZ"), "VSQRTPH_Z missing");
assert!(has("VCVTPH2WZ"), "VCVTPH2W_Z missing");
}
#[test]
fn test_amx_coverage() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has = |s: &str| mnemonics.iter().any(|&m| m.starts_with(s));
assert!(has("TDPBSSDZ"), "TDPBSSD_Z missing");
assert!(has("TDPBF16PSZ"), "TDPBF16PS_Z missing");
assert!(has("TILELOADDZ"), "TILELOADD_Z missing");
assert!(has("TILESTOREDZ"), "TILESTORED_Z missing");
}
#[test]
fn test_isel_dag_avx512_patterns() {
let dag = X86ISelDAGPatterns::generate();
let names: Vec<&str> = dag.entries.iter().map(|e| e.name).collect();
assert!(names.contains(&"VMULPSZrr"));
assert!(names.contains(&"VANDPSZrr"));
assert!(names.contains(&"VMOVDQA32Zrr"));
assert!(names.contains(&"VPGATHERDDZrm"));
assert!(names.contains(&"VCOMPRESSPSZrr"));
assert!(names.contains(&"VBROADCASTSSZrr"));
assert!(names.contains(&"VADDPHZrr"));
}
#[test]
fn test_opcode_count_exceeds_300() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
assert!(
backend.instructions.len() >= 300,
"Expected >= 300 instruction definitions, got {}",
backend.instructions.len()
);
}
#[test]
fn test_bmi_bmi2_vex_flags() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let andn = backend
.instructions
.iter()
.find(|i| i.mnemonic == "ANDN32rr")
.expect("ANDN32rr should exist");
assert!(andn.is_vex, "ANDN should be VEX-encoded");
assert_eq!(andn.vex_l, Some(false), "ANDN L=0 for 32-bit");
assert!(andn.is_three_address, "ANDN is three-address");
let rorx = backend
.instructions
.iter()
.find(|i| i.mnemonic == "RORX32ri")
.expect("RORX32ri should exist");
assert!(rorx.is_vex, "RORX should be VEX-encoded");
}
#[test]
fn test_fma_vex_flags() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let fmadd = backend
.instructions
.iter()
.find(|i| i.mnemonic == "VFMADD132PDr")
.expect("VFMADD132PDr should exist");
assert!(fmadd.is_vex, "VFMADD should be VEX-encoded");
assert_eq!(fmadd.vex_l, Some(true), "VFMADD PD L=1");
assert_eq!(fmadd.vex_w, Some(true), "VFMADD PD W=1");
assert!(fmadd.is_three_address, "VFMADD is three-address");
}
#[test]
fn test_instruction_count_breakdown_by_family() {
let mut backend = X86TableGenFull::new();
backend.generate_all();
let mnemonics: Vec<&str> = backend
.instructions
.iter()
.map(|i| i.mnemonic.as_str())
.collect();
let has_prefix = |p: &str| mnemonics.iter().filter(|m| m.starts_with(p)).count();
let mov_count = has_prefix("MOV") + has_prefix("CMOV");
assert!(mov_count >= 10, "MOV family count: {}", mov_count);
let add_count = has_prefix("ADD") - has_prefix("ADDSUB");
assert!(add_count >= 4, "ADD count: {}", add_count);
let sse_count = has_prefix("ADDSS")
+ has_prefix("ADDSD")
+ has_prefix("SUBSS")
+ has_prefix("SUBSD")
+ has_prefix("MULSS")
+ has_prefix("MULSD");
assert!(sse_count >= 6, "SSE scalar count: {}", sse_count);
let avx_count = has_prefix("VADD")
+ has_prefix("VSUB")
+ has_prefix("VMUL")
+ has_prefix("VDIV")
+ has_prefix("VAND")
+ has_prefix("VOR")
+ has_prefix("VXOR")
+ has_prefix("VBROADCAST");
assert!(avx_count >= 8, "AVX count: {}", avx_count);
let avx512_count = mnemonics.iter().filter(|m| m.contains("Z")).count();
assert!(avx512_count >= 15, "AVX-512 count: {}", avx512_count);
}
}