use super::regs::{self};
use super::EmitState;
use crate::ir::condcodes::{FloatCC, IntCC};
use crate::ir::types::*;
use crate::ir::MemFlags;
use crate::isa::x64::inst::regs::pretty_print_reg;
use crate::isa::x64::inst::Inst;
use crate::machinst::*;
use smallvec::{smallvec, SmallVec};
use std::fmt;
use std::string::String;
pub use crate::isa::x64::lower::isle::generated_code::DivSignedness;
pub trait ToWritableReg {
fn to_writable_reg(&self) -> Writable<Reg>;
}
pub trait FromWritableReg: Sized {
fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
}
macro_rules! newtype_of_reg {
(
$newtype_reg:ident,
$newtype_writable_reg:ident,
$newtype_option_writable_reg:ident,
reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*),
reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*),
$newtype_imm8_reg:ident,
|$check_reg:ident| $check:expr
) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $newtype_reg(Reg);
impl PartialEq<Reg> for $newtype_reg {
fn eq(&self, other: &Reg) -> bool {
self.0 == *other
}
}
impl From<$newtype_reg> for Reg {
fn from(r: $newtype_reg) -> Self {
r.0
}
}
impl $newtype_reg {
pub fn new($check_reg: Reg) -> Option<Self> {
if $check {
Some(Self($check_reg))
} else {
None
}
}
pub fn unwrap_new($check_reg: Reg) -> Self {
if $check {
Self($check_reg)
} else {
panic!(
"cannot construct {} from register {:?} with register class {:?}",
stringify!($newtype_reg),
$check_reg,
$check_reg.class(),
)
}
}
pub fn to_reg(self) -> Reg {
self.0
}
}
impl std::ops::Deref for $newtype_reg {
type Target = Reg;
fn deref(&self) -> &Reg {
&self.0
}
}
impl AsMut<Reg> for $newtype_reg {
fn as_mut(&mut self) -> &mut Reg {
&mut self.0
}
}
pub type $newtype_writable_reg = Writable<$newtype_reg>;
#[allow(dead_code)] pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>;
impl ToWritableReg for $newtype_writable_reg {
fn to_writable_reg(&self) -> Writable<Reg> {
Writable::from_reg(self.to_reg().to_reg())
}
}
impl FromWritableReg for $newtype_writable_reg {
fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
}
}
$(
#[derive(Clone, Debug)]
pub struct $newtype_reg_mem(RegMem);
impl From<$newtype_reg_mem> for RegMem {
fn from(rm: $newtype_reg_mem) -> Self {
rm.0
}
}
impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem {
fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem {
&rm.0
}
}
impl From<$newtype_reg> for $newtype_reg_mem {
fn from(r: $newtype_reg) -> Self {
$newtype_reg_mem(RegMem::reg(r.into()))
}
}
impl $newtype_reg_mem {
pub fn new(rm: RegMem) -> Option<Self> {
match rm {
RegMem::Mem { addr } => {
let mut _allow = true;
$(
if $aligned {
_allow = addr.aligned();
}
)?
if _allow {
Some(Self(RegMem::Mem { addr }))
} else {
None
}
}
RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
}
}
pub fn unwrap_new(rm: RegMem) -> Self {
match rm {
RegMem::Mem { addr } => {
$(
if $aligned && !addr.aligned() {
panic!(
"cannot create {} from an unaligned memory address: {addr:?}",
stringify!($newtype_reg_mem),
);
}
)?
Self(RegMem::Mem { addr })
}
RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
}
}
pub fn to_reg_mem(self) -> RegMem {
self.0
}
#[allow(dead_code)] pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
self.0.get_operands(collector);
}
}
impl PrettyPrint for $newtype_reg_mem {
fn pretty_print(&self, size: u8) -> String {
self.0.pretty_print(size)
}
}
)*
$(
#[derive(Clone, Debug)]
pub struct $newtype_reg_mem_imm(RegMemImm);
impl From<$newtype_reg_mem_imm> for RegMemImm {
fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
rmi.0
}
}
impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm {
fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm {
&rmi.0
}
}
impl From<$newtype_reg> for $newtype_reg_mem_imm {
fn from(r: $newtype_reg) -> Self {
$newtype_reg_mem_imm(RegMemImm::reg(r.into()))
}
}
impl $newtype_reg_mem_imm {
pub fn new(rmi: RegMemImm) -> Option<Self> {
match rmi {
RegMemImm::Imm { .. } => Some(Self(rmi)),
RegMemImm::Mem { addr } => {
let mut _allow = true;
$(
if $aligned_imm {
_allow = addr.aligned();
}
)?
if _allow {
Some(Self(RegMemImm::Mem { addr }))
} else {
None
}
}
RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
}
}
pub fn unwrap_new(rmi: RegMemImm) -> Self {
match rmi {
RegMemImm::Imm { .. } => Self(rmi),
RegMemImm::Mem { addr } => {
$(
if $aligned_imm && !addr.aligned() {
panic!(
"cannot construct {} from unaligned memory address: {:?}",
stringify!($newtype_reg_mem_imm),
addr,
);
}
)?
Self(RegMemImm::Mem { addr })
}
RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
}
}
#[allow(dead_code)] pub fn to_reg_mem_imm(self) -> RegMemImm {
self.0
}
#[allow(dead_code)] pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
self.0.get_operands(collector);
}
}
impl PrettyPrint for $newtype_reg_mem_imm {
fn pretty_print(&self, size: u8) -> String {
self.0.pretty_print(size)
}
}
)*
#[derive(Clone, Debug)]
#[allow(dead_code)] pub struct $newtype_imm8_reg(Imm8Reg);
impl From<$newtype_reg> for $newtype_imm8_reg {
fn from(r: $newtype_reg) -> Self {
Self(Imm8Reg::Reg { reg: r.to_reg() })
}
}
impl $newtype_imm8_reg {
#[allow(dead_code)] pub fn new(imm8_reg: Imm8Reg) -> Option<Self> {
match imm8_reg {
Imm8Reg::Imm8 { .. } => Some(Self(imm8_reg)),
Imm8Reg::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
}
}
pub fn unwrap_new(imm8_reg: Imm8Reg) -> Self {
match imm8_reg {
Imm8Reg::Imm8 { .. } => Self(imm8_reg),
Imm8Reg::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
}
}
#[allow(dead_code)] pub fn as_imm8_reg(&self) -> &Imm8Reg {
&self.0
}
#[allow(dead_code)] pub fn as_imm8_reg_mut(&mut self) -> &mut Imm8Reg {
&mut self.0
}
}
};
}
newtype_of_reg!(
Gpr,
WritableGpr,
OptionWritableGpr,
reg_mem: (GprMem),
reg_mem_imm: (GprMemImm),
Imm8Gpr,
|reg| reg.class() == RegClass::Int
);
newtype_of_reg!(
Xmm,
WritableXmm,
OptionWritableXmm,
reg_mem: (XmmMem, XmmMemAligned aligned:true),
reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
Imm8Xmm,
|reg| reg.class() == RegClass::Float
);
pub use crate::isa::x64::lower::isle::generated_code::Amode;
impl Amode {
pub fn imm_reg(simm32: i32, base: Reg) -> Self {
debug_assert!(base.class() == RegClass::Int);
Self::ImmReg {
simm32,
base,
flags: MemFlags::trusted(),
}
}
pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
debug_assert!(base.class() == RegClass::Int);
debug_assert!(index.class() == RegClass::Int);
debug_assert!(shift <= 3);
Self::ImmRegRegShift {
simm32,
base,
index,
shift,
flags: MemFlags::trusted(),
}
}
pub(crate) fn rip_relative(target: MachLabel) -> Self {
Self::RipRelative { target }
}
pub fn with_flags(&self, flags: MemFlags) -> Self {
match self {
&Self::ImmReg { simm32, base, .. } => Self::ImmReg {
simm32,
base,
flags,
},
&Self::ImmRegRegShift {
simm32,
base,
index,
shift,
..
} => Self::ImmRegRegShift {
simm32,
base,
index,
shift,
flags,
},
_ => panic!("Amode {self:?} cannot take memflags"),
}
}
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
match self {
Amode::ImmReg { base, .. } => {
if *base != regs::rbp() && *base != regs::rsp() {
collector.reg_use(base);
}
}
Amode::ImmRegRegShift { base, index, .. } => {
debug_assert_ne!(base.to_reg(), regs::rbp());
debug_assert_ne!(base.to_reg(), regs::rsp());
collector.reg_use(base);
debug_assert_ne!(index.to_reg(), regs::rbp());
debug_assert_ne!(index.to_reg(), regs::rsp());
collector.reg_use(index);
}
Amode::RipRelative { .. } => {
}
}
}
pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
match self {
Amode::ImmReg { base, .. } => {
collector.reg_late_use(base);
}
Amode::ImmRegRegShift { base, index, .. } => {
collector.reg_late_use(base);
collector.reg_late_use(index);
}
Amode::RipRelative { .. } => {
}
}
}
pub(crate) fn get_flags(&self) -> MemFlags {
match self {
Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
Amode::RipRelative { .. } => MemFlags::trusted(),
}
}
pub(crate) fn offset(&self, offset: i32) -> Self {
let mut ret = self.clone();
match &mut ret {
&mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
&mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
_ => panic!("Cannot offset amode: {self:?}"),
}
ret
}
pub(crate) fn aligned(&self) -> bool {
self.get_flags().aligned()
}
}
impl PrettyPrint for Amode {
fn pretty_print(&self, _size: u8) -> String {
match self {
Amode::ImmReg { simm32, base, .. } => {
format!("{}({})", *simm32, pretty_print_reg(*base, 8))
}
Amode::ImmRegRegShift {
simm32,
base,
index,
shift,
..
} => format!(
"{}({},{},{})",
*simm32,
pretty_print_reg(base.to_reg(), 8),
pretty_print_reg(index.to_reg(), 8),
1 << shift
),
Amode::RipRelative { ref target } => format!("label{}(%rip)", target.get()),
}
}
}
#[derive(Clone, Debug)]
pub enum SyntheticAmode {
Real(Amode),
IncomingArg {
offset: u32,
},
SlotOffset {
simm32: i32,
},
ConstantOffset(VCodeConstant),
}
impl SyntheticAmode {
pub fn real(amode: Amode) -> Self {
Self::Real(amode)
}
pub(crate) fn slot_offset(simm32: i32) -> Self {
SyntheticAmode::SlotOffset { simm32 }
}
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
match self {
SyntheticAmode::Real(addr) => addr.get_operands(collector),
SyntheticAmode::IncomingArg { .. } => {
}
SyntheticAmode::SlotOffset { .. } => {
}
SyntheticAmode::ConstantOffset(_) => {}
}
}
pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
match self {
SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
SyntheticAmode::IncomingArg { .. } => {
}
SyntheticAmode::SlotOffset { .. } => {
}
SyntheticAmode::ConstantOffset(_) => {}
}
}
pub(crate) fn finalize(&self, state: &mut EmitState, buffer: &mut MachBuffer<Inst>) -> Amode {
match self {
SyntheticAmode::Real(addr) => addr.clone(),
SyntheticAmode::IncomingArg { offset } => {
let args_max_fp_offset =
state.frame_layout().tail_args_size + state.frame_layout().setup_area_size;
Amode::imm_reg(
i32::try_from(args_max_fp_offset - offset).unwrap(),
regs::rbp(),
)
}
SyntheticAmode::SlotOffset { simm32 } => {
let off = *simm32 as i64 + i64::from(state.frame_layout().outgoing_args_size);
Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
}
SyntheticAmode::ConstantOffset(c) => {
Amode::rip_relative(buffer.get_label_for_constant(*c))
}
}
}
pub(crate) fn aligned(&self) -> bool {
match self {
SyntheticAmode::Real(addr) => addr.aligned(),
&SyntheticAmode::IncomingArg { .. }
| SyntheticAmode::SlotOffset { .. }
| SyntheticAmode::ConstantOffset { .. } => true,
}
}
}
impl Into<SyntheticAmode> for Amode {
fn into(self) -> SyntheticAmode {
SyntheticAmode::Real(self)
}
}
impl Into<SyntheticAmode> for VCodeConstant {
fn into(self) -> SyntheticAmode {
SyntheticAmode::ConstantOffset(self)
}
}
impl PrettyPrint for SyntheticAmode {
fn pretty_print(&self, _size: u8) -> String {
match self {
SyntheticAmode::Real(addr) => addr.pretty_print(8),
&SyntheticAmode::IncomingArg { offset } => {
format!("rbp(stack args max - {offset})")
}
SyntheticAmode::SlotOffset { simm32 } => {
format!("rsp({} + virtual offset)", *simm32)
}
SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
}
}
}
#[derive(Clone, Debug)]
pub enum RegMemImm {
Reg {
reg: Reg,
},
Mem {
addr: SyntheticAmode,
},
Imm {
simm32: u32,
},
}
impl RegMemImm {
pub fn reg(reg: Reg) -> Self {
debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
Self::Reg { reg }
}
pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
Self::Mem { addr: addr.into() }
}
pub fn imm(simm32: u32) -> Self {
Self::Imm { simm32 }
}
pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
if let Self::Reg { reg } = self {
debug_assert_eq!(reg.class(), expected_reg_class);
}
}
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
match self {
Self::Reg { reg } => collector.reg_use(reg),
Self::Mem { addr } => addr.get_operands(collector),
Self::Imm { .. } => {}
}
}
}
impl From<RegMem> for RegMemImm {
fn from(rm: RegMem) -> RegMemImm {
match rm {
RegMem::Reg { reg } => RegMemImm::Reg { reg },
RegMem::Mem { addr } => RegMemImm::Mem { addr },
}
}
}
impl From<Reg> for RegMemImm {
fn from(reg: Reg) -> Self {
RegMemImm::Reg { reg }
}
}
impl PrettyPrint for RegMemImm {
fn pretty_print(&self, size: u8) -> String {
match self {
Self::Reg { reg } => pretty_print_reg(*reg, size),
Self::Mem { addr } => addr.pretty_print(size),
Self::Imm { simm32 } => format!("${}", *simm32 as i32),
}
}
}
#[derive(Clone, Debug)]
pub enum Imm8Reg {
Imm8 {
imm: u8,
},
Reg {
reg: Reg,
},
}
impl From<u8> for Imm8Reg {
fn from(imm: u8) -> Self {
Self::Imm8 { imm }
}
}
impl From<Reg> for Imm8Reg {
fn from(reg: Reg) -> Self {
Self::Reg { reg }
}
}
#[derive(Clone, Debug)]
pub enum RegMem {
Reg {
reg: Reg,
},
Mem {
addr: SyntheticAmode,
},
}
impl RegMem {
pub fn reg(reg: Reg) -> Self {
debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
Self::Reg { reg }
}
pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
Self::Mem { addr: addr.into() }
}
pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
if let Self::Reg { reg } = self {
debug_assert_eq!(reg.class(), expected_reg_class);
}
}
pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
match self {
RegMem::Reg { reg } => collector.reg_use(reg),
RegMem::Mem { addr, .. } => addr.get_operands(collector),
}
}
}
impl From<Reg> for RegMem {
fn from(reg: Reg) -> RegMem {
RegMem::Reg { reg }
}
}
impl From<Writable<Reg>> for RegMem {
fn from(r: Writable<Reg>) -> Self {
RegMem::reg(r.to_reg())
}
}
impl PrettyPrint for RegMem {
fn pretty_print(&self, size: u8) -> String {
match self {
RegMem::Reg { reg } => pretty_print_reg(*reg, size),
RegMem::Mem { addr, .. } => addr.pretty_print(size),
}
}
}
#[derive(Copy, Clone, PartialEq)]
pub enum AluRmiROpcode {
Add,
Adc,
Sub,
Sbb,
And,
Or,
Xor,
}
impl fmt::Debug for AluRmiROpcode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
AluRmiROpcode::Add => "add",
AluRmiROpcode::Adc => "adc",
AluRmiROpcode::Sub => "sub",
AluRmiROpcode::Sbb => "sbb",
AluRmiROpcode::And => "and",
AluRmiROpcode::Or => "or",
AluRmiROpcode::Xor => "xor",
};
write!(fmt, "{name}")
}
}
impl fmt::Display for AluRmiROpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub use crate::isa::x64::lower::isle::generated_code::AluRmROpcode;
impl AluRmROpcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
AluRmROpcode::Andn => smallvec![InstructionSet::BMI1],
AluRmROpcode::Sarx | AluRmROpcode::Shrx | AluRmROpcode::Shlx | AluRmROpcode::Bzhi => {
smallvec![InstructionSet::BMI2]
}
}
}
}
impl fmt::Display for AluRmROpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&format!("{self:?}").to_lowercase())
}
}
#[derive(Clone, PartialEq)]
pub enum UnaryRmROpcode {
Bsr,
Bsf,
Lzcnt,
Tzcnt,
Popcnt,
}
impl UnaryRmROpcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
UnaryRmROpcode::Bsr | UnaryRmROpcode::Bsf => smallvec![],
UnaryRmROpcode::Lzcnt => smallvec![InstructionSet::Lzcnt],
UnaryRmROpcode::Tzcnt => smallvec![InstructionSet::BMI1],
UnaryRmROpcode::Popcnt => smallvec![InstructionSet::Popcnt],
}
}
}
impl fmt::Debug for UnaryRmROpcode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
UnaryRmROpcode::Bsr => write!(fmt, "bsr"),
UnaryRmROpcode::Bsf => write!(fmt, "bsf"),
UnaryRmROpcode::Lzcnt => write!(fmt, "lzcnt"),
UnaryRmROpcode::Tzcnt => write!(fmt, "tzcnt"),
UnaryRmROpcode::Popcnt => write!(fmt, "popcnt"),
}
}
}
impl fmt::Display for UnaryRmROpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub use crate::isa::x64::lower::isle::generated_code::UnaryRmRVexOpcode;
impl UnaryRmRVexOpcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
UnaryRmRVexOpcode::Blsi | UnaryRmRVexOpcode::Blsmsk | UnaryRmRVexOpcode::Blsr => {
smallvec![InstructionSet::BMI1]
}
}
}
}
impl fmt::Display for UnaryRmRVexOpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&format!("{self:?}").to_lowercase())
}
}
pub use crate::isa::x64::lower::isle::generated_code::UnaryRmRImmVexOpcode;
impl UnaryRmRImmVexOpcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
UnaryRmRImmVexOpcode::Rorx => {
smallvec![InstructionSet::BMI2]
}
}
}
}
impl fmt::Display for UnaryRmRImmVexOpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&format!("{self:?}").to_lowercase())
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum CmpOpcode {
Cmp,
Test,
}
#[derive(Debug)]
pub(crate) enum InstructionSet {
SSE,
SSE2,
SSSE3,
SSE41,
SSE42,
Popcnt,
Lzcnt,
BMI1,
#[allow(dead_code)] BMI2,
FMA,
AVX,
AVX2,
AVX512BITALG,
AVX512DQ,
AVX512F,
AVX512VBMI,
AVX512VL,
}
#[derive(Clone, Copy, PartialEq)]
#[allow(dead_code)] #[allow(missing_docs)]
pub enum SseOpcode {
Addps,
Addpd,
Addss,
Addsd,
Andps,
Andpd,
Andnps,
Andnpd,
Blendvpd,
Blendvps,
Comiss,
Comisd,
Cmpps,
Cmppd,
Cmpss,
Cmpsd,
Cvtdq2ps,
Cvtdq2pd,
Cvtpd2ps,
Cvtps2pd,
Cvtsd2ss,
Cvtsd2si,
Cvtsi2ss,
Cvtsi2sd,
Cvtss2si,
Cvtss2sd,
Cvttpd2dq,
Cvttps2dq,
Cvttss2si,
Cvttsd2si,
Divps,
Divpd,
Divss,
Divsd,
Insertps,
Maxps,
Maxpd,
Maxss,
Maxsd,
Minps,
Minpd,
Minss,
Minsd,
Movaps,
Movapd,
Movd,
Movdqa,
Movdqu,
Movlhps,
Movmskps,
Movmskpd,
Movq,
Movss,
Movsd,
Movups,
Movupd,
Mulps,
Mulpd,
Mulss,
Mulsd,
Orps,
Orpd,
Pabsb,
Pabsw,
Pabsd,
Packssdw,
Packsswb,
Packusdw,
Packuswb,
Paddb,
Paddd,
Paddq,
Paddw,
Paddsb,
Paddsw,
Paddusb,
Paddusw,
Palignr,
Pand,
Pandn,
Pavgb,
Pavgw,
Pblendvb,
Pcmpeqb,
Pcmpeqw,
Pcmpeqd,
Pcmpeqq,
Pcmpgtb,
Pcmpgtw,
Pcmpgtd,
Pcmpgtq,
Pextrb,
Pextrw,
Pextrd,
Pextrq,
Pinsrb,
Pinsrw,
Pinsrd,
Pmaddubsw,
Pmaddwd,
Pmaxsb,
Pmaxsw,
Pmaxsd,
Pmaxub,
Pmaxuw,
Pmaxud,
Pminsb,
Pminsw,
Pminsd,
Pminub,
Pminuw,
Pminud,
Pmovmskb,
Pmovsxbd,
Pmovsxbw,
Pmovsxbq,
Pmovsxwd,
Pmovsxwq,
Pmovsxdq,
Pmovzxbd,
Pmovzxbw,
Pmovzxbq,
Pmovzxwd,
Pmovzxwq,
Pmovzxdq,
Pmuldq,
Pmulhw,
Pmulhuw,
Pmulhrsw,
Pmulld,
Pmullw,
Pmuludq,
Por,
Pshufb,
Pshufd,
Psllw,
Pslld,
Psllq,
Psraw,
Psrad,
Psrlw,
Psrld,
Psrlq,
Psubb,
Psubd,
Psubq,
Psubw,
Psubsb,
Psubsw,
Psubusb,
Psubusw,
Ptest,
Punpckhbw,
Punpckhwd,
Punpcklbw,
Punpcklwd,
Pxor,
Rcpss,
Roundps,
Roundpd,
Roundss,
Roundsd,
Rsqrtss,
Shufps,
Sqrtps,
Sqrtpd,
Sqrtss,
Sqrtsd,
Subps,
Subpd,
Subss,
Subsd,
Ucomiss,
Ucomisd,
Unpcklps,
Unpcklpd,
Unpckhps,
Xorps,
Xorpd,
Phaddw,
Phaddd,
Punpckhdq,
Punpckldq,
Punpckhqdq,
Punpcklqdq,
Pshuflw,
Pshufhw,
Pblendw,
Movddup,
}
impl SseOpcode {
pub(crate) fn available_from(&self) -> InstructionSet {
use InstructionSet::*;
match self {
SseOpcode::Addps
| SseOpcode::Addss
| SseOpcode::Andps
| SseOpcode::Andnps
| SseOpcode::Comiss
| SseOpcode::Cmpps
| SseOpcode::Cmpss
| SseOpcode::Cvtsi2ss
| SseOpcode::Cvtss2si
| SseOpcode::Cvttss2si
| SseOpcode::Divps
| SseOpcode::Divss
| SseOpcode::Maxps
| SseOpcode::Maxss
| SseOpcode::Minps
| SseOpcode::Minss
| SseOpcode::Movaps
| SseOpcode::Movlhps
| SseOpcode::Movmskps
| SseOpcode::Movss
| SseOpcode::Movups
| SseOpcode::Mulps
| SseOpcode::Mulss
| SseOpcode::Orps
| SseOpcode::Rcpss
| SseOpcode::Rsqrtss
| SseOpcode::Shufps
| SseOpcode::Sqrtps
| SseOpcode::Sqrtss
| SseOpcode::Subps
| SseOpcode::Subss
| SseOpcode::Ucomiss
| SseOpcode::Unpcklps
| SseOpcode::Unpckhps
| SseOpcode::Xorps => SSE,
SseOpcode::Addpd
| SseOpcode::Addsd
| SseOpcode::Andpd
| SseOpcode::Andnpd
| SseOpcode::Cmppd
| SseOpcode::Cmpsd
| SseOpcode::Comisd
| SseOpcode::Cvtdq2ps
| SseOpcode::Cvtdq2pd
| SseOpcode::Cvtpd2ps
| SseOpcode::Cvtps2pd
| SseOpcode::Cvtsd2ss
| SseOpcode::Cvtsd2si
| SseOpcode::Cvtsi2sd
| SseOpcode::Cvtss2sd
| SseOpcode::Cvttpd2dq
| SseOpcode::Cvttps2dq
| SseOpcode::Cvttsd2si
| SseOpcode::Divpd
| SseOpcode::Divsd
| SseOpcode::Maxpd
| SseOpcode::Maxsd
| SseOpcode::Minpd
| SseOpcode::Minsd
| SseOpcode::Movapd
| SseOpcode::Movd
| SseOpcode::Movmskpd
| SseOpcode::Movq
| SseOpcode::Movsd
| SseOpcode::Movupd
| SseOpcode::Movdqa
| SseOpcode::Movdqu
| SseOpcode::Mulpd
| SseOpcode::Mulsd
| SseOpcode::Orpd
| SseOpcode::Packssdw
| SseOpcode::Packsswb
| SseOpcode::Packuswb
| SseOpcode::Paddb
| SseOpcode::Paddd
| SseOpcode::Paddq
| SseOpcode::Paddw
| SseOpcode::Paddsb
| SseOpcode::Paddsw
| SseOpcode::Paddusb
| SseOpcode::Paddusw
| SseOpcode::Pand
| SseOpcode::Pandn
| SseOpcode::Pavgb
| SseOpcode::Pavgw
| SseOpcode::Pcmpeqb
| SseOpcode::Pcmpeqw
| SseOpcode::Pcmpeqd
| SseOpcode::Pcmpgtb
| SseOpcode::Pcmpgtw
| SseOpcode::Pcmpgtd
| SseOpcode::Pextrw
| SseOpcode::Pinsrw
| SseOpcode::Pmaddwd
| SseOpcode::Pmaxsw
| SseOpcode::Pmaxub
| SseOpcode::Pminsw
| SseOpcode::Pminub
| SseOpcode::Pmovmskb
| SseOpcode::Pmulhw
| SseOpcode::Pmulhuw
| SseOpcode::Pmullw
| SseOpcode::Pmuludq
| SseOpcode::Por
| SseOpcode::Pshufd
| SseOpcode::Psllw
| SseOpcode::Pslld
| SseOpcode::Psllq
| SseOpcode::Psraw
| SseOpcode::Psrad
| SseOpcode::Psrlw
| SseOpcode::Psrld
| SseOpcode::Psrlq
| SseOpcode::Psubb
| SseOpcode::Psubd
| SseOpcode::Psubq
| SseOpcode::Psubw
| SseOpcode::Psubsb
| SseOpcode::Psubsw
| SseOpcode::Psubusb
| SseOpcode::Psubusw
| SseOpcode::Punpckhbw
| SseOpcode::Punpckhwd
| SseOpcode::Punpcklbw
| SseOpcode::Punpcklwd
| SseOpcode::Pxor
| SseOpcode::Sqrtpd
| SseOpcode::Sqrtsd
| SseOpcode::Subpd
| SseOpcode::Subsd
| SseOpcode::Ucomisd
| SseOpcode::Xorpd
| SseOpcode::Punpckldq
| SseOpcode::Punpckhdq
| SseOpcode::Punpcklqdq
| SseOpcode::Punpckhqdq
| SseOpcode::Pshuflw
| SseOpcode::Pshufhw
| SseOpcode::Unpcklpd => SSE2,
SseOpcode::Pabsb
| SseOpcode::Pabsw
| SseOpcode::Pabsd
| SseOpcode::Palignr
| SseOpcode::Pmulhrsw
| SseOpcode::Pshufb
| SseOpcode::Phaddw
| SseOpcode::Phaddd
| SseOpcode::Pmaddubsw
| SseOpcode::Movddup => SSSE3,
SseOpcode::Blendvpd
| SseOpcode::Blendvps
| SseOpcode::Insertps
| SseOpcode::Packusdw
| SseOpcode::Pblendvb
| SseOpcode::Pcmpeqq
| SseOpcode::Pextrb
| SseOpcode::Pextrd
| SseOpcode::Pextrq
| SseOpcode::Pinsrb
| SseOpcode::Pinsrd
| SseOpcode::Pmaxsb
| SseOpcode::Pmaxsd
| SseOpcode::Pmaxuw
| SseOpcode::Pmaxud
| SseOpcode::Pminsb
| SseOpcode::Pminsd
| SseOpcode::Pminuw
| SseOpcode::Pminud
| SseOpcode::Pmovsxbd
| SseOpcode::Pmovsxbw
| SseOpcode::Pmovsxbq
| SseOpcode::Pmovsxwd
| SseOpcode::Pmovsxwq
| SseOpcode::Pmovsxdq
| SseOpcode::Pmovzxbd
| SseOpcode::Pmovzxbw
| SseOpcode::Pmovzxbq
| SseOpcode::Pmovzxwd
| SseOpcode::Pmovzxwq
| SseOpcode::Pmovzxdq
| SseOpcode::Pmuldq
| SseOpcode::Pmulld
| SseOpcode::Ptest
| SseOpcode::Roundps
| SseOpcode::Roundpd
| SseOpcode::Roundss
| SseOpcode::Roundsd
| SseOpcode::Pblendw => SSE41,
SseOpcode::Pcmpgtq => SSE42,
}
}
pub(crate) fn src_size(&self) -> u8 {
match self {
SseOpcode::Movd => 4,
_ => 8,
}
}
pub(crate) fn has_scalar_src2(self) -> bool {
match self {
SseOpcode::Pinsrb | SseOpcode::Pinsrw | SseOpcode::Pinsrd => true,
SseOpcode::Pmovsxbw
| SseOpcode::Pmovsxbd
| SseOpcode::Pmovsxbq
| SseOpcode::Pmovsxwd
| SseOpcode::Pmovsxwq
| SseOpcode::Pmovsxdq => true,
SseOpcode::Pmovzxbw
| SseOpcode::Pmovzxbd
| SseOpcode::Pmovzxbq
| SseOpcode::Pmovzxwd
| SseOpcode::Pmovzxwq
| SseOpcode::Pmovzxdq => true,
_ => false,
}
}
}
impl fmt::Debug for SseOpcode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
SseOpcode::Addps => "addps",
SseOpcode::Addpd => "addpd",
SseOpcode::Addss => "addss",
SseOpcode::Addsd => "addsd",
SseOpcode::Andpd => "andpd",
SseOpcode::Andps => "andps",
SseOpcode::Andnps => "andnps",
SseOpcode::Andnpd => "andnpd",
SseOpcode::Blendvpd => "blendvpd",
SseOpcode::Blendvps => "blendvps",
SseOpcode::Cmpps => "cmpps",
SseOpcode::Cmppd => "cmppd",
SseOpcode::Cmpss => "cmpss",
SseOpcode::Cmpsd => "cmpsd",
SseOpcode::Comiss => "comiss",
SseOpcode::Comisd => "comisd",
SseOpcode::Cvtdq2ps => "cvtdq2ps",
SseOpcode::Cvtdq2pd => "cvtdq2pd",
SseOpcode::Cvtpd2ps => "cvtpd2ps",
SseOpcode::Cvtps2pd => "cvtps2pd",
SseOpcode::Cvtsd2ss => "cvtsd2ss",
SseOpcode::Cvtsd2si => "cvtsd2si",
SseOpcode::Cvtsi2ss => "cvtsi2ss",
SseOpcode::Cvtsi2sd => "cvtsi2sd",
SseOpcode::Cvtss2si => "cvtss2si",
SseOpcode::Cvtss2sd => "cvtss2sd",
SseOpcode::Cvttpd2dq => "cvttpd2dq",
SseOpcode::Cvttps2dq => "cvttps2dq",
SseOpcode::Cvttss2si => "cvttss2si",
SseOpcode::Cvttsd2si => "cvttsd2si",
SseOpcode::Divps => "divps",
SseOpcode::Divpd => "divpd",
SseOpcode::Divss => "divss",
SseOpcode::Divsd => "divsd",
SseOpcode::Insertps => "insertps",
SseOpcode::Maxps => "maxps",
SseOpcode::Maxpd => "maxpd",
SseOpcode::Maxss => "maxss",
SseOpcode::Maxsd => "maxsd",
SseOpcode::Minps => "minps",
SseOpcode::Minpd => "minpd",
SseOpcode::Minss => "minss",
SseOpcode::Minsd => "minsd",
SseOpcode::Movaps => "movaps",
SseOpcode::Movapd => "movapd",
SseOpcode::Movd => "movd",
SseOpcode::Movdqa => "movdqa",
SseOpcode::Movdqu => "movdqu",
SseOpcode::Movlhps => "movlhps",
SseOpcode::Movmskps => "movmskps",
SseOpcode::Movmskpd => "movmskpd",
SseOpcode::Movq => "movq",
SseOpcode::Movss => "movss",
SseOpcode::Movsd => "movsd",
SseOpcode::Movups => "movups",
SseOpcode::Movupd => "movupd",
SseOpcode::Mulps => "mulps",
SseOpcode::Mulpd => "mulpd",
SseOpcode::Mulss => "mulss",
SseOpcode::Mulsd => "mulsd",
SseOpcode::Orpd => "orpd",
SseOpcode::Orps => "orps",
SseOpcode::Pabsb => "pabsb",
SseOpcode::Pabsw => "pabsw",
SseOpcode::Pabsd => "pabsd",
SseOpcode::Packssdw => "packssdw",
SseOpcode::Packsswb => "packsswb",
SseOpcode::Packusdw => "packusdw",
SseOpcode::Packuswb => "packuswb",
SseOpcode::Paddb => "paddb",
SseOpcode::Paddd => "paddd",
SseOpcode::Paddq => "paddq",
SseOpcode::Paddw => "paddw",
SseOpcode::Paddsb => "paddsb",
SseOpcode::Paddsw => "paddsw",
SseOpcode::Paddusb => "paddusb",
SseOpcode::Paddusw => "paddusw",
SseOpcode::Palignr => "palignr",
SseOpcode::Pand => "pand",
SseOpcode::Pandn => "pandn",
SseOpcode::Pavgb => "pavgb",
SseOpcode::Pavgw => "pavgw",
SseOpcode::Pblendvb => "pblendvb",
SseOpcode::Pcmpeqb => "pcmpeqb",
SseOpcode::Pcmpeqw => "pcmpeqw",
SseOpcode::Pcmpeqd => "pcmpeqd",
SseOpcode::Pcmpeqq => "pcmpeqq",
SseOpcode::Pcmpgtb => "pcmpgtb",
SseOpcode::Pcmpgtw => "pcmpgtw",
SseOpcode::Pcmpgtd => "pcmpgtd",
SseOpcode::Pcmpgtq => "pcmpgtq",
SseOpcode::Pextrb => "pextrb",
SseOpcode::Pextrw => "pextrw",
SseOpcode::Pextrd => "pextrd",
SseOpcode::Pextrq => "pextrq",
SseOpcode::Pinsrb => "pinsrb",
SseOpcode::Pinsrw => "pinsrw",
SseOpcode::Pinsrd => "pinsrd",
SseOpcode::Pmaddubsw => "pmaddubsw",
SseOpcode::Pmaddwd => "pmaddwd",
SseOpcode::Pmaxsb => "pmaxsb",
SseOpcode::Pmaxsw => "pmaxsw",
SseOpcode::Pmaxsd => "pmaxsd",
SseOpcode::Pmaxub => "pmaxub",
SseOpcode::Pmaxuw => "pmaxuw",
SseOpcode::Pmaxud => "pmaxud",
SseOpcode::Pminsb => "pminsb",
SseOpcode::Pminsw => "pminsw",
SseOpcode::Pminsd => "pminsd",
SseOpcode::Pminub => "pminub",
SseOpcode::Pminuw => "pminuw",
SseOpcode::Pminud => "pminud",
SseOpcode::Pmovmskb => "pmovmskb",
SseOpcode::Pmovsxbd => "pmovsxbd",
SseOpcode::Pmovsxbw => "pmovsxbw",
SseOpcode::Pmovsxbq => "pmovsxbq",
SseOpcode::Pmovsxwd => "pmovsxwd",
SseOpcode::Pmovsxwq => "pmovsxwq",
SseOpcode::Pmovsxdq => "pmovsxdq",
SseOpcode::Pmovzxbd => "pmovzxbd",
SseOpcode::Pmovzxbw => "pmovzxbw",
SseOpcode::Pmovzxbq => "pmovzxbq",
SseOpcode::Pmovzxwd => "pmovzxwd",
SseOpcode::Pmovzxwq => "pmovzxwq",
SseOpcode::Pmovzxdq => "pmovzxdq",
SseOpcode::Pmuldq => "pmuldq",
SseOpcode::Pmulhw => "pmulhw",
SseOpcode::Pmulhuw => "pmulhuw",
SseOpcode::Pmulhrsw => "pmulhrsw",
SseOpcode::Pmulld => "pmulld",
SseOpcode::Pmullw => "pmullw",
SseOpcode::Pmuludq => "pmuludq",
SseOpcode::Por => "por",
SseOpcode::Pshufb => "pshufb",
SseOpcode::Pshufd => "pshufd",
SseOpcode::Psllw => "psllw",
SseOpcode::Pslld => "pslld",
SseOpcode::Psllq => "psllq",
SseOpcode::Psraw => "psraw",
SseOpcode::Psrad => "psrad",
SseOpcode::Psrlw => "psrlw",
SseOpcode::Psrld => "psrld",
SseOpcode::Psrlq => "psrlq",
SseOpcode::Psubb => "psubb",
SseOpcode::Psubd => "psubd",
SseOpcode::Psubq => "psubq",
SseOpcode::Psubw => "psubw",
SseOpcode::Psubsb => "psubsb",
SseOpcode::Psubsw => "psubsw",
SseOpcode::Psubusb => "psubusb",
SseOpcode::Psubusw => "psubusw",
SseOpcode::Ptest => "ptest",
SseOpcode::Punpckhbw => "punpckhbw",
SseOpcode::Punpckhwd => "punpckhwd",
SseOpcode::Punpcklbw => "punpcklbw",
SseOpcode::Punpcklwd => "punpcklwd",
SseOpcode::Pxor => "pxor",
SseOpcode::Rcpss => "rcpss",
SseOpcode::Roundps => "roundps",
SseOpcode::Roundpd => "roundpd",
SseOpcode::Roundss => "roundss",
SseOpcode::Roundsd => "roundsd",
SseOpcode::Rsqrtss => "rsqrtss",
SseOpcode::Shufps => "shufps",
SseOpcode::Sqrtps => "sqrtps",
SseOpcode::Sqrtpd => "sqrtpd",
SseOpcode::Sqrtss => "sqrtss",
SseOpcode::Sqrtsd => "sqrtsd",
SseOpcode::Subps => "subps",
SseOpcode::Subpd => "subpd",
SseOpcode::Subss => "subss",
SseOpcode::Subsd => "subsd",
SseOpcode::Ucomiss => "ucomiss",
SseOpcode::Ucomisd => "ucomisd",
SseOpcode::Unpcklps => "unpcklps",
SseOpcode::Unpckhps => "unpckhps",
SseOpcode::Xorps => "xorps",
SseOpcode::Xorpd => "xorpd",
SseOpcode::Phaddw => "phaddw",
SseOpcode::Phaddd => "phaddd",
SseOpcode::Punpckldq => "punpckldq",
SseOpcode::Punpckhdq => "punpckhdq",
SseOpcode::Punpcklqdq => "punpcklqdq",
SseOpcode::Punpckhqdq => "punpckhqdq",
SseOpcode::Pshuflw => "pshuflw",
SseOpcode::Pshufhw => "pshufhw",
SseOpcode::Pblendw => "pblendw",
SseOpcode::Movddup => "movddup",
SseOpcode::Unpcklpd => "unpcklpd",
};
write!(fmt, "{name}")
}
}
impl fmt::Display for SseOpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
impl AvxOpcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
AvxOpcode::Vfmadd213ss
| AvxOpcode::Vfmadd213sd
| AvxOpcode::Vfmadd213ps
| AvxOpcode::Vfmadd213pd
| AvxOpcode::Vfmadd132ss
| AvxOpcode::Vfmadd132sd
| AvxOpcode::Vfmadd132ps
| AvxOpcode::Vfmadd132pd
| AvxOpcode::Vfnmadd213ss
| AvxOpcode::Vfnmadd213sd
| AvxOpcode::Vfnmadd213ps
| AvxOpcode::Vfnmadd213pd
| AvxOpcode::Vfnmadd132ss
| AvxOpcode::Vfnmadd132sd
| AvxOpcode::Vfnmadd132ps
| AvxOpcode::Vfnmadd132pd
| AvxOpcode::Vfmsub213ss
| AvxOpcode::Vfmsub213sd
| AvxOpcode::Vfmsub213ps
| AvxOpcode::Vfmsub213pd
| AvxOpcode::Vfmsub132ss
| AvxOpcode::Vfmsub132sd
| AvxOpcode::Vfmsub132ps
| AvxOpcode::Vfmsub132pd
| AvxOpcode::Vfnmsub213ss
| AvxOpcode::Vfnmsub213sd
| AvxOpcode::Vfnmsub213ps
| AvxOpcode::Vfnmsub213pd
| AvxOpcode::Vfnmsub132ss
| AvxOpcode::Vfnmsub132sd
| AvxOpcode::Vfnmsub132ps
| AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA],
AvxOpcode::Vminps
| AvxOpcode::Vminpd
| AvxOpcode::Vmaxps
| AvxOpcode::Vmaxpd
| AvxOpcode::Vandnps
| AvxOpcode::Vandnpd
| AvxOpcode::Vpandn
| AvxOpcode::Vcmpps
| AvxOpcode::Vcmppd
| AvxOpcode::Vpsrlw
| AvxOpcode::Vpsrld
| AvxOpcode::Vpsrlq
| AvxOpcode::Vpaddb
| AvxOpcode::Vpaddw
| AvxOpcode::Vpaddd
| AvxOpcode::Vpaddq
| AvxOpcode::Vpaddsb
| AvxOpcode::Vpaddsw
| AvxOpcode::Vpaddusb
| AvxOpcode::Vpaddusw
| AvxOpcode::Vpsubb
| AvxOpcode::Vpsubw
| AvxOpcode::Vpsubd
| AvxOpcode::Vpsubq
| AvxOpcode::Vpsubsb
| AvxOpcode::Vpsubsw
| AvxOpcode::Vpsubusb
| AvxOpcode::Vpsubusw
| AvxOpcode::Vpavgb
| AvxOpcode::Vpavgw
| AvxOpcode::Vpand
| AvxOpcode::Vandps
| AvxOpcode::Vandpd
| AvxOpcode::Vpor
| AvxOpcode::Vorps
| AvxOpcode::Vorpd
| AvxOpcode::Vpxor
| AvxOpcode::Vxorps
| AvxOpcode::Vxorpd
| AvxOpcode::Vpmullw
| AvxOpcode::Vpmulld
| AvxOpcode::Vpmulhw
| AvxOpcode::Vpmulhd
| AvxOpcode::Vpmulhrsw
| AvxOpcode::Vpmulhuw
| AvxOpcode::Vpmuldq
| AvxOpcode::Vpmuludq
| AvxOpcode::Vpunpckhwd
| AvxOpcode::Vpunpcklwd
| AvxOpcode::Vunpcklps
| AvxOpcode::Vunpckhps
| AvxOpcode::Vaddps
| AvxOpcode::Vaddpd
| AvxOpcode::Vsubps
| AvxOpcode::Vsubpd
| AvxOpcode::Vmulps
| AvxOpcode::Vmulpd
| AvxOpcode::Vdivps
| AvxOpcode::Vdivpd
| AvxOpcode::Vpcmpeqb
| AvxOpcode::Vpcmpeqw
| AvxOpcode::Vpcmpeqd
| AvxOpcode::Vpcmpeqq
| AvxOpcode::Vpcmpgtb
| AvxOpcode::Vpcmpgtw
| AvxOpcode::Vpcmpgtd
| AvxOpcode::Vpcmpgtq
| AvxOpcode::Vblendvps
| AvxOpcode::Vblendvpd
| AvxOpcode::Vpblendvb
| AvxOpcode::Vmovlhps
| AvxOpcode::Vpminsb
| AvxOpcode::Vpminsw
| AvxOpcode::Vpminsd
| AvxOpcode::Vpminub
| AvxOpcode::Vpminuw
| AvxOpcode::Vpminud
| AvxOpcode::Vpmaxsb
| AvxOpcode::Vpmaxsw
| AvxOpcode::Vpmaxsd
| AvxOpcode::Vpmaxub
| AvxOpcode::Vpmaxuw
| AvxOpcode::Vpmaxud
| AvxOpcode::Vpunpcklbw
| AvxOpcode::Vpunpckhbw
| AvxOpcode::Vpacksswb
| AvxOpcode::Vpackssdw
| AvxOpcode::Vpackuswb
| AvxOpcode::Vpackusdw
| AvxOpcode::Vpalignr
| AvxOpcode::Vpinsrb
| AvxOpcode::Vpinsrw
| AvxOpcode::Vpinsrd
| AvxOpcode::Vpinsrq
| AvxOpcode::Vpmaddwd
| AvxOpcode::Vpmaddubsw
| AvxOpcode::Vinsertps
| AvxOpcode::Vpshufb
| AvxOpcode::Vshufps
| AvxOpcode::Vpsllw
| AvxOpcode::Vpslld
| AvxOpcode::Vpsllq
| AvxOpcode::Vpsraw
| AvxOpcode::Vpsrad
| AvxOpcode::Vpmovsxbw
| AvxOpcode::Vpmovzxbw
| AvxOpcode::Vpmovsxwd
| AvxOpcode::Vpmovzxwd
| AvxOpcode::Vpmovsxdq
| AvxOpcode::Vpmovzxdq
| AvxOpcode::Vaddss
| AvxOpcode::Vaddsd
| AvxOpcode::Vmulss
| AvxOpcode::Vmulsd
| AvxOpcode::Vsubss
| AvxOpcode::Vsubsd
| AvxOpcode::Vdivss
| AvxOpcode::Vdivsd
| AvxOpcode::Vpabsb
| AvxOpcode::Vpabsw
| AvxOpcode::Vpabsd
| AvxOpcode::Vminss
| AvxOpcode::Vminsd
| AvxOpcode::Vmaxss
| AvxOpcode::Vmaxsd
| AvxOpcode::Vsqrtps
| AvxOpcode::Vsqrtpd
| AvxOpcode::Vroundpd
| AvxOpcode::Vroundps
| AvxOpcode::Vcvtdq2pd
| AvxOpcode::Vcvtdq2ps
| AvxOpcode::Vcvtpd2ps
| AvxOpcode::Vcvtps2pd
| AvxOpcode::Vcvttpd2dq
| AvxOpcode::Vcvttps2dq
| AvxOpcode::Vphaddw
| AvxOpcode::Vphaddd
| AvxOpcode::Vpunpckldq
| AvxOpcode::Vpunpckhdq
| AvxOpcode::Vpunpcklqdq
| AvxOpcode::Vpunpckhqdq
| AvxOpcode::Vpshuflw
| AvxOpcode::Vpshufhw
| AvxOpcode::Vpshufd
| AvxOpcode::Vmovss
| AvxOpcode::Vmovsd
| AvxOpcode::Vmovups
| AvxOpcode::Vmovupd
| AvxOpcode::Vmovdqu
| AvxOpcode::Vpextrb
| AvxOpcode::Vpextrw
| AvxOpcode::Vpextrd
| AvxOpcode::Vpextrq
| AvxOpcode::Vpblendw
| AvxOpcode::Vmovddup
| AvxOpcode::Vbroadcastss
| AvxOpcode::Vmovd
| AvxOpcode::Vmovq
| AvxOpcode::Vmovmskps
| AvxOpcode::Vmovmskpd
| AvxOpcode::Vpmovmskb
| AvxOpcode::Vcvtsi2ss
| AvxOpcode::Vcvtsi2sd
| AvxOpcode::Vcvtss2sd
| AvxOpcode::Vcvtsd2ss
| AvxOpcode::Vsqrtss
| AvxOpcode::Vsqrtsd
| AvxOpcode::Vroundss
| AvxOpcode::Vroundsd
| AvxOpcode::Vunpcklpd
| AvxOpcode::Vptest
| AvxOpcode::Vucomiss
| AvxOpcode::Vucomisd => {
smallvec![InstructionSet::AVX]
}
AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => {
smallvec![InstructionSet::AVX2]
}
}
}
pub(crate) fn is_commutative(&self) -> bool {
match *self {
AvxOpcode::Vpaddb
| AvxOpcode::Vpaddw
| AvxOpcode::Vpaddd
| AvxOpcode::Vpaddq
| AvxOpcode::Vpaddsb
| AvxOpcode::Vpaddsw
| AvxOpcode::Vpaddusb
| AvxOpcode::Vpaddusw
| AvxOpcode::Vpand
| AvxOpcode::Vandps
| AvxOpcode::Vandpd
| AvxOpcode::Vpor
| AvxOpcode::Vorps
| AvxOpcode::Vorpd
| AvxOpcode::Vpxor
| AvxOpcode::Vxorps
| AvxOpcode::Vxorpd
| AvxOpcode::Vpmuldq
| AvxOpcode::Vpmuludq
| AvxOpcode::Vaddps
| AvxOpcode::Vaddpd
| AvxOpcode::Vmulps
| AvxOpcode::Vmulpd
| AvxOpcode::Vpcmpeqb
| AvxOpcode::Vpcmpeqw
| AvxOpcode::Vpcmpeqd
| AvxOpcode::Vpcmpeqq
| AvxOpcode::Vaddss
| AvxOpcode::Vaddsd
| AvxOpcode::Vmulss
| AvxOpcode::Vmulsd => true,
_ => false,
}
}
}
impl fmt::Display for AvxOpcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format!("{self:?}").to_lowercase().fmt(f)
}
}
#[derive(Copy, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum Avx512TupleType {
Full,
FullMem,
Mem128,
}
pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
impl Avx512Opcode {
pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
match self {
Avx512Opcode::Vcvtudq2ps
| Avx512Opcode::Vpabsq
| Avx512Opcode::Vpsraq
| Avx512Opcode::VpsraqImm => {
smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
}
Avx512Opcode::Vpermi2b => {
smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
}
Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
Avx512Opcode::Vpopcntb => {
smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
}
}
}
pub fn tuple_type(&self) -> Avx512TupleType {
use Avx512Opcode::*;
use Avx512TupleType::*;
match self {
Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
Vpermi2b | Vpopcntb => FullMem,
Vpsraq => Mem128,
}
}
}
impl fmt::Display for Avx512Opcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = format!("{self:?}");
f.write_str(&s.to_lowercase())
}
}
#[allow(dead_code)]
#[derive(Clone, PartialEq)]
pub enum ExtKind {
None,
SignExtend,
ZeroExtend,
}
#[derive(Clone, PartialEq)]
pub enum ExtMode {
BL,
BQ,
WL,
WQ,
LQ,
}
impl ExtMode {
pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
match (from_bits, to_bits) {
(1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
(1, 64) | (8, 64) => Some(ExtMode::BQ),
(16, 32) => Some(ExtMode::WL),
(16, 64) => Some(ExtMode::WQ),
(32, 64) => Some(ExtMode::LQ),
_ => None,
}
}
pub(crate) fn src_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::BQ => 1,
ExtMode::WL | ExtMode::WQ => 2,
ExtMode::LQ => 4,
}
}
pub(crate) fn dst_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::WL => 4,
ExtMode::BQ | ExtMode::WQ | ExtMode::LQ => 8,
}
}
pub(crate) fn src_type(&self) -> Type {
match self {
ExtMode::BL | ExtMode::BQ => I8,
ExtMode::WL | ExtMode::WQ => I16,
ExtMode::LQ => I32,
}
}
}
impl fmt::Debug for ExtMode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
ExtMode::BL => "bl",
ExtMode::BQ => "bq",
ExtMode::WL => "wl",
ExtMode::WQ => "wq",
ExtMode::LQ => "lq",
};
write!(fmt, "{name}")
}
}
impl fmt::Display for ExtMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, Copy)]
pub enum ShiftKind {
ShiftLeft,
ShiftRightLogical,
ShiftRightArithmetic,
RotateLeft,
RotateRight,
}
impl fmt::Debug for ShiftKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
ShiftKind::ShiftLeft => "shl",
ShiftKind::ShiftRightLogical => "shr",
ShiftKind::ShiftRightArithmetic => "sar",
ShiftKind::RotateLeft => "rol",
ShiftKind::RotateRight => "ror",
};
write!(fmt, "{name}")
}
}
impl fmt::Display for ShiftKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum CC {
O = 0,
NO = 1,
B = 2,
NB = 3,
Z = 4,
NZ = 5,
BE = 6,
NBE = 7,
S = 8,
NS = 9,
L = 12,
NL = 13,
LE = 14,
NLE = 15,
P = 10,
NP = 11,
}
impl CC {
pub(crate) fn from_intcc(intcc: IntCC) -> Self {
match intcc {
IntCC::Equal => CC::Z,
IntCC::NotEqual => CC::NZ,
IntCC::SignedGreaterThanOrEqual => CC::NL,
IntCC::SignedGreaterThan => CC::NLE,
IntCC::SignedLessThanOrEqual => CC::LE,
IntCC::SignedLessThan => CC::L,
IntCC::UnsignedGreaterThanOrEqual => CC::NB,
IntCC::UnsignedGreaterThan => CC::NBE,
IntCC::UnsignedLessThanOrEqual => CC::BE,
IntCC::UnsignedLessThan => CC::B,
}
}
pub(crate) fn invert(&self) -> Self {
match self {
CC::O => CC::NO,
CC::NO => CC::O,
CC::B => CC::NB,
CC::NB => CC::B,
CC::Z => CC::NZ,
CC::NZ => CC::Z,
CC::BE => CC::NBE,
CC::NBE => CC::BE,
CC::S => CC::NS,
CC::NS => CC::S,
CC::L => CC::NL,
CC::NL => CC::L,
CC::LE => CC::NLE,
CC::NLE => CC::LE,
CC::P => CC::NP,
CC::NP => CC::P,
}
}
pub(crate) fn get_enc(self) -> u8 {
self as u8
}
}
impl fmt::Debug for CC {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
CC::O => "o",
CC::NO => "no",
CC::B => "b",
CC::NB => "nb",
CC::Z => "z",
CC::NZ => "nz",
CC::BE => "be",
CC::NBE => "nbe",
CC::S => "s",
CC::NS => "ns",
CC::L => "l",
CC::NL => "nl",
CC::LE => "le",
CC::NLE => "nle",
CC::P => "p",
CC::NP => "np",
};
write!(fmt, "{name}")
}
}
impl fmt::Display for CC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, Copy)]
pub enum FcmpImm {
Equal = 0x00,
LessThan = 0x01,
LessThanOrEqual = 0x02,
Unordered = 0x03,
NotEqual = 0x04,
UnorderedOrGreaterThanOrEqual = 0x05,
UnorderedOrGreaterThan = 0x06,
Ordered = 0x07,
}
impl FcmpImm {
pub(crate) fn encode(self) -> u8 {
self as u8
}
}
impl From<FloatCC> for FcmpImm {
fn from(cond: FloatCC) -> Self {
match cond {
FloatCC::Equal => FcmpImm::Equal,
FloatCC::LessThan => FcmpImm::LessThan,
FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
FloatCC::Unordered => FcmpImm::Unordered,
FloatCC::NotEqual => FcmpImm::NotEqual,
FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
FloatCC::Ordered => FcmpImm::Ordered,
_ => panic!("unable to create comparison predicate for {cond}"),
}
}
}
#[derive(Clone, Copy)]
pub enum RoundImm {
RoundNearest = 0x00,
RoundDown = 0x01,
RoundUp = 0x02,
RoundZero = 0x03,
}
impl RoundImm {
pub(crate) fn encode(self) -> u8 {
self as u8
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum OperandSize {
Size8,
Size16,
Size32,
Size64,
}
impl OperandSize {
pub(crate) fn from_bytes(num_bytes: u32) -> Self {
match num_bytes {
1 => OperandSize::Size8,
2 => OperandSize::Size16,
4 => OperandSize::Size32,
8 => OperandSize::Size64,
_ => unreachable!("Invalid OperandSize: {}", num_bytes),
}
}
pub(crate) fn from_ty(ty: Type) -> Self {
Self::from_bytes(ty.lane_type().bytes())
}
pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
sizes.iter().any(|val| *self == *val)
}
pub(crate) fn to_bytes(&self) -> u8 {
match self {
Self::Size8 => 1,
Self::Size16 => 2,
Self::Size32 => 4,
Self::Size64 => 8,
}
}
pub(crate) fn to_bits(&self) -> u8 {
self.to_bytes() * 8
}
pub(crate) fn to_type(&self) -> Type {
match self {
Self::Size8 => I8,
Self::Size16 => I16,
Self::Size32 => I32,
Self::Size64 => I64,
}
}
}
#[derive(Clone)]
#[allow(dead_code)]
pub enum FenceKind {
MFence,
LFence,
SFence,
}