use crate::{Cmov, CmovEq, Condition};
use core::arch::asm;
macro_rules! csel {
($cmp:expr, $csel:expr, $dst:expr, $src:expr, $condition:expr) => {
unsafe {
asm! {
"cmp {0:w}, 0",
$csel,
in(reg) $condition,
inlateout(reg) *$dst,
in(reg) *$src,
in(reg) *$dst,
options(pure, nomem, nostack),
};
}
};
}
macro_rules! cseleq {
($eor:expr, $cmp:expr, $instruction:expr, $lhs:expr, $rhs:expr, $condition:expr, $dst:expr) => {
let mut tmp = *$dst as u16;
unsafe {
asm! {
$eor,
$cmp,
$instruction,
out(reg) _,
in(reg) *$lhs,
in(reg) *$rhs,
inlateout(reg) tmp,
in(reg) $condition as u16,
in(reg) tmp,
options(pure, nomem, nostack),
};
};
#[allow(clippy::cast_possible_truncation)]
{
*$dst = tmp as u8;
}
};
}
macro_rules! csel32 {
($csel:expr, $dst:expr, $src:expr, $condition:expr) => {
csel!("cmp {0:w}, 0", $csel, $dst, $src, $condition)
};
}
macro_rules! csel64 {
($csel:expr, $dst:expr, $src:expr, $condition:expr) => {
csel!("cmp {0:x}, 0", $csel, $dst, $src, $condition)
};
}
macro_rules! cseleq32 {
($instruction:expr, $lhs:expr, $rhs:expr, $condition:expr, $dst:expr) => {
cseleq!(
"eor {0:w}, {1:w}, {2:w}",
"cmp {0:w}, 0",
$instruction,
$lhs,
$rhs,
$condition,
$dst
)
};
}
macro_rules! cseleq64 {
($instruction:expr, $lhs:expr, $rhs:expr, $condition:expr, $dst:expr) => {
cseleq!(
"eor {0:x}, {1:x}, {2:x}",
"cmp {0:x}, 0",
$instruction,
$lhs,
$rhs,
$condition,
$dst
)
};
}
impl Cmov for u16 {
#[inline]
fn cmovnz(&mut self, value: &Self, condition: Condition) {
csel32!("csel {1:w}, {2:w}, {3:w}, NE", self, value, condition);
}
#[inline]
fn cmovz(&mut self, value: &Self, condition: Condition) {
csel32!("csel {1:w}, {2:w}, {3:w}, EQ", self, value, condition);
}
}
impl CmovEq for u16 {
#[inline]
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq32!("csel {3:w}, {4:w}, {5:w}, NE", self, rhs, input, output);
}
#[inline]
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq32!("csel {3:w}, {4:w}, {5:w}, EQ", self, rhs, input, output);
}
}
impl Cmov for u32 {
#[inline]
fn cmovnz(&mut self, value: &Self, condition: Condition) {
csel32!("csel {1:w}, {2:w}, {3:w}, NE", self, value, condition);
}
#[inline]
fn cmovz(&mut self, value: &Self, condition: Condition) {
csel32!("csel {1:w}, {2:w}, {3:w}, EQ", self, value, condition);
}
}
impl CmovEq for u32 {
#[inline]
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq32!("csel {3:w}, {4:w}, {5:w}, NE", self, rhs, input, output);
}
#[inline]
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq32!("csel {3:w}, {4:w}, {5:w}, EQ", self, rhs, input, output);
}
}
impl Cmov for u64 {
#[inline]
fn cmovnz(&mut self, value: &Self, condition: Condition) {
csel64!("csel {1:x}, {2:x}, {3:x}, NE", self, value, condition);
}
#[inline]
fn cmovz(&mut self, value: &Self, condition: Condition) {
csel64!("csel {1:x}, {2:x}, {3:x}, EQ", self, value, condition);
}
}
impl CmovEq for u64 {
#[inline]
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq64!("csel {3:x}, {4:x}, {5:x}, NE", self, rhs, input, output);
}
#[inline]
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
cseleq64!("csel {3:x}, {4:x}, {5:x}, EQ", self, rhs, input, output);
}
}