129c32c40SBoqun Feng // SPDX-License-Identifier: GPL-2.0 229c32c40SBoqun Feng 329c32c40SBoqun Feng //! Pre-defined atomic types 429c32c40SBoqun Feng 5*84c6d36bSBoqun Feng use crate::static_assert; 6*84c6d36bSBoqun Feng use core::mem::{align_of, size_of}; 7*84c6d36bSBoqun Feng 829c32c40SBoqun Feng // SAFETY: `i32` has the same size and alignment with itself, and is round-trip transmutable to 929c32c40SBoqun Feng // itself. 1029c32c40SBoqun Feng unsafe impl super::AtomicType for i32 { 1129c32c40SBoqun Feng type Repr = i32; 1229c32c40SBoqun Feng } 1329c32c40SBoqun Feng 14d1320543SBoqun Feng // SAFETY: The wrapping add result of two `i32`s is a valid `i32`. 15d1320543SBoqun Feng unsafe impl super::AtomicAdd<i32> for i32 { rhs_into_delta(rhs: i32) -> i3216d1320543SBoqun Feng fn rhs_into_delta(rhs: i32) -> i32 { 17d1320543SBoqun Feng rhs 18d1320543SBoqun Feng } 19d1320543SBoqun Feng } 20d1320543SBoqun Feng 2129c32c40SBoqun Feng // SAFETY: `i64` has the same size and alignment with itself, and is round-trip transmutable to 2229c32c40SBoqun Feng // itself. 2329c32c40SBoqun Feng unsafe impl super::AtomicType for i64 { 2429c32c40SBoqun Feng type Repr = i64; 2529c32c40SBoqun Feng } 26d1320543SBoqun Feng 27d1320543SBoqun Feng // SAFETY: The wrapping add result of two `i64`s is a valid `i64`. 28d1320543SBoqun Feng unsafe impl super::AtomicAdd<i64> for i64 { rhs_into_delta(rhs: i64) -> i6429d1320543SBoqun Feng fn rhs_into_delta(rhs: i64) -> i64 { 30d1320543SBoqun Feng rhs 31d1320543SBoqun Feng } 32d1320543SBoqun Feng } 33d6df37baSBoqun Feng 34*84c6d36bSBoqun Feng // Defines an internal type that always maps to the integer type which has the same size alignment 35*84c6d36bSBoqun Feng // as `isize` and `usize`, and `isize` and `usize` are always bi-directional transmutable to 36*84c6d36bSBoqun Feng // `isize_atomic_repr`, which also always implements `AtomicImpl`. 37*84c6d36bSBoqun Feng #[allow(non_camel_case_types)] 38*84c6d36bSBoqun Feng #[cfg(not(CONFIG_64BIT))] 39*84c6d36bSBoqun Feng type isize_atomic_repr = i32; 40*84c6d36bSBoqun Feng #[allow(non_camel_case_types)] 41*84c6d36bSBoqun Feng #[cfg(CONFIG_64BIT)] 42*84c6d36bSBoqun Feng type isize_atomic_repr = i64; 43*84c6d36bSBoqun Feng 44*84c6d36bSBoqun Feng // Ensure size and alignment requirements are checked. 45*84c6d36bSBoqun Feng static_assert!(size_of::<isize>() == size_of::<isize_atomic_repr>()); 46*84c6d36bSBoqun Feng static_assert!(align_of::<isize>() == align_of::<isize_atomic_repr>()); 47*84c6d36bSBoqun Feng static_assert!(size_of::<usize>() == size_of::<isize_atomic_repr>()); 48*84c6d36bSBoqun Feng static_assert!(align_of::<usize>() == align_of::<isize_atomic_repr>()); 49*84c6d36bSBoqun Feng 50*84c6d36bSBoqun Feng // SAFETY: `isize` has the same size and alignment with `isize_atomic_repr`, and is round-trip 51*84c6d36bSBoqun Feng // transmutable to `isize_atomic_repr`. 52*84c6d36bSBoqun Feng unsafe impl super::AtomicType for isize { 53*84c6d36bSBoqun Feng type Repr = isize_atomic_repr; 54*84c6d36bSBoqun Feng } 55*84c6d36bSBoqun Feng 56*84c6d36bSBoqun Feng // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`. 57*84c6d36bSBoqun Feng unsafe impl super::AtomicAdd<isize> for isize { rhs_into_delta(rhs: isize) -> isize_atomic_repr58*84c6d36bSBoqun Feng fn rhs_into_delta(rhs: isize) -> isize_atomic_repr { 59*84c6d36bSBoqun Feng rhs as isize_atomic_repr 60*84c6d36bSBoqun Feng } 61*84c6d36bSBoqun Feng } 62*84c6d36bSBoqun Feng 63d6df37baSBoqun Feng // SAFETY: `u32` and `i32` has the same size and alignment, and `u32` is round-trip transmutable to 64d6df37baSBoqun Feng // `i32`. 65d6df37baSBoqun Feng unsafe impl super::AtomicType for u32 { 66d6df37baSBoqun Feng type Repr = i32; 67d6df37baSBoqun Feng } 68d6df37baSBoqun Feng 69d6df37baSBoqun Feng // SAFETY: The wrapping add result of two `i32`s is a valid `u32`. 70d6df37baSBoqun Feng unsafe impl super::AtomicAdd<u32> for u32 { rhs_into_delta(rhs: u32) -> i3271d6df37baSBoqun Feng fn rhs_into_delta(rhs: u32) -> i32 { 72d6df37baSBoqun Feng rhs as i32 73d6df37baSBoqun Feng } 74d6df37baSBoqun Feng } 75d6df37baSBoqun Feng 76d6df37baSBoqun Feng // SAFETY: `u64` and `i64` has the same size and alignment, and `u64` is round-trip transmutable to 77d6df37baSBoqun Feng // `i64`. 78d6df37baSBoqun Feng unsafe impl super::AtomicType for u64 { 79d6df37baSBoqun Feng type Repr = i64; 80d6df37baSBoqun Feng } 81d6df37baSBoqun Feng 82d6df37baSBoqun Feng // SAFETY: The wrapping add result of two `i64`s is a valid `u64`. 83d6df37baSBoqun Feng unsafe impl super::AtomicAdd<u64> for u64 { rhs_into_delta(rhs: u64) -> i6484d6df37baSBoqun Feng fn rhs_into_delta(rhs: u64) -> i64 { 85d6df37baSBoqun Feng rhs as i64 86d6df37baSBoqun Feng } 87d6df37baSBoqun Feng } 88d6df37baSBoqun Feng 89*84c6d36bSBoqun Feng // SAFETY: `usize` has the same size and alignment with `isize_atomic_repr`, and is round-trip 90*84c6d36bSBoqun Feng // transmutable to `isize_atomic_repr`. 91*84c6d36bSBoqun Feng unsafe impl super::AtomicType for usize { 92*84c6d36bSBoqun Feng type Repr = isize_atomic_repr; 93*84c6d36bSBoqun Feng } 94*84c6d36bSBoqun Feng 95*84c6d36bSBoqun Feng // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`. 96*84c6d36bSBoqun Feng unsafe impl super::AtomicAdd<usize> for usize { rhs_into_delta(rhs: usize) -> isize_atomic_repr97*84c6d36bSBoqun Feng fn rhs_into_delta(rhs: usize) -> isize_atomic_repr { 98*84c6d36bSBoqun Feng rhs as isize_atomic_repr 99*84c6d36bSBoqun Feng } 100*84c6d36bSBoqun Feng } 101*84c6d36bSBoqun Feng 102d6df37baSBoqun Feng use crate::macros::kunit_tests; 103d6df37baSBoqun Feng 104d6df37baSBoqun Feng #[kunit_tests(rust_atomics)] 105d6df37baSBoqun Feng mod tests { 106d6df37baSBoqun Feng use super::super::*; 107d6df37baSBoqun Feng 108d6df37baSBoqun Feng // Call $fn($val) with each $type of $val. 109d6df37baSBoqun Feng macro_rules! for_each_type { 110d6df37baSBoqun Feng ($val:literal in [$($type:ty),*] $fn:expr) => { 111d6df37baSBoqun Feng $({ 112d6df37baSBoqun Feng let v: $type = $val; 113d6df37baSBoqun Feng 114d6df37baSBoqun Feng $fn(v); 115d6df37baSBoqun Feng })* 116d6df37baSBoqun Feng } 117d6df37baSBoqun Feng } 118d6df37baSBoqun Feng 119d6df37baSBoqun Feng #[test] atomic_basic_tests()120d6df37baSBoqun Feng fn atomic_basic_tests() { 121*84c6d36bSBoqun Feng for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 122d6df37baSBoqun Feng let x = Atomic::new(v); 123d6df37baSBoqun Feng 124d6df37baSBoqun Feng assert_eq!(v, x.load(Relaxed)); 125d6df37baSBoqun Feng }); 126d6df37baSBoqun Feng } 127d6df37baSBoqun Feng 128d6df37baSBoqun Feng #[test] atomic_xchg_tests()129d6df37baSBoqun Feng fn atomic_xchg_tests() { 130*84c6d36bSBoqun Feng for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 131d6df37baSBoqun Feng let x = Atomic::new(v); 132d6df37baSBoqun Feng 133d6df37baSBoqun Feng let old = v; 134d6df37baSBoqun Feng let new = v + 1; 135d6df37baSBoqun Feng 136d6df37baSBoqun Feng assert_eq!(old, x.xchg(new, Full)); 137d6df37baSBoqun Feng assert_eq!(new, x.load(Relaxed)); 138d6df37baSBoqun Feng }); 139d6df37baSBoqun Feng } 140d6df37baSBoqun Feng 141d6df37baSBoqun Feng #[test] atomic_cmpxchg_tests()142d6df37baSBoqun Feng fn atomic_cmpxchg_tests() { 143*84c6d36bSBoqun Feng for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 144d6df37baSBoqun Feng let x = Atomic::new(v); 145d6df37baSBoqun Feng 146d6df37baSBoqun Feng let old = v; 147d6df37baSBoqun Feng let new = v + 1; 148d6df37baSBoqun Feng 149d6df37baSBoqun Feng assert_eq!(Err(old), x.cmpxchg(new, new, Full)); 150d6df37baSBoqun Feng assert_eq!(old, x.load(Relaxed)); 151d6df37baSBoqun Feng assert_eq!(Ok(old), x.cmpxchg(old, new, Relaxed)); 152d6df37baSBoqun Feng assert_eq!(new, x.load(Relaxed)); 153d6df37baSBoqun Feng }); 154d6df37baSBoqun Feng } 155d6df37baSBoqun Feng 156d6df37baSBoqun Feng #[test] atomic_arithmetic_tests()157d6df37baSBoqun Feng fn atomic_arithmetic_tests() { 158*84c6d36bSBoqun Feng for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 159d6df37baSBoqun Feng let x = Atomic::new(v); 160d6df37baSBoqun Feng 161d6df37baSBoqun Feng assert_eq!(v, x.fetch_add(12, Full)); 162d6df37baSBoqun Feng assert_eq!(v + 12, x.load(Relaxed)); 163d6df37baSBoqun Feng 164d6df37baSBoqun Feng x.add(13, Relaxed); 165d6df37baSBoqun Feng 166d6df37baSBoqun Feng assert_eq!(v + 25, x.load(Relaxed)); 167d6df37baSBoqun Feng }); 168d6df37baSBoqun Feng } 169d6df37baSBoqun Feng } 170