delegate_size!(delegate_all);
use core::{
arch::asm,
mem::{self, MaybeUninit},
sync::atomic::Ordering,
};
use crate::raw::{AtomicCompareExchange, AtomicLoad, AtomicStore, AtomicSwap};
#[rustfmt::skip]
macro_rules! disable {
() => {
concat!(
"mov r2, {sr}", "\n", "dint {{ nop", )
};
}
macro_rules! restore {
() => {
"nop {{ mov {sr}, r2 {{ nop" };
}
macro_rules! atomic {
($ty:ident, $suffix:tt) => {
delegate_signed!(delegate_all, $ty);
impl AtomicLoad for $ty {
#[inline]
unsafe fn atomic_load(
src: *const MaybeUninit<Self>,
_order: Ordering,
) -> MaybeUninit<Self> {
let out: MaybeUninit<Self>;
unsafe {
asm!(
concat!("mov.", $suffix, " @{src}, {out}"), src = in(reg) src,
out = lateout(reg) out,
options(nostack, preserves_flags),
);
}
out
}
}
impl AtomicStore for $ty {
#[inline]
unsafe fn atomic_store(
dst: *mut MaybeUninit<Self>,
val: MaybeUninit<Self>,
_order: Ordering,
) {
unsafe {
asm!(
concat!("mov.", $suffix, " {val}, 0({dst})"), dst = in(reg) dst,
val = in(reg) val,
options(nostack, preserves_flags),
);
}
}
}
impl AtomicSwap for $ty {
#[inline]
unsafe fn atomic_swap(
dst: *mut MaybeUninit<Self>,
val: MaybeUninit<Self>,
_order: Ordering,
) -> MaybeUninit<Self> {
let out: MaybeUninit<Self>;
unsafe {
asm!(
disable!(), concat!("mov.", $suffix, " @{dst}, {out}"), concat!("mov.", $suffix, " {val}, 0({dst})"), restore!(), dst = in(reg) dst,
val = in(reg) val,
out = out(reg) out,
sr = out(reg) _,
options(nostack, preserves_flags),
);
}
out
}
}
impl AtomicCompareExchange for $ty {
#[inline]
unsafe fn atomic_compare_exchange(
dst: *mut MaybeUninit<Self>,
old: MaybeUninit<Self>,
new: MaybeUninit<Self>,
_success: Ordering,
_failure: Ordering,
) -> (MaybeUninit<Self>, bool) {
let out: MaybeUninit<Self>;
let mut r: $ty;
unsafe {
asm!(
disable!(), concat!("mov.", $suffix, " @{dst}, {out}"), concat!("xor.", $suffix, " {out}, {old}"), "jne 2f", concat!("mov.", $suffix, " {new}, 0({dst})"), "2:", restore!(), dst = in(reg) dst,
old = inout(reg) old => r,
new = in(reg) new,
out = out(reg) out,
sr = out(reg) _,
options(nostack, preserves_flags),
);
}
(out, r == 0)
}
}
};
}
atomic!(u8, "b");
atomic!(u16, "w");
#[macro_export]
macro_rules! cfg_has_atomic_8 {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_no_atomic_8 {
($($tt:tt)*) => {};
}
#[macro_export]
macro_rules! cfg_has_atomic_16 {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_no_atomic_16 {
($($tt:tt)*) => {};
}
#[macro_export]
macro_rules! cfg_has_atomic_32 {
($($tt:tt)*) => {};
}
#[macro_export]
macro_rules! cfg_no_atomic_32 {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_has_atomic_64 {
($($tt:tt)*) => {};
}
#[macro_export]
macro_rules! cfg_no_atomic_64 {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_has_atomic_128 {
($($tt:tt)*) => {};
}
#[macro_export]
macro_rules! cfg_no_atomic_128 {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_has_atomic_cas {
($($tt:tt)*) => { $($tt)* };
}
#[macro_export]
macro_rules! cfg_no_atomic_cas {
($($tt:tt)*) => {};
}