#![cfg_attr(feature = "c", allow(unused_macros))]
#[rustfmt::skip]
macro_rules! int_ty {
(1) => { i8 };
(2) => { i16 };
(4) => { i32 };
(8) => { i64 };
(16) => { i128 };
}
#[rustfmt::skip]
macro_rules! reg {
(1, $num:literal) => { concat!("w", $num) };
(2, $num:literal) => { concat!("w", $num) };
(4, $num:literal) => { concat!("w", $num) };
(8, $num:literal) => { concat!("x", $num) };
}
#[rustfmt::skip]
macro_rules! acquire {
(Relaxed) => { "" };
(Acquire) => { "a" };
(Release) => { "" };
(AcqRel) => { "a" };
}
#[rustfmt::skip]
macro_rules! release {
(Relaxed) => { "" };
(Acquire) => { "" };
(Release) => { "l" };
(AcqRel) => { "l" };
}
#[rustfmt::skip]
macro_rules! size {
(1) => { "b" };
(2) => { "h" };
(4) => { "" };
(8) => { "" };
(16) => { "" };
}
#[rustfmt::skip]
macro_rules! uxt {
(1) => { "uxtb" };
(2) => { "uxth" };
($_:tt) => { "mov" };
}
macro_rules! ldxr {
($ordering:ident, $bytes:tt) => {
concat!("ld", acquire!($ordering), "xr", size!($bytes))
};
}
macro_rules! stxr {
($ordering:ident, $bytes:tt) => {
concat!("st", release!($ordering), "xr", size!($bytes))
};
}
macro_rules! ldxp {
($ordering:ident) => {
concat!("ld", acquire!($ordering), "xp")
};
}
macro_rules! stxp {
($ordering:ident) => {
concat!("st", release!($ordering), "xp")
};
}
macro_rules! compare_and_swap {
($ordering:ident, $bytes:tt, $name:ident) => {
intrinsics! {
#[maybe_use_optimized_c_shim]
#[naked]
pub unsafe extern "C" fn $name (
expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes)
) -> int_ty!($bytes) {
unsafe { core::arch::asm! {
concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"),
concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)),
"bne 1f",
concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"),
"cbnz w17, 0b",
"1:",
"ret",
options(noreturn)
} }
}
}
};
}
macro_rules! compare_and_swap_i128 {
($ordering:ident, $name:ident) => {
intrinsics! {
#[maybe_use_optimized_c_shim]
#[naked]
pub unsafe extern "C" fn $name (
expected: i128, desired: i128, ptr: *mut i128
) -> i128 {
unsafe { core::arch::asm! {
"mov x16, x0",
"mov x17, x1",
"0:",
concat!(ldxp!($ordering), " x0, x1, [x4]"),
"cmp x0, x16",
"ccmp x1, x17, #0, eq",
"bne 1f",
concat!(stxp!($ordering), " w15, x2, x3, [x4]"),
"cbnz w15, 0b",
"1:",
"ret",
options(noreturn)
} }
}
}
};
}
macro_rules! swap {
($ordering:ident, $bytes:tt, $name:ident) => {
intrinsics! {
#[maybe_use_optimized_c_shim]
#[naked]
pub unsafe extern "C" fn $name (
left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes)
) -> int_ty!($bytes) {
unsafe { core::arch::asm! {
concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"),
concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"),
"cbnz w17, 0b",
"ret",
options(noreturn)
} }
}
}
};
}
macro_rules! fetch_op {
($ordering:ident, $bytes:tt, $name:ident, $op:literal) => {
intrinsics! {
#[maybe_use_optimized_c_shim]
#[naked]
pub unsafe extern "C" fn $name (
val: int_ty!($bytes), ptr: *mut int_ty!($bytes)
) -> int_ty!($bytes) {
unsafe { core::arch::asm! {
concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"),
concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)),
concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"),
"cbnz w15, 0b",
"ret",
options(noreturn)
} }
}
}
}
}
macro_rules! add {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "add" }
};
}
macro_rules! and {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "bic" }
};
}
macro_rules! xor {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "eor" }
};
}
macro_rules! or {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "orr" }
};
}
include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs"));
foreach_cas!(compare_and_swap);
foreach_cas16!(compare_and_swap_i128);
foreach_swp!(swap);
foreach_ldadd!(add);
foreach_ldclr!(and);
foreach_ldeor!(xor);
foreach_ldset!(or);