use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum VectorWidth {
V64,
V128,
V256,
V512,
}
impl VectorWidth {
pub fn bytes(self) -> usize {
match self {
VectorWidth::V64 => 8,
VectorWidth::V128 => 16,
VectorWidth::V256 => 32,
VectorWidth::V512 => 64,
}
}
pub fn bits(self) -> usize {
self.bytes() * 8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ShuffleElementType {
U8,
U16,
U32,
U64,
F32,
F64,
}
impl ShuffleElementType {
pub fn bits(self) -> usize {
match self {
ShuffleElementType::U8 => 8,
ShuffleElementType::U16 => 16,
ShuffleElementType::U32 => 32,
ShuffleElementType::U64 => 64,
ShuffleElementType::F32 => 32,
ShuffleElementType::F64 => 64,
}
}
pub fn bytes(self) -> usize {
self.bits() / 8
}
pub fn is_float(self) -> bool {
matches!(self, ShuffleElementType::F32 | ShuffleElementType::F64)
}
pub fn is_integer(self) -> bool {
!self.is_float()
}
}
impl fmt::Display for ShuffleElementType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ShuffleElementType::U8 => write!(f, "i8"),
ShuffleElementType::U16 => write!(f, "i16"),
ShuffleElementType::U32 => write!(f, "i32"),
ShuffleElementType::U64 => write!(f, "i64"),
ShuffleElementType::F32 => write!(f, "f32"),
ShuffleElementType::F64 => write!(f, "f64"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ShuffleClass {
Broadcast,
Reverse,
InterleaveLow,
InterleaveHigh,
Deinterleave,
Blend,
Permute,
TwoSourcePermute,
Extract,
Insert,
Align,
LaneCrossing,
MaskedPermute,
CompressExpand,
Pack,
Unpack,
}
impl fmt::Display for ShuffleClass {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ShuffleClass::Broadcast => write!(f, "broadcast"),
ShuffleClass::Reverse => write!(f, "reverse"),
ShuffleClass::InterleaveLow => write!(f, "interleave-low"),
ShuffleClass::InterleaveHigh => write!(f, "interleave-high"),
ShuffleClass::Deinterleave => write!(f, "deinterleave"),
ShuffleClass::Blend => write!(f, "blend"),
ShuffleClass::Permute => write!(f, "permute"),
ShuffleClass::TwoSourcePermute => write!(f, "2src-permute"),
ShuffleClass::Extract => write!(f, "extract"),
ShuffleClass::Insert => write!(f, "insert"),
ShuffleClass::Align => write!(f, "align"),
ShuffleClass::LaneCrossing => write!(f, "lane-crossing"),
ShuffleClass::MaskedPermute => write!(f, "masked-permute"),
ShuffleClass::CompressExpand => write!(f, "compress-expand"),
ShuffleClass::Pack => write!(f, "pack"),
ShuffleClass::Unpack => write!(f, "unpack"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum IsaLevel {
Mmx,
Sse,
Sse2,
Sse3,
Ssse3,
Sse41,
Sse42,
Avx,
Avx2,
Avx512f,
Avx512bw,
Avx512dq,
Avx512vbmi,
Avx512vbmi2,
Avx512vl,
Avx512fp16,
}
impl fmt::Display for IsaLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IsaLevel::Mmx => write!(f, "MMX"),
IsaLevel::Sse => write!(f, "SSE"),
IsaLevel::Sse2 => write!(f, "SSE2"),
IsaLevel::Sse3 => write!(f, "SSE3"),
IsaLevel::Ssse3 => write!(f, "SSSE3"),
IsaLevel::Sse41 => write!(f, "SSE4.1"),
IsaLevel::Sse42 => write!(f, "SSE4.2"),
IsaLevel::Avx => write!(f, "AVX"),
IsaLevel::Avx2 => write!(f, "AVX2"),
IsaLevel::Avx512f => write!(f, "AVX-512F"),
IsaLevel::Avx512bw => write!(f, "AVX-512BW"),
IsaLevel::Avx512dq => write!(f, "AVX-512DQ"),
IsaLevel::Avx512vbmi => write!(f, "AVX-512VBMI"),
IsaLevel::Avx512vbmi2 => write!(f, "AVX-512VBMI2"),
IsaLevel::Avx512vl => write!(f, "AVX-512VL"),
IsaLevel::Avx512fp16 => write!(f, "AVX-512FP16"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ShuffleMask {
Immediate8(u8),
ImmediateWord([u8; 8]),
RegisterMask,
OpMask { mask: u8 },
MaskedOpMask { mask: u8, zeroing: bool },
None,
}
impl Default for ShuffleMask {
fn default() -> Self {
ShuffleMask::None
}
}
impl ShuffleMask {
pub fn is_immediate(&self) -> bool {
matches!(
self,
ShuffleMask::Immediate8(_) | ShuffleMask::ImmediateWord(_)
)
}
pub fn is_opmask(&self) -> bool {
matches!(
self,
ShuffleMask::OpMask { .. } | ShuffleMask::MaskedOpMask { .. }
)
}
}
#[derive(Debug, Clone)]
pub struct X86ShufflePattern {
pub mnemonic: String,
pub opcode: u32,
pub description: String,
pub class: ShuffleClass,
pub isa_level: IsaLevel,
pub widths: Vec<VectorWidth>,
pub element_type: ShuffleElementType,
pub num_sources: u8,
pub num_elements: u8,
pub has_memory_form: bool,
pub supports_masking: bool,
pub reads_mask: bool,
pub imm_type: ShuffleImmType,
pub identity_mask: Option<Vec<u8>>,
pub reverse_mask: Option<Vec<u8>>,
pub has_evex_form: bool,
pub upper_behavior: UpperBitsBehavior,
pub latency: u8,
pub throughput: f32,
pub port_mask: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ShuffleImmType {
TwoBitPerElem,
TwoBitSingle,
OneBitPerElem,
FourBitLanePair,
ByteRotate,
Variable,
None,
Immediate8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UpperBitsBehavior {
Zero,
Merge,
Preserve,
Undefined,
}
pub struct X86ShufflePatterns {
patterns: Vec<X86ShufflePattern>,
by_mnemonic: HashMap<String, usize>,
by_class: HashMap<ShuffleClass, Vec<usize>>,
by_width_elem: HashMap<(VectorWidth, ShuffleElementType), Vec<usize>>,
by_isa: HashMap<IsaLevel, Vec<usize>>,
}
impl X86ShufflePatterns {
pub fn new() -> Self {
let mut patterns: Vec<X86ShufflePattern> = Vec::with_capacity(150);
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKLBW".into(),
opcode: 0x0F60,
description: "Unpack low data, interleave bytes into words".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15, });
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKHBW".into(),
opcode: 0x0F68,
description: "Unpack high data, interleave bytes into words".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKLWD".into(),
opcode: 0x0F61,
description: "Unpack low data, interleave words into doublewords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKHWD".into(),
opcode: 0x0F69,
description: "Unpack high data, interleave words into doublewords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKLDQ".into(),
opcode: 0x0F62,
description: "Unpack low data, interleave doublewords into quadwords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKHDQ".into(),
opcode: 0x0F6A,
description: "Unpack high data, interleave doublewords into quadwords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKLQDQ".into(),
opcode: 0x0F6C,
description: "Unpack low data, interleave quadwords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PUNPCKHQDQ".into(),
opcode: 0x0F6D,
description: "Unpack high data, interleave quadwords".into(),
class: ShuffleClass::Unpack,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PSHUFW".into(),
opcode: 0x0F70,
description: "Shuffle packed words in MMX register by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse,
widths: vec![VectorWidth::V64],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]), reverse_mask: Some(vec![0x1B]), has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PSHUFD".into(),
opcode: 0x0F70,
description: "Shuffle packed doublewords by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]), reverse_mask: Some(vec![0x1B]), has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PSHUFHW".into(),
opcode: 0x0F70,
description: "Shuffle high words of packed words by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PSHUFLW".into(),
opcode: 0x0F70,
description: "Shuffle low words of packed words by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "SHUFPS".into(),
opcode: 0x0FC6,
description: "Shuffle packed single-precision values from two sources".into(),
class: ShuffleClass::TwoSourcePermute,
isa_level: IsaLevel::Sse,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem,
identity_mask: Some(vec![0xE4]), reverse_mask: Some(vec![0x1B]),
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "SHUFPD".into(),
opcode: 0x0FC6,
description: "Shuffle packed double-precision values from two sources".into(),
class: ShuffleClass::TwoSourcePermute,
isa_level: IsaLevel::Sse2,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: Some(vec![0x00]),
reverse_mask: Some(vec![0x03]), has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "MOVSHDUP".into(),
opcode: 0x0F16,
description: "Move packed single-precision high and duplicate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse3,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "MOVSLDUP".into(),
opcode: 0x0F12,
description: "Move packed single-precision low and duplicate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Sse3,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "MOVDDUP".into(),
opcode: 0x0F12,
description: "Move one double-precision FP and duplicate".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Sse3,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PSHUFB".into(),
opcode: 0x0F3800,
description: "Packed shuffle bytes using byte mask in second operand".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Ssse3,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: Some((0..16).map(|i| i as u8).collect()),
reverse_mask: Some((0..16).rev().map(|i| i as u8).collect()),
has_evex_form: true, upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PALIGNR".into(),
opcode: 0x0F3A0F,
description: "Packed align right — concatenate two vectors, shift right by N bytes"
.into(),
class: ShuffleClass::Align,
isa_level: IsaLevel::Ssse3,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::ByteRotate,
identity_mask: None,
reverse_mask: None,
has_evex_form: true, upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "BLENDPS".into(),
opcode: 0x0F3A0C,
description: "Blend packed single-precision values by immediate mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem, identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.33,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "BLENDPD".into(),
opcode: 0x0F3A0D,
description: "Blend packed double-precision values by immediate mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.33,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PBLENDW".into(),
opcode: 0x0F3A0E,
description: "Blend packed words by immediate mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PBLENDVB".into(),
opcode: 0x0F3810,
description: "Variable blend packed bytes using XMM0 as mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: true, imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "BLENDVPS".into(),
opcode: 0x0F3814,
description: "Variable blend packed single-precision using XMM0 as mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "BLENDVPD".into(),
opcode: 0x0F3815,
description: "Variable blend packed double-precision using XMM0 as mask".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "INSERTPS".into(),
opcode: 0x0F3A21,
description: "Insert scalar single-precision value into packed single-precision".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "EXTRACTPS".into(),
opcode: 0x0F3A17,
description: "Extract packed single-precision value to register or memory".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 3,
throughput: 1.0,
port_mask: 0x01, });
patterns.push(X86ShufflePattern {
mnemonic: "PINSRB".into(),
opcode: 0x0F3A20,
description: "Insert byte into packed bytes at specified position".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PINSRW".into(),
opcode: 0x0FC4,
description: "Insert word into packed words at specified position".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Sse,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PINSRD".into(),
opcode: 0x0F3A22,
description: "Insert doubleword into packed doublewords at specified position".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PINSRQ".into(),
opcode: 0x0F3A22,
description: "Insert quadword into packed quadwords at specified position".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "PEXTRB".into(),
opcode: 0x0F3A14,
description: "Extract byte from packed bytes".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U8,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "PEXTRW".into(),
opcode: 0x0FC5,
description: "Extract word from packed words".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Sse,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "PEXTRD".into(),
opcode: 0x0F3A16,
description: "Extract doubleword from packed doublewords".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "PEXTRQ".into(),
opcode: 0x0F3A16,
description: "Extract quadword from packed quadwords".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "PACKUSDW".into(),
opcode: 0x0F382B,
description: "Pack doublewords to words with unsigned saturation".into(),
class: ShuffleClass::Pack,
isa_level: IsaLevel::Sse41,
widths: vec![VectorWidth::V128],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Preserve,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFPS".into(),
opcode: 0xC6, description: "AVX shuffle packed single-precision values, 3-operand".into(),
class: ShuffleClass::TwoSourcePermute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 8, has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFPD".into(),
opcode: 0xC6,
description: "AVX shuffle packed double-precision values".into(),
class: ShuffleClass::TwoSourcePermute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 4, has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: Some(vec![0x00]),
reverse_mask: Some(vec![0x0F]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPSHUFD".into(),
opcode: 0x70,
description: "AVX shuffle packed doublewords by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPSHUFHW".into(),
opcode: 0x70,
description: "AVX shuffle high words by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPSHUFLW".into(),
opcode: 0x70,
description: "AVX shuffle low words by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPSimm".into(),
opcode: 0x04,
description: "Permute single-precision floating-point values by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPSvar".into(),
opcode: 0x0C,
description: "Permute single-precision values using variable mask register".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPDimm".into(),
opcode: 0x05,
description: "Permute double-precision floating-point values by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: Some(vec![0x00]),
reverse_mask: Some(vec![0x0F]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPDvar".into(),
opcode: 0x0D,
description: "Permute double-precision values using variable mask register".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERM2F128".into(),
opcode: 0x06,
description: "Permute 128-bit floating-point lanes across two 256-bit sources".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 2, has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x20]), reverse_mask: Some(vec![0x31]), has_evex_form: false,
upper_behavior: UpperBitsBehavior::Zero,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERM2I128".into(),
opcode: 0x46,
description: "Permute 128-bit integer lanes across two 256-bit sources".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x20]),
reverse_mask: Some(vec![0x31]),
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Zero,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMD".into(),
opcode: 0x36,
description: "Permute packed doublewords using index vector".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: Some((0..8).map(|i| i).collect()),
reverse_mask: Some((0..8).rev().map(|i| i).collect()),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMQ".into(),
opcode: 0x36,
description: "Permute packed quadwords using index or immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMPD".into(),
opcode: 0x01,
description: "Permute packed double-precision values by immediate".into(),
class: ShuffleClass::Permute,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPBROADCASTB".into(),
opcode: 0x78,
description: "Broadcast byte element to all positions".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U8,
num_sources: 1,
num_elements: 32,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPBROADCASTW".into(),
opcode: 0x79,
description: "Broadcast word element to all positions".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U16,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPBROADCASTD".into(),
opcode: 0x58,
description: "Broadcast doubleword element to all positions".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPBROADCASTQ".into(),
opcode: 0x59,
description: "Broadcast quadword element to all positions".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VBROADCASTSS".into(),
opcode: 0x18,
description: "Broadcast single-precision scalar to all elements".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VBROADCASTSD".into(),
opcode: 0x19,
description: "Broadcast double-precision scalar to all elements".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VBROADCASTF128".into(),
opcode: 0x1A,
description: "Broadcast 128-bit floating-point lane to both lanes".into(),
class: ShuffleClass::Broadcast,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 2,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: false,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPALIGNR".into(),
opcode: 0x0F,
description: "AVX2 packed align right — concatenate and shift by N bytes".into(),
class: ShuffleClass::Align,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 32,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::ByteRotate,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMDz".into(),
opcode: 0x36,
description: "AVX-512 permute packed doublewords with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: Some((0..16).map(|i| i).collect()),
reverse_mask: Some((0..16).rev().map(|i| i).collect()),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMQz".into(),
opcode: 0x36,
description: "AVX-512 permute packed quadwords with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFF32X4".into(),
opcode: 0x23,
description: "Shuffle 128-bit lanes of packed 32-bit integers with mask".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4, has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x44]), reverse_mask: Some(vec![0x1B]), has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFF64X2".into(),
opcode: 0x23,
description: "Shuffle 128-bit lanes of packed 64-bit values with mask".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x44]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFI32X4".into(),
opcode: 0x43,
description: "Shuffle 128-bit lanes of packed 32-bit integers with mask".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x44]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VSHUFI64X2".into(),
opcode: 0x43,
description: "Shuffle 128-bit lanes of packed 64-bit integers with mask".into(),
class: ShuffleClass::LaneCrossing,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::FourBitLanePair,
identity_mask: Some(vec![0x44]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VALIGND".into(),
opcode: 0x03,
description: "Align packed doublewords by shifting and merging two sources".into(),
class: ShuffleClass::Align,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::ByteRotate,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VALIGNQ".into(),
opcode: 0x03,
description: "Align packed quadwords by shifting and merging two sources".into(),
class: ShuffleClass::Align,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::ByteRotate,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPCOMPRESSD".into(),
opcode: 0x8B,
description: "Compress (store sparse) packed doublewords using opmask".into(),
class: ShuffleClass::CompressExpand,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPEXPANDD".into(),
opcode: 0x89,
description: "Expand (load sparse) packed doublewords using opmask".into(),
class: ShuffleClass::CompressExpand,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPCOMPRESSQ".into(),
opcode: 0x8B,
description: "Compress (store sparse) packed quadwords using opmask".into(),
class: ShuffleClass::CompressExpand,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPEXPANDQ".into(),
opcode: 0x89,
description: "Expand (load sparse) packed quadwords using opmask".into(),
class: ShuffleClass::CompressExpand,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: true,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMW".into(),
opcode: 0x8D,
description: "Permute packed words using index vector with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512bw,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U16,
num_sources: 2,
num_elements: 32,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: Some((0..32).map(|i| i).collect()),
reverse_mask: Some((0..32).rev().map(|i| i).collect()),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMB".into(),
opcode: 0x8D,
description: "Permute packed bytes using index vector with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512vbmi,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U8,
num_sources: 2,
num_elements: 64,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: Some((0..64).map(|i| i).collect()),
reverse_mask: Some((0..64).rev().map(|i| i).collect()),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VINSERTF32X4".into(),
opcode: 0x18,
description: "Insert 128-bit lane of packed single-precision values".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VEXTRACTF32X4".into(),
opcode: 0x19,
description: "Extract 128-bit lane of packed single-precision values".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "VINSERTF64X2".into(),
opcode: 0x18,
description: "Insert 128-bit lane of packed double-precision values".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Avx512dq,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VEXTRACTF64X2".into(),
opcode: 0x19,
description: "Extract 128-bit lane of packed double-precision values".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Avx512dq,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 2,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "VINSERTI32X4".into(),
opcode: 0x38,
description: "Insert 128-bit lane of packed integer doublewords".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VEXTRACTI32X4".into(),
opcode: 0x39,
description: "Extract 128-bit lane of packed integer doublewords".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 1,
num_elements: 4,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "VINSERTI64X2".into(),
opcode: 0x38,
description: "Insert 128-bit lane of packed integer quadwords".into(),
class: ShuffleClass::Insert,
isa_level: IsaLevel::Avx512dq,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 2,
num_elements: 2,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VEXTRACTI64X2".into(),
opcode: 0x39,
description: "Extract 128-bit lane of packed integer quadwords".into(),
class: ShuffleClass::Extract,
isa_level: IsaLevel::Avx512dq,
widths: vec![VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 1,
num_elements: 2,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Immediate8,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x01,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMI2D".into(),
opcode: 0x76,
description: "Permute dwords from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 3, num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMT2D".into(),
opcode: 0x7E,
description: "Permute dwords from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U32,
num_sources: 3,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMI2Q".into(),
opcode: 0x76,
description: "Permute qwords from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 3,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMT2Q".into(),
opcode: 0x7E,
description: "Permute qwords from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U64,
num_sources: 3,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMI2W".into(),
opcode: 0x75,
description: "Permute words from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512bw,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U16,
num_sources: 3,
num_elements: 32,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMT2W".into(),
opcode: 0x7D,
description: "Permute words from two source tables using index and opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512bw,
widths: vec![VectorWidth::V128, VectorWidth::V256, VectorWidth::V512],
element_type: ShuffleElementType::U16,
num_sources: 3,
num_elements: 32,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::Variable,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 3,
throughput: 1.0,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPSz_imm".into(),
opcode: 0x04,
description: "AVX-512 permute single-precision values by immediate with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V512],
element_type: ShuffleElementType::F32,
num_sources: 1,
num_elements: 16,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitSingle,
identity_mask: Some(vec![0xE4]),
reverse_mask: Some(vec![0x1B]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPERMILPDz_imm".into(),
opcode: 0x05,
description: "AVX-512 permute double-precision values by immediate with opmask".into(),
class: ShuffleClass::MaskedPermute,
isa_level: IsaLevel::Avx512f,
widths: vec![VectorWidth::V512],
element_type: ShuffleElementType::F64,
num_sources: 1,
num_elements: 8,
has_memory_form: true,
supports_masking: true,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: Some(vec![0x00]),
reverse_mask: Some(vec![0xFF]),
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Merge,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VUNPCKLPS".into(),
opcode: 0x14,
description: "Unpack and interleave low single-precision values, 3-operand".into(),
class: ShuffleClass::InterleaveLow,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VUNPCKHPS".into(),
opcode: 0x15,
description: "Unpack and interleave high single-precision values, 3-operand".into(),
class: ShuffleClass::InterleaveHigh,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VUNPCKLPD".into(),
opcode: 0x14,
description: "Unpack and interleave low double-precision values, 3-operand".into(),
class: ShuffleClass::InterleaveLow,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VUNPCKHPD".into(),
opcode: 0x15,
description: "Unpack and interleave high double-precision values, 3-operand".into(),
class: ShuffleClass::InterleaveHigh,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::None,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.5,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VBLENDPS".into(),
opcode: 0x0C,
description: "AVX blend packed single-precision by immediate, 3-operand".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.33,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VBLENDPD".into(),
opcode: 0x0D,
description: "AVX blend packed double-precision by immediate, 3-operand".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Avx,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::F64,
num_sources: 2,
num_elements: 4,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::OneBitPerElem,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.33,
port_mask: 0x15,
});
patterns.push(X86ShufflePattern {
mnemonic: "VPBLENDD".into(),
opcode: 0x02,
description: "Blend packed doublewords by immediate, 3-operand".into(),
class: ShuffleClass::Blend,
isa_level: IsaLevel::Avx2,
widths: vec![VectorWidth::V128, VectorWidth::V256],
element_type: ShuffleElementType::U32,
num_sources: 2,
num_elements: 8,
has_memory_form: true,
supports_masking: false,
reads_mask: false,
imm_type: ShuffleImmType::TwoBitPerElem,
identity_mask: None,
reverse_mask: None,
has_evex_form: true,
upper_behavior: UpperBitsBehavior::Zero,
latency: 1,
throughput: 0.33,
port_mask: 0x15,
});
let mut by_mnemonic = HashMap::with_capacity(patterns.len());
let mut by_class: HashMap<ShuffleClass, Vec<usize>> = HashMap::new();
let mut by_width_elem: HashMap<(VectorWidth, ShuffleElementType), Vec<usize>> =
HashMap::new();
let mut by_isa: HashMap<IsaLevel, Vec<usize>> = HashMap::new();
for (i, p) in patterns.iter().enumerate() {
by_mnemonic.insert(p.mnemonic.clone(), i);
by_class.entry(p.class).or_default().push(i);
by_isa.entry(p.isa_level).or_default().push(i);
for &w in &p.widths {
by_width_elem
.entry((w, p.element_type))
.or_default()
.push(i);
}
}
X86ShufflePatterns {
patterns,
by_mnemonic,
by_class,
by_width_elem,
by_isa,
}
}
pub fn len(&self) -> usize {
self.patterns.len()
}
pub fn is_empty(&self) -> bool {
self.patterns.is_empty()
}
pub fn lookup_mnemonic(&self, mnemonic: &str) -> Option<&X86ShufflePattern> {
self.by_mnemonic.get(mnemonic).map(|&i| &self.patterns[i])
}
pub fn patterns_by_class(&self, class: ShuffleClass) -> &[usize] {
self.by_class
.get(&class)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn patterns_by_isa(&self, isa: IsaLevel) -> &[usize] {
self.by_isa.get(&isa).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn patterns_by_width_elem(&self, width: VectorWidth, elem: ShuffleElementType) -> &[usize] {
self.by_width_elem
.get(&(width, elem))
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn get(&self, index: usize) -> Option<&X86ShufflePattern> {
self.patterns.get(index)
}
pub fn iter(&self) -> impl Iterator<Item = &X86ShufflePattern> {
self.patterns.iter()
}
pub fn identity_imm(&self, mnemonic: &str) -> Option<u8> {
self.lookup_mnemonic(mnemonic)
.and_then(|p| p.identity_mask.as_ref())
.and_then(|v| v.first().copied())
}
pub fn reverse_imm(&self, mnemonic: &str) -> Option<u8> {
self.lookup_mnemonic(mnemonic)
.and_then(|p| p.reverse_mask.as_ref())
.and_then(|v| v.first().copied())
}
}
impl Default for X86ShufflePatterns {
fn default() -> Self {
Self::new()
}
}
pub struct ShuffleMaskEncoder;
impl ShuffleMaskEncoder {
pub fn encode_pshufd(sel0: u8, sel1: u8, sel2: u8, sel3: u8) -> u8 {
((sel3 & 0x3) << 6) | ((sel2 & 0x3) << 4) | ((sel1 & 0x3) << 2) | (sel0 & 0x3)
}
pub fn decode_pshufd(imm: u8) -> [u8; 4] {
[
imm & 0x3,
(imm >> 2) & 0x3,
(imm >> 4) & 0x3,
(imm >> 6) & 0x3,
]
}
pub fn encode_shufps(dst0_src: u8, dst1_src: u8, dst2_src: u8, dst3_src: u8) -> u8 {
((dst3_src & 0x3) << 6)
| ((dst2_src & 0x3) << 4)
| ((dst1_src & 0x3) << 2)
| (dst0_src & 0x3)
}
pub fn decode_shufps(imm: u8) -> [u8; 4] {
[
imm & 0x3,
(imm >> 2) & 0x3,
(imm >> 4) & 0x3,
(imm >> 6) & 0x3,
]
}
pub fn encode_shufpd(dst0_src: bool, dst1_src: bool) -> u8 {
((dst1_src as u8) << 1) | (dst0_src as u8)
}
pub fn decode_shufpd(imm: u8) -> [bool; 2] {
[(imm & 0x1) != 0, ((imm >> 1) & 0x1) != 0]
}
pub fn encode_palignr(shift_bytes: u8) -> u8 {
shift_bytes & 0x1F
}
pub fn encode_vperm2f128(dst0: u8, dst1: u8) -> u8 {
((dst1 & 0x3) << 2) | (dst0 & 0x3)
}
pub fn decode_vperm2f128(imm: u8) -> [u8; 2] {
[imm & 0x3, (imm >> 2) & 0x3]
}
pub fn encode_vshuff32x4(dst0: u8, dst1: u8, dst2: u8, dst3: u8) -> u8 {
((dst3 & 0x3) << 6) | ((dst2 & 0x3) << 4) | ((dst1 & 0x3) << 2) | (dst0 & 0x3)
}
pub fn decode_vshuff32x4(imm: u8) -> [u8; 4] {
[
imm & 0x3,
(imm >> 2) & 0x3,
(imm >> 4) & 0x3,
(imm >> 6) & 0x3,
]
}
pub fn encode_vpermq(sel0: u8, sel1: u8, sel2: u8, sel3: u8) -> u8 {
Self::encode_pshufd(sel0, sel1, sel2, sel3)
}
pub fn decode_vpermq(imm: u8) -> [u8; 4] {
Self::decode_pshufd(imm)
}
pub fn encode_blend_imm(num_elements: u8, selections: &[bool]) -> u8 {
let mut imm = 0u8;
for (i, &sel) in selections.iter().enumerate() {
if sel {
imm |= 1 << i;
}
}
imm & ((1u8 << num_elements) - 1)
}
pub fn decode_blend_imm(imm: u8, num_elements: u8) -> Vec<bool> {
(0..num_elements).map(|i| (imm >> i) & 1 != 0).collect()
}
pub fn identity_imm(mnemonic: &str) -> Option<u8> {
let catalog = X86ShufflePatterns::new();
catalog.identity_imm(mnemonic)
}
pub fn reverse_imm(mnemonic: &str) -> Option<u8> {
let catalog = X86ShufflePatterns::new();
catalog.reverse_imm(mnemonic)
}
}
#[derive(Debug, Clone)]
pub struct LegalizedShuffle {
pub sequence: Vec<ShuffleStep>,
pub was_lowered: bool,
}
#[derive(Debug, Clone)]
pub struct ShuffleStep {
pub mnemonic: String,
pub imm: Option<u8>,
pub mask: Option<Vec<u8>>,
}
pub struct ShuffleLegalizer;
impl ShuffleLegalizer {
pub fn is_native(pattern: &X86ShufflePattern, width: VectorWidth) -> bool {
pattern.widths.contains(&width)
}
pub fn legalize(
catalog: &X86ShufflePatterns,
mnemonic: &str,
imm: Option<u8>,
from_width: VectorWidth,
to_width: VectorWidth,
) -> Option<LegalizedShuffle> {
let pattern = catalog.lookup_mnemonic(mnemonic)?;
if Self::is_native(pattern, to_width) {
return Some(LegalizedShuffle {
sequence: vec![ShuffleStep {
mnemonic: mnemonic.to_string(),
imm,
mask: None,
}],
was_lowered: false,
});
}
let supported_widths: Vec<VectorWidth> = pattern
.widths
.iter()
.filter(|&&w| w < from_width)
.copied()
.collect();
if supported_widths.is_empty() {
return None; }
let sub_width = *supported_widths.last().unwrap();
let num_lanes = from_width.bytes() / sub_width.bytes();
let mut sequence = Vec::with_capacity(num_lanes);
for _ in 0..num_lanes {
sequence.push(ShuffleStep {
mnemonic: mnemonic.to_string(),
imm,
mask: None,
});
}
Some(LegalizedShuffle {
sequence,
was_lowered: true,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_catalog_size() {
let catalog = X86ShufflePatterns::new();
assert!(catalog.len() >= 80, "Expected at least 80 shuffle patterns");
}
#[test]
fn test_lookup_by_mnemonic() {
let catalog = X86ShufflePatterns::new();
let p = catalog.lookup_mnemonic("PSHUFD");
assert!(p.is_some());
let p = p.unwrap();
assert_eq!(p.class, ShuffleClass::Permute);
assert_eq!(p.element_type, ShuffleElementType::U32);
assert_eq!(p.num_elements, 4);
}
#[test]
fn test_class_lookup() {
let catalog = X86ShufflePatterns::new();
let broadcast_indices = catalog.patterns_by_class(ShuffleClass::Broadcast);
assert!(!broadcast_indices.is_empty(), "Expected broadcast patterns");
}
#[test]
fn test_isa_lookup() {
let catalog = X86ShufflePatterns::new();
let avx512_patterns = catalog.patterns_by_isa(IsaLevel::Avx512f);
assert!(!avx512_patterns.is_empty(), "Expected AVX-512F patterns");
}
#[test]
fn test_width_elem_lookup() {
let catalog = X86ShufflePatterns::new();
let patterns = catalog.patterns_by_width_elem(VectorWidth::V128, ShuffleElementType::U32);
assert!(!patterns.is_empty(), "Expected 128-bit i32 patterns");
}
#[test]
fn test_encode_pshufd_identity() {
let imm = ShuffleMaskEncoder::encode_pshufd(0, 1, 2, 3);
assert_eq!(imm, 0xE4);
let decoded = ShuffleMaskEncoder::decode_pshufd(imm);
assert_eq!(decoded, [0, 1, 2, 3]);
}
#[test]
fn test_encode_pshufd_reverse() {
let imm = ShuffleMaskEncoder::encode_pshufd(3, 2, 1, 0);
assert_eq!(imm, 0x1B);
let decoded = ShuffleMaskEncoder::decode_pshufd(imm);
assert_eq!(decoded, [3, 2, 1, 0]);
}
#[test]
fn test_encode_shufps_identity() {
let imm = ShuffleMaskEncoder::encode_shufps(0, 1, 2, 3);
assert_eq!(imm, 0xE4);
}
#[test]
fn test_encode_shufpd() {
let imm = ShuffleMaskEncoder::encode_shufpd(false, true);
assert_eq!(imm, 0x02);
let decoded = ShuffleMaskEncoder::decode_shufpd(imm);
assert_eq!(decoded, [false, true]);
}
#[test]
fn test_encode_palignr() {
let imm = ShuffleMaskEncoder::encode_palignr(8);
assert_eq!(imm, 8);
}
#[test]
fn test_encode_vperm2f128() {
let imm = ShuffleMaskEncoder::encode_vperm2f128(0x2, 0x0);
assert_eq!(imm, 0x02);
let decoded = ShuffleMaskEncoder::decode_vperm2f128(imm);
assert_eq!(decoded, [0x2, 0x0]);
}
#[test]
fn test_encode_vshuff32x4() {
let imm = ShuffleMaskEncoder::encode_vshuff32x4(0, 1, 2, 3);
assert_eq!(imm, 0xE4);
let decoded = ShuffleMaskEncoder::decode_vshuff32x4(imm);
assert_eq!(decoded, [0, 1, 2, 3]);
}
#[test]
fn test_encode_blend_imm() {
let imm = ShuffleMaskEncoder::encode_blend_imm(4, &[true, false, true, false]);
assert_eq!(imm, 0x05); let decoded = ShuffleMaskEncoder::decode_blend_imm(imm, 4);
assert_eq!(decoded, vec![true, false, true, false]);
}
#[test]
fn test_identity_immediates() {
let catalog = X86ShufflePatterns::new();
let imm = catalog.identity_imm("PSHUFD");
assert_eq!(imm, Some(0xE4));
}
#[test]
fn test_reverse_immediates() {
let catalog = X86ShufflePatterns::new();
let imm = catalog.reverse_imm("PSHUFD");
assert_eq!(imm, Some(0x1B));
}
#[test]
fn test_legalize_native() {
let catalog = X86ShufflePatterns::new();
let result = ShuffleLegalizer::legalize(
&catalog,
"PSHUFD",
Some(0xE4),
VectorWidth::V128,
VectorWidth::V128,
);
assert!(result.is_some());
let legal = result.unwrap();
assert!(!legal.was_lowered);
assert_eq!(legal.sequence.len(), 1);
}
#[test]
fn test_vector_width_bytes() {
assert_eq!(VectorWidth::V64.bytes(), 8);
assert_eq!(VectorWidth::V128.bytes(), 16);
assert_eq!(VectorWidth::V256.bytes(), 32);
assert_eq!(VectorWidth::V512.bytes(), 64);
}
#[test]
fn test_shuffle_element_type() {
assert_eq!(ShuffleElementType::U8.bits(), 8);
assert_eq!(ShuffleElementType::U16.bits(), 16);
assert_eq!(ShuffleElementType::U32.bits(), 32);
assert_eq!(ShuffleElementType::U64.bits(), 64);
assert_eq!(ShuffleElementType::F32.bits(), 32);
assert_eq!(ShuffleElementType::F64.bits(), 64);
assert!(ShuffleElementType::F32.is_float());
assert!(!ShuffleElementType::U32.is_float());
}
#[test]
fn test_shuffle_mask_default() {
let mask = ShuffleMask::default();
assert_eq!(mask, ShuffleMask::None);
}
#[test]
fn test_eq_for_isa_level() {
assert_eq!(IsaLevel::Avx, IsaLevel::Avx);
assert_ne!(IsaLevel::Avx, IsaLevel::Avx2);
}
#[test]
fn test_eq_for_shuffle_class() {
assert_eq!(ShuffleClass::Broadcast, ShuffleClass::Broadcast);
assert_ne!(ShuffleClass::Broadcast, ShuffleClass::Permute);
}
#[test]
fn test_all_mnemonics_unique() {
let catalog = X86ShufflePatterns::new();
let mut seen = std::collections::HashSet::new();
for p in &catalog.patterns {
assert!(
seen.insert(&p.mnemonic),
"Duplicate mnemonic: {}",
p.mnemonic
);
}
}
#[test]
fn test_class_display() {
assert_eq!(format!("{}", ShuffleClass::Broadcast), "broadcast");
assert_eq!(format!("{}", ShuffleClass::Permute), "permute");
}
#[test]
fn test_isa_display() {
assert_eq!(format!("{}", IsaLevel::Avx), "AVX");
assert_eq!(format!("{}", IsaLevel::Avx512f), "AVX-512F");
}
}