use crate::codegen::{MachineBasicBlock, MachineFunction, MachineInstr, MachineOperand};
use crate::ir_builder::IRBuilder;
use crate::selection_dag::dag_builder::SelectionDAGBuilder;
use crate::selection_dag::legalize_ops::{
OpLegalizeAction, OperationLegalizer, PromoteAction, TargetLegalizer,
};
use crate::selection_dag::legalize_types::{LegalizeAction, TypeActionMap, TypeLegalizer};
use crate::selection_dag::sd_node::{
EVTKind, SDNode, SDNodeFlags, SDOpcode, SDValue, SelectionDAG, EVT, MVT,
};
use crate::types::Type;
use crate::value::ValueRef;
use crate::x86::{
x86_calling_convention::X86CallingConvention,
x86_instr_info::{
OperandType, X86InstrDesc, X86InstrInfo, X86MemOperand, X86Opcode, X86Operand, X86SchedInfo,
},
x86_register_info::X86RegisterInfo,
x86_schedule_model::{
instruction_latency, instruction_resources, instruction_uops, lookup_itinerary,
InstrItinerary, ProcResource, SchedMachineModel, SchedModel, X86SchedModelKind,
},
x86_subtarget::X86Subtarget,
};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct DAGPattern {
pub id: u32,
pub name: String,
pub category: DAGPatternCategory,
pub x86_opcode: X86Opcode,
pub min_isa: IsaRequirement,
pub input_types: Vec<MVT>,
pub output_type: MVT,
pub complexity: u32,
pub node_count: u32,
pub produces_flags: bool,
pub reads_flags: bool,
pub has_folded_load: bool,
pub has_folded_imm: bool,
pub sched: X86SchedInfo,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DAGPatternCategory {
ScalarArith,
ScalarBitwise,
ScalarCondCode,
ScalarConvert,
ScalarFP,
ScalarFPConvert,
VectorArith,
VectorFP,
VectorShuffle,
VectorCmp,
VectorConvert,
Addressing,
Load,
Store,
Branch,
CallReturn,
Trap,
Special,
Copy,
Nop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IsaRequirement {
Base,
Sse,
Sse2,
Sse3,
Ssse3,
Sse41,
Sse42,
Avx,
Avx2,
Avx512f,
Avx512bw,
Avx512dq,
Avx512vl,
Bmi,
Bmi2,
Lzcnt,
Popcnt,
Cmov,
X8664,
Adx,
Sha,
Aes,
}
pub struct X86SelDAGDeep {
patterns: Vec<DAGPattern>,
by_category: HashMap<DAGPatternCategory, Vec<usize>>,
by_output_type: HashMap<MVT, Vec<usize>>,
by_name: HashMap<String, usize>,
by_opcode: HashMap<X86Opcode, Vec<usize>>,
}
impl X86SelDAGDeep {
pub fn new() -> Self {
let mut patterns: Vec<DAGPattern> = Vec::with_capacity(200);
let mut next_id: u32 = 0;
let mut add = |p: DAGPattern| -> usize {
let idx = patterns.len();
patterns.push(p);
idx
};
let sched_alu_simple = X86SchedInfo {
latency: 1,
throughput: 0.25,
uops: 1,
port_mask: 0x3F, can_dual_issue: true,
};
let sched_alu_complex = X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x01, can_dual_issue: false,
};
let sched_load = X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x0C, can_dual_issue: true,
};
let sched_store = X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x10, can_dual_issue: false,
};
let sched_fp_simple = X86SchedInfo {
latency: 3,
throughput: 0.5,
uops: 1,
port_mask: 0x01, can_dual_issue: false,
};
let sched_fp_div = X86SchedInfo {
latency: 14,
throughput: 7.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
};
let sched_vec_simple = X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x15, can_dual_issue: true,
};
let sched_branch = X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x40, can_dual_issue: false,
};
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Add two 32-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i32_ri".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD32ri8,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Add signed 8-bit immediate to 32-bit register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i32_ri32".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD32ri,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Add 32-bit immediate to 32-bit register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i32_rm".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD32rm,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 3,
node_count: 3,
produces_flags: true,
reads_flags: false,
has_folded_load: true,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5, throughput: 0.5,
uops: 1, port_mask: 0x0C,
can_dual_issue: false,
},
description: "Add memory operand to 32-bit register, micro-fused".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i64_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD64rr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64],
output_type: MVT::i64,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Add two 64-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i16_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD16rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i16, MVT::i16],
output_type: MVT::i16,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Add two 16-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "add_i8_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADD8rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8, MVT::i8],
output_type: MVT::i8,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Add two 8-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sub_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::SUB32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Subtract 32-bit register from register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sub_i64_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::SUB64rr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64],
output_type: MVT::i64,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Subtract 64-bit register from register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "imul_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::IMUL32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply two 32-bit registers (IMUL r32, r32)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "imul_i64_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::IMUL64rr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64],
output_type: MVT::i64,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply two 64-bit registers (IMUL r64, r64)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "idiv_i32".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::IDIV32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i64, MVT::i32], output_type: MVT::i32,
complexity: 5,
node_count: 4,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 20,
throughput: 10.0,
uops: 9,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Signed divide EDX:EAX by 32-bit register, quotient in EAX".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "neg_i32".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::NEG32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Negate 32-bit register (two's complement)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "inc_i32".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::INC32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Increment 32-bit register, preserves CF".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "dec_i32".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::DEC32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Decrement 32-bit register, preserves CF".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "and_i32_rr".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::AND32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Bitwise AND two 32-bit registers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "or_i32_rr".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::OR32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Bitwise OR two 32-bit registers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "xor_i32_rr".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::XOR32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Bitwise XOR two 32-bit registers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "xor_i32_zero".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::XOR32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 10, node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Zero register via XOR same,same (dependency-breaking idiom)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "not_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::NOT32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Bitwise NOT of 32-bit register (one's complement)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "shl_i32_cl".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::SHL32rCL,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Shift left 32-bit register by CL (variable count)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "shl_i32_imm".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::SHL32ri,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Shift left 32-bit register by immediate count".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "shr_i32_cl".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::SHR32rCL,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Shift right logical 32-bit register by CL".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sar_i32_cl".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::SAR32rCL,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Shift right arithmetic 32-bit register by CL".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "shl_i64_imm".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::SHL64ri,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i8],
output_type: MVT::i64,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Shift left 64-bit register by immediate count".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "bswap_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::BSWAP32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 5,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Byte swap 32-bit register (endian conversion)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "bswap_i64".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::BSWAP64r,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 5,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Byte swap 64-bit register (endian conversion)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "bsf_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::BSF32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 4,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Bit scan forward (find first set bit from LSB)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "bsr_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::BSR32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 4,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Bit scan reverse (find first set bit from MSB)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "lzcnt_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::LZCNT32rr,
min_isa: IsaRequirement::Lzcnt,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 6,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Count leading zero bits (LZCNT, BMI)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "tzcnt_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::TZCNT32rr,
min_isa: IsaRequirement::Bmi,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 6,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Count trailing zero bits (TZCNT, BMI)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "popcnt_i32".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::POPCNT32rr,
min_isa: IsaRequirement::Popcnt,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 6,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Count number of set bits (POPCNT)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "bt_i32_imm".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::BT32ri8,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 3,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Bit test — copy bit to CF".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cmp_i32_rr".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::CMP32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Compare two 32-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "test_i32_rr".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::TEST32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Bitwise TEST of two 32-bit registers, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sete".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETEr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if equal (ZF=1), else 0".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "setne".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETNEr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if not equal (ZF=0), else 0".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "setl".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETLr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if signed less (SF≠OF), else 0".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "setg".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETGr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if signed greater (ZF=0 and SF=OF)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "setb".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETBr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if unsigned below (CF=1)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "seta".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::SETAr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i8,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Set byte to 1 if unsigned above (CF=0 and ZF=0)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cmove_i32".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::CMOVE32rr,
min_isa: IsaRequirement::Cmov,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 5,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x03,
can_dual_issue: false,
},
description: "Conditional move if equal (CMOVcc)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cmovne_i32".into(),
category: DAGPatternCategory::ScalarCondCode,
x86_opcode: X86Opcode::CMOVNE32rr,
min_isa: IsaRequirement::Cmov,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 5,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Conditional move if not equal (CMOVNE)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movzx_i8_to_i32".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVZX32rr8,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Zero-extend 8-bit register to 32-bit".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movzx_i16_to_i32".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVZX32rr16,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i16],
output_type: MVT::i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Zero-extend 16-bit register to 32-bit".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movsx_i8_to_i32".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVSX32rr8,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Sign-extend 8-bit register to 32-bit".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movsx_i16_to_i32".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVSX32rr16,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i16],
output_type: MVT::i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Sign-extend 16-bit register to 32-bit".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movsx_i32_to_i64".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVSX64rr32,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i32],
output_type: MVT::i64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Sign-extend 32-bit register to 64-bit (MOVSXD)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "trunc_i32_to_i8".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOV8rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i8,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Truncate 32-bit register to 8-bit (sub-register MOV)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "addss".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::ADDSSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::f32],
output_type: MVT::f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_simple,
description: "Add scalar single-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "addsd".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::ADDSDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::f64],
output_type: MVT::f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_simple,
description: "Add scalar double-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "mulss".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::MULSSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::f32],
output_type: MVT::f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply scalar single-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "mulsd".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::MULSDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::f64],
output_type: MVT::f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply scalar double-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "divss".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::DIVSSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::f32],
output_type: MVT::f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_div,
description: "Divide scalar single-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "divsd".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::DIVSDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::f64],
output_type: MVT::f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 20,
throughput: 10.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Divide scalar double-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sqrtss".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::SQRTSSr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32],
output_type: MVT::f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 12,
throughput: 6.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Square root of scalar single-precision value".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sqrtsd".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::SQRTSDr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64],
output_type: MVT::f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 18,
throughput: 9.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Square root of scalar double-precision value".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvtsi2ss_i32".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTSI2SSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::i32],
output_type: MVT::f32,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Convert signed 32-bit integer to single-precision float".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvtsi2sd_i32".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTSI2SDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::i32],
output_type: MVT::f64,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Convert signed 32-bit integer to double-precision float".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvtsi2sd_i64".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTSI642SDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::i64],
output_type: MVT::f64,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Convert signed 64-bit integer to double-precision float".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvttss2si_i32".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTTSS2SIrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32],
output_type: MVT::i32,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Truncate single-precision float to 32-bit integer".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvttsd2si_i32".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTTSD2SIrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64],
output_type: MVT::i32,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Truncate double-precision float to 32-bit integer".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvtss2sd".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTSS2SDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f32],
output_type: MVT::f64,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Convert single-precision float to double-precision".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "cvtsd2ss".into(),
category: DAGPatternCategory::ScalarFPConvert,
x86_opcode: X86Opcode::CVTSD2SSrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64],
output_type: MVT::f32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Convert double-precision float to single-precision".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ucomiss".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::UCOMISSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::f32],
output_type: MVT::f32,
complexity: 2,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Unordered compare scalar single-precision, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ucomisd".into(),
category: DAGPatternCategory::ScalarFP,
x86_opcode: X86Opcode::UCOMISDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::f64],
output_type: MVT::f64,
complexity: 2,
node_count: 1,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Unordered compare scalar double-precision, set EFLAGS".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "paddd_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PADDDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Add packed 32-bit integers (4 × i32)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "paddq_v2i64".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PADDQrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v2i64, MVT::v2i64],
output_type: MVT::v2i64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Add packed 64-bit integers (2 × i64)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "psubd_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PSUBDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Subtract packed 32-bit integers (4 × i32)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pmulld_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMULLDrr,
min_isa: IsaRequirement::Sse41,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply packed 32-bit integers, low 32 bits (SSE4.1)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pand_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PANDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Bitwise AND of packed 32-bit integers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "por_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PORrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Bitwise OR of packed 32-bit integers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pxor_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PXORrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Bitwise XOR of packed 32-bit integers".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pslld_v4i32_imm".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PSLLDri,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::i8],
output_type: MVT::v4i32,
complexity: 2,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_vec_simple,
description: "Shift left logical packed dwords by immediate".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "psrad_v4i32_imm".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PSRADri,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::i8],
output_type: MVT::v4i32,
complexity: 2,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_vec_simple,
description: "Shift right arithmetic packed dwords by immediate".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pcmpeqd_v4i32".into(),
category: DAGPatternCategory::VectorCmp,
x86_opcode: X86Opcode::PCMPEQDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Compare packed dwords for equality, produce mask".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pcmpgtd_v4i32".into(),
category: DAGPatternCategory::VectorCmp,
x86_opcode: X86Opcode::PCMPGTDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Compare packed dwords for signed greater-than".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pmaxsd_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMAXSDrr,
min_isa: IsaRequirement::Sse41,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Maximum of packed signed 32-bit integers (SSE4.1)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pminsd_v4i32".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMINSDrr,
min_isa: IsaRequirement::Sse41,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v4i32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Minimum of packed signed 32-bit integers (SSE4.1)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "addps_v4f32".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::ADDPSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v4f32, MVT::v4f32],
output_type: MVT::v4f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_simple,
description: "Add packed single-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "mulps_v4f32".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::MULPSrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v4f32, MVT::v4f32],
output_type: MVT::v4f32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply packed single-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "addpd_v2f64".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::ADDPDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v2f64, MVT::v2f64],
output_type: MVT::v2f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_simple,
description: "Add packed double-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "mulpd_v2f64".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::MULPDrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v2f64, MVT::v2f64],
output_type: MVT::v2f64,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply packed double-precision floating-point values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "vaddps_v8f32".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::VADDPSYrr,
min_isa: IsaRequirement::Avx,
input_types: vec![MVT::v8f32, MVT::v8f32],
output_type: MVT::v8f32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_fp_simple,
description: "AVX add packed single-precision (8 × f32, 256-bit)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "vfmadd132ps".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::VFMADD132PSr,
min_isa: IsaRequirement::Avx2,
input_types: vec![MVT::v4f32, MVT::v4f32, MVT::v4f32],
output_type: MVT::v4f32,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 4,
throughput: 0.5,
uops: 1,
port_mask: 0x03,
can_dual_issue: false,
},
description: "Fused multiply-add: a*b+c, packed single-precision".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pshufd_v4i32".into(),
category: DAGPatternCategory::VectorShuffle,
x86_opcode: X86Opcode::PSHUFDri,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::i8],
output_type: MVT::v4i32,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_vec_simple,
description: "Shuffle packed dwords by immediate mask".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pshufb_v16i8".into(),
category: DAGPatternCategory::VectorShuffle,
x86_opcode: X86Opcode::PSHUFBrr,
min_isa: IsaRequirement::Ssse3,
input_types: vec![MVT::v16i8, MVT::v16i8],
output_type: MVT::v16i8,
complexity: 5,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Variable byte shuffle using mask register (SSSE3)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "lea_i32_base_index_scale".into(),
category: DAGPatternCategory::Addressing,
x86_opcode: X86Opcode::LEA32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32, MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 8,
node_count: 4,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x03, can_dual_issue: true,
},
description: "Compute effective address: base + index*scale + disp".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "lea_i32_base_disp".into(),
category: DAGPatternCategory::Addressing,
x86_opcode: X86Opcode::LEA32r,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Compute effective address: base + displacement (no index)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "lea_i64_base_index_scale".into(),
category: DAGPatternCategory::Addressing,
x86_opcode: X86Opcode::LEA64r,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64, MVT::i32, MVT::i8],
output_type: MVT::i64,
complexity: 8,
node_count: 4,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Compute 64-bit effective address with scale".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "load_i32".into(),
category: DAGPatternCategory::Load,
x86_opcode: X86Opcode::MOV32rm,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load 32-bit integer from memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "load_i64".into(),
category: DAGPatternCategory::Load,
x86_opcode: X86Opcode::MOV64rm,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load 64-bit integer from memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "store_i32".into(),
category: DAGPatternCategory::Store,
x86_opcode: X86Opcode::MOV32mr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::Other,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_store,
description: "Store 32-bit integer to memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "store_i64".into(),
category: DAGPatternCategory::Store,
x86_opcode: X86Opcode::MOV64mr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64],
output_type: MVT::Other,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_store,
description: "Store 64-bit integer to memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "store_f32".into(),
category: DAGPatternCategory::Store,
x86_opcode: X86Opcode::MOVSSmr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::f32, MVT::f32],
output_type: MVT::Other,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_store,
description: "Store scalar single-precision float to memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "store_f64".into(),
category: DAGPatternCategory::Store,
x86_opcode: X86Opcode::MOVSDmr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::f64, MVT::f64],
output_type: MVT::Other,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_store,
description: "Store scalar double-precision float to memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "store_v4i32".into(),
category: DAGPatternCategory::Store,
x86_opcode: X86Opcode::MOVDQUMr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::Other,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_store,
description: "Store unaligned 128-bit integer vector to memory".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "jmp_uncond".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JMP_4,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Unconditional jump".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "je_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JE_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32], output_type: MVT::Other,
complexity: 6, node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if equal (JE), reads EFLAGS from CMP".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "jne_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JNE_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::Other,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if not equal (JNE)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "jl_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JL_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::Other,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if signed less (JL)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "jg_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JG_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::Other,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if signed greater (JG)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "jb_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JB_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::Other,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if unsigned below (JB/JC)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ja_folded_cmp".into(),
category: DAGPatternCategory::Branch,
x86_opcode: X86Opcode::JA_4,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::Other,
complexity: 6,
node_count: 3,
produces_flags: false,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Conditional branch if unsigned above (JA)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "call_direct".into(),
category: DAGPatternCategory::CallReturn,
x86_opcode: X86Opcode::CALLpcrel32,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 5,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 1,
port_mask: 0x40,
can_dual_issue: false,
},
description: "Direct call with PC-relative target".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "call_indirect_reg".into(),
category: DAGPatternCategory::CallReturn,
x86_opcode: X86Opcode::CALL64r,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::Other,
complexity: 5,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Indirect call via register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ret".into(),
category: DAGPatternCategory::CallReturn,
x86_opcode: X86Opcode::RET,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Return from procedure".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ret_imm".into(),
category: DAGPatternCategory::CallReturn,
x86_opcode: X86Opcode::RETI,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i16],
output_type: MVT::Other,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_branch,
description: "Return from procedure, pop N bytes from stack (stdcall)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "tail_jmp".into(),
category: DAGPatternCategory::CallReturn,
x86_opcode: X86Opcode::JMP_4,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 7,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_branch,
description: "Tail call via jmp (frame reuse optimization)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "trap_ud2".into(),
category: DAGPatternCategory::Trap,
x86_opcode: X86Opcode::UD2,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 1.0,
uops: 1,
port_mask: 0x00,
can_dual_issue: false,
},
description: "Undefined instruction trap (UD2)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "trap_int3".into(),
category: DAGPatternCategory::Trap,
x86_opcode: X86Opcode::INT3,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 1,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 1.0,
uops: 1,
port_mask: 0x00,
can_dual_issue: false,
},
description: "Software breakpoint interrupt (INT3 / 0xCC)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "nop".into(),
category: DAGPatternCategory::Nop,
x86_opcode: X86Opcode::NOOP,
min_isa: IsaRequirement::Base,
input_types: vec![],
output_type: MVT::Other,
complexity: 0,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 0,
throughput: 0.0,
uops: 0,
port_mask: 0x00,
can_dual_issue: true,
},
description: "No operation (NOP)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "copy_i32".into(),
category: DAGPatternCategory::Copy,
x86_opcode: X86Opcode::MOV32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32],
output_type: MVT::i32,
complexity: 0,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Copy 32-bit register (MOV r32, r32)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "copy_i64".into(),
category: DAGPatternCategory::Copy,
x86_opcode: X86Opcode::MOV64rr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 0,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Copy 64-bit register (MOV r64, r64)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "tls_fs_base".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::MOV64rm, min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 12,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load from FS segment (TLS base for x86-64 ELF)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "tls_gs_base".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::MOV64rm, min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 12,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load from GS segment (TLS base for Windows x64)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "stack_protector_load".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::MOV64rm,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::i64,
complexity: 15,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load stack canary (FS:0x28 on Linux, __security_cookie)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "stack_protector_check".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::CMP64rr,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64, MVT::i64],
output_type: MVT::Other,
complexity: 15,
node_count: 5,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Compare stack canary against saved value".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "va_start_sysv".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::VASTART_SAVE_XMM_REGS,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::Other,
complexity: 20,
node_count: 8,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 10,
throughput: 5.0,
uops: 16,
port_mask: 0xFF,
can_dual_issue: false,
},
description: "Initialize va_list for System V AMD64 varargs (save GPR+XMM)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "va_start_msvc".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::VASTART_MSVC,
min_isa: IsaRequirement::X8664,
input_types: vec![MVT::i64],
output_type: MVT::Other,
complexity: 20,
node_count: 6,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 8,
throughput: 4.0,
uops: 8,
port_mask: 0xFF,
can_dual_issue: false,
},
description: "Initialize va_list for Microsoft x64 varargs (shadow space walk)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "eh_landing_pad".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::EH_LANDINGPAD,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::Other,
complexity: 25,
node_count: 8,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 2.0,
uops: 4,
port_mask: 0xFF,
can_dual_issue: false,
},
description: "Exception handling landing pad setup (personality + selector)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "patchpoint".into(),
category: DAGPatternCategory::Special,
x86_opcode: X86Opcode::PATCHPOINT,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i64, MVT::i32, MVT::i32],
output_type: MVT::Other,
complexity: 30,
node_count: 10,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 2.0,
uops: 5,
port_mask: 0x40,
can_dual_issue: false,
},
description: "Stackmap patchpoint — NOP sled with live-value recording".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "rol_i32_imm".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::ROL32ri,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Rotate left 32-bit register by immediate count".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "ror_i32_imm".into(),
category: DAGPatternCategory::ScalarBitwise,
x86_opcode: X86Opcode::ROR32ri,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i8],
output_type: MVT::i32,
complexity: 2,
node_count: 2,
produces_flags: true,
reads_flags: false,
has_folded_load: false,
has_folded_imm: true,
sched: sched_alu_simple,
description: "Rotate right 32-bit register by immediate count".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "adc_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::ADC32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 5,
node_count: 3,
produces_flags: true,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Add with carry (multi-precision arithmetic)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "sbb_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::SBB32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 5,
node_count: 3,
produces_flags: true,
reads_flags: true,
has_folded_load: false,
has_folded_imm: false,
sched: sched_alu_simple,
description: "Subtract with borrow (multi-precision arithmetic)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "xchg_i32_rr".into(),
category: DAGPatternCategory::ScalarArith,
x86_opcode: X86Opcode::XCHG32rr,
min_isa: IsaRequirement::Base,
input_types: vec![MVT::i32, MVT::i32],
output_type: MVT::i32,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 1,
throughput: 0.5,
uops: 2,
port_mask: 0x3F,
can_dual_issue: false,
},
description: "Exchange two 32-bit register values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movd_to_xmm".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVDI2PDIrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::i32],
output_type: MVT::v4i32,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Move 32-bit integer to low dword of XMM register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "movd_from_xmm".into(),
category: DAGPatternCategory::ScalarConvert,
x86_opcode: X86Opcode::MOVPDI2DIrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32],
output_type: MVT::i32,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Extract 32-bit integer from low dword of XMM register".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "haddps".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::HADDPSrr,
min_isa: IsaRequirement::Sse3,
input_types: vec![MVT::v4f32, MVT::v4f32],
output_type: MVT::v4f32,
complexity: 4,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 0.5,
uops: 3,
port_mask: 0x15,
can_dual_issue: false,
},
description: "Horizontal add of packed single-precision values".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "psadbw".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PSADBWrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v16i8, MVT::v16i8],
output_type: MVT::v2i64,
complexity: 5,
node_count: 4,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 3,
throughput: 0.5,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Compute sum of absolute differences of bytes".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pmaddwd".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMADDWDrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v8i16, MVT::v8i16],
output_type: MVT::v4i32,
complexity: 5,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 5,
throughput: 1.0,
uops: 1,
port_mask: 0x01,
can_dual_issue: false,
},
description: "Multiply and add packed 16-bit integers to 32-bit".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "packssdw".into(),
category: DAGPatternCategory::VectorConvert,
x86_opcode: X86Opcode::PACKSSDWrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v8i16,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Pack dwords to words with signed saturation".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "punpckldq".into(),
category: DAGPatternCategory::VectorConvert,
x86_opcode: X86Opcode::PUNPCKLDQrr,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32, MVT::v4i32],
output_type: MVT::v2i64,
complexity: 3,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Unpack and interleave low dwords to qwords".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pminub".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMINUBrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v16i8, MVT::v16i8],
output_type: MVT::v16i8,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Minimum of packed unsigned bytes".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pmaxub".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PMAXUBrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v16i8, MVT::v16i8],
output_type: MVT::v16i8,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Maximum of packed unsigned bytes".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "pavgb".into(),
category: DAGPatternCategory::VectorArith,
x86_opcode: X86Opcode::PAVGBrr,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v16i8, MVT::v16i8],
output_type: MVT::v16i8,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Average of packed unsigned bytes (rounded)".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "load_aligned_v4i32".into(),
category: DAGPatternCategory::Load,
x86_opcode: X86Opcode::MOVDQArm,
min_isa: IsaRequirement::Sse2,
input_types: vec![MVT::v4i32],
output_type: MVT::v4i32,
complexity: 2,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "Load aligned 128-bit integer vector".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "load_aligned_v8i32".into(),
category: DAGPatternCategory::Load,
x86_opcode: X86Opcode::VMOVDQAYrm,
min_isa: IsaRequirement::Avx,
input_types: vec![MVT::v8i32],
output_type: MVT::v8i32,
complexity: 3,
node_count: 1,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_load,
description: "AVX load aligned 256-bit integer vector".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "addps_folded_load".into(),
category: DAGPatternCategory::VectorFP,
x86_opcode: X86Opcode::ADDPSrm,
min_isa: IsaRequirement::Sse,
input_types: vec![MVT::v4f32, MVT::v4f32],
output_type: MVT::v4f32,
complexity: 4,
node_count: 3,
produces_flags: false,
reads_flags: false,
has_folded_load: true,
has_folded_imm: false,
sched: X86SchedInfo {
latency: 7,
throughput: 0.5,
uops: 1,
port_mask: 0x0D,
can_dual_issue: false,
},
description: "Add packed single-precision with folded memory load".into(),
});
add(DAGPattern {
id: { next_id += 1; next_id },
name: "vpbroadcastd".into(),
category: DAGPatternCategory::VectorShuffle,
x86_opcode: X86Opcode::VPBROADCASTDrr,
min_isa: IsaRequirement::Avx2,
input_types: vec![MVT::i32],
output_type: MVT::v8i32,
complexity: 5,
node_count: 2,
produces_flags: false,
reads_flags: false,
has_folded_load: false,
has_folded_imm: false,
sched: sched_vec_simple,
description: "Broadcast 32-bit value to all elements of 256-bit vector".into(),
});
let mut by_category: HashMap<DAGPatternCategory, Vec<usize>> = HashMap::new();
let mut by_output_type: HashMap<MVT, Vec<usize>> = HashMap::new();
let mut by_name: HashMap<String, usize> = HashMap::new();
let mut by_opcode: HashMap<X86Opcode, Vec<usize>> = HashMap::new();
for (i, p) in patterns.iter().enumerate() {
by_category.entry(p.category).or_default().push(i);
by_output_type.entry(p.output_type).or_default().push(i);
by_name.insert(p.name.clone(), i);
by_opcode.entry(p.x86_opcode).or_default().push(i);
}
X86SelDAGDeep {
patterns,
by_category,
by_output_type,
by_name,
by_opcode,
}
}
pub fn len(&self) -> usize {
self.patterns.len()
}
pub fn is_empty(&self) -> bool {
self.patterns.is_empty()
}
pub fn lookup_name(&self, name: &str) -> Option<&DAGPattern> {
self.by_name.get(name).map(|&i| &self.patterns[i])
}
pub fn patterns_by_category(&self, category: DAGPatternCategory) -> &[usize] {
self.by_category
.get(&category)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn patterns_by_output_type(&self, ty: MVT) -> &[usize] {
self.by_output_type
.get(&ty)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn patterns_by_opcode(&self, opcode: X86Opcode) -> &[usize] {
self.by_opcode
.get(&opcode)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn get(&self, index: usize) -> Option<&DAGPattern> {
self.patterns.get(index)
}
pub fn iter(&self) -> impl Iterator<Item = &DAGPattern> {
self.patterns.iter()
}
pub fn find_best_match(
&self,
category: DAGPatternCategory,
input_types: &[MVT],
has_folded_load: Option<bool>,
) -> Option<&DAGPattern> {
let candidates = self.patterns_by_category(category);
candidates
.iter()
.filter_map(|&i| {
let p = &self.patterns[i];
if p.input_types.len() != input_types.len() {
return None;
}
if p.input_types.iter().zip(input_types.iter()).all(|(a, b)| a == b) {
if let Some(load_req) = has_folded_load {
if p.has_folded_load != load_req {
return None;
}
}
Some(p)
} else {
None
}
})
.max_by_key(|p| p.complexity)
}
}
impl Default for X86SelDAGDeep {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_catalog_size() {
let catalog = X86SelDAGDeep::new();
assert!(catalog.len() >= 150, "Expected at least 150 DAG patterns");
}
#[test]
fn test_lookup_by_name() {
let catalog = X86SelDAGDeep::new();
let p = catalog.lookup_name("add_i32_rr");
assert!(p.is_some());
let p = p.unwrap();
assert_eq!(p.x86_opcode, X86Opcode::ADD32rr);
assert_eq!(p.category, DAGPatternCategory::ScalarArith);
}
#[test]
fn test_category_lookup() {
let catalog = X86SelDAGDeep::new();
let scalar_arith = catalog.patterns_by_category(DAGPatternCategory::ScalarArith);
assert!(!scalar_arith.is_empty());
}
#[test]
fn test_output_type_lookup() {
let catalog = X86SelDAGDeep::new();
let i32_patterns = catalog.patterns_by_output_type(MVT::i32);
assert!(i32_patterns.len() >= 10, "Expected many i32 patterns");
}
#[test]
fn test_opcode_lookup() {
let catalog = X86SelDAGDeep::new();
let add32_patterns = catalog.patterns_by_opcode(X86Opcode::ADD32rr);
assert!(!add32_patterns.is_empty());
}
#[test]
fn test_find_best_match() {
let catalog = X86SelDAGDeep::new();
let result = catalog.find_best_match(
DAGPatternCategory::ScalarArith,
&[MVT::i32, MVT::i32],
None,
);
assert!(result.is_some());
let p = result.unwrap();
assert_eq!(p.name, "add_i32_rr");
}
#[test]
fn test_find_folded_load_match() {
let catalog = X86SelDAGDeep::new();
let result = catalog.find_best_match(
DAGPatternCategory::ScalarArith,
&[MVT::i32, MVT::i32],
Some(true),
);
assert!(result.is_some());
let p = result.unwrap();
assert!(p.has_folded_load);
}
#[test]
fn test_all_patterns_have_unique_names() {
let catalog = X86SelDAGDeep::new();
let mut names = std::collections::HashSet::new();
for p in &catalog.patterns {
assert!(
names.insert(&p.name),
"Duplicate pattern name: {}",
p.name
);
}
}
#[test]
fn test_branch_patterns() {
let catalog = X86SelDAGDeep::new();
let branches = catalog.patterns_by_category(DAGPatternCategory::Branch);
assert!(branches.len() >= 8, "Expected at least 8 branch patterns");
}
#[test]
fn test_fp_patterns() {
let catalog = X86SelDAGDeep::new();
let fp_patterns = catalog.patterns_by_category(DAGPatternCategory::ScalarFP);
assert!(fp_patterns.len() >= 8, "Expected at least 8 scalar FP patterns");
}
#[test]
fn test_vector_patterns() {
let catalog = X86SelDAGDeep::new();
let vec_patterns = catalog.patterns_by_category(DAGPatternCategory::VectorArith);
assert!(vec_patterns.len() >= 10, "Expected at least 10 vector patterns");
}
#[test]
fn test_special_patterns_exist() {
let catalog = X86SelDAGDeep::new();
assert!(catalog.lookup_name("tls_fs_base").is_some());
assert!(catalog.lookup_name("stack_protector_load").is_some());
assert!(catalog.lookup_name("eh_landing_pad").is_some());
assert!(catalog.lookup_name("patchpoint").is_some());
assert!(catalog.lookup_name("va_start_sysv").is_some());
}
#[test]
fn test_conversion_patterns() {
let catalog = X86SelDAGDeep::new();
assert!(catalog.lookup_name("cvtsi2ss_i32").is_some());
assert!(catalog.lookup_name("cvtsi2sd_i32").is_some());
assert!(catalog.lookup_name("cvttss2si_i32").is_some());
assert!(catalog.lookup_name("cvtss2sd").is_some());
}
#[test]
fn test_complexity_ordering() {
let catalog = X86SelDAGDeep::new();
let add_rr = catalog.lookup_name("add_i32_rr").unwrap();
let add_rm = catalog.lookup_name("add_i32_rm").unwrap();
assert!(add_rm.complexity > add_rr.complexity);
}
}