pessimize/
sync.rs

1//! Implementations of Pessimize for core::sync
2
3/// Implementations of Pessimize for core::sync::atomic
4mod atomic {
5    use crate::{assume_accessed, pessimize_cast, BorrowPessimize};
6    use core::sync::atomic;
7
8    macro_rules! pessimize_atomics {
9        (
10            $doc_cfg:meta
11            {
12                $(
13                    $inner:ty : $outer:ident $(<$param:ident>)?
14                ),*
15            }
16        ) => {
17            use atomic::{ $($outer),* };
18            //
19            pessimize_cast!(
20                $doc_cfg
21                {
22                    $(
23                        $inner : (
24                            $(|$param|)? $outer $(<$param>)? : (Self::into_inner, Self::new)
25                        )
26                    ),*
27                }
28            );
29            //
30            $(
31                #[cfg_attr(feature = "nightly", $doc_cfg)]
32                impl $(<$param>)? BorrowPessimize for $outer $(<$param>)? {
33                    type BorrowedPessimize = *const Self;
34
35                    #[inline]
36                    fn with_pessimize(&self, f: impl FnOnce(&Self::BorrowedPessimize)) {
37                        // While it is possible to extract an inner value from
38                        // &self, doing so is not something that LLVM can be
39                        // reliably expected to optimize out at the moment, so
40                        // must pessimize by pointer.
41                        f(&(self as *const Self))
42                    }
43
44                    #[inline]
45                    fn assume_accessed_impl(&mut self) {
46                        assume_accessed::<$inner>(self.get_mut())
47                    }
48                }
49            )*
50        };
51    }
52    //
53    #[cfg(target_has_atomic = "8")]
54    pessimize_atomics!(
55        doc(cfg(target_has_atomic = "8"))
56        {
57            bool: AtomicBool,
58            i8: AtomicI8,
59            u8: AtomicU8
60        }
61    );
62    #[cfg(target_has_atomic = "16")]
63    pessimize_atomics!(
64        doc(cfg(target_has_atomic = "16"))
65        {
66            i16: AtomicI16,
67            u16: AtomicU16
68        }
69    );
70    #[cfg(target_has_atomic = "32")]
71    pessimize_atomics!(
72        doc(cfg(target_has_atomic = "32"))
73        {
74            i32: AtomicI32,
75            u32: AtomicU32
76        }
77    );
78    // Need a 64-bit Pessimize impl as well as 64-bit atomics. Taking a little
79    // shortcut by taking the pessimistic assumption that you need a 64-bit
80    // arch to be able to hold 64-bit integers into registers.
81    #[cfg(all(target_has_atomic = "64", target_pointer_width = "64"))]
82    pessimize_atomics!(
83        doc(cfg(all(target_has_atomic = "64", target_pointer_width = "64")))
84        {
85            i64: AtomicI64,
86            u64: AtomicU64
87        }
88    );
89    #[cfg(target_has_atomic = "ptr")]
90    pessimize_atomics!(
91        doc(cfg(target_has_atomic = "ptr"))
92        {
93            isize: AtomicIsize,
94            usize: AtomicUsize,
95            *mut T: AtomicPtr<T>
96        }
97    );
98
99    #[allow(non_snake_case)]
100    #[cfg(test)]
101    mod tests {
102        use super::*;
103        use crate::{
104            cell::tests::test_unoptimized_cell,
105            pessimize_newtypes,
106            tests::{test_unoptimized_value_type, test_value, test_value_type},
107        };
108        use std::sync::atomic::Ordering;
109
110        macro_rules! make_testable_atomics {
111            (
112                $(
113                    ($inner:ty, $outer:ty, $testable:ident)
114                ),*
115            ) => {
116                $(
117                    #[derive(Debug, Default)]
118                    struct $testable($outer);
119
120                    impl $testable {
121                        fn new(inner: $inner) -> Self {
122                            Self(<$outer>::new(inner))
123                        }
124
125                        fn load(&self) -> $inner {
126                            self.0.load(Ordering::Relaxed)
127                        }
128                    }
129
130                    impl Clone for $testable {
131                        fn clone(&self) -> Self {
132                            $testable::new(self.load())
133                        }
134                    }
135
136                    impl PartialEq for $testable {
137                        fn eq(&self, other: &Self) -> bool {
138                            self.load() == other.load()
139                        }
140                    }
141
142                    pessimize_newtypes!( allow(missing_docs) { $testable{ $outer } } );
143                )*
144            };
145        }
146        //
147        macro_rules! test_scalar_atomics {
148            (
149                $(
150                    ($inner:ty, $outer:ty, $testable:ident, $basic_test:ident, $optim_test:ident, $min:expr, $max:expr)
151                ),*
152            ) => {
153                make_testable_atomics!(
154                    $(
155                        ($inner, $outer, $testable)
156                    ),*
157                );
158                $(
159                    #[test]
160                    fn $basic_test() {
161                        test_value_type($testable::new($min), $testable::new($max));
162                    }
163
164                    #[test]
165                    #[ignore]
166                    fn $optim_test() {
167                        test_unoptimized_value_type::<$testable>();
168                        test_unoptimized_cell(<$outer>::new(<$inner>::default()), <$outer>::get_mut);
169                    }
170                )*
171            };
172        }
173        //
174        macro_rules! test_int_atomics {
175            (
176                $(
177                    ($inner:ty, $outer:ident, $testable:ident, $basic_test:ident, $optim_test:ident)
178                ),*
179            ) => {
180                test_scalar_atomics!(
181                    $(
182                        ($inner, $outer, $testable, $basic_test, $optim_test, <$inner>::MIN, <$inner>::MAX)
183                    ),*
184                );
185            };
186        }
187        //
188        #[cfg(target_has_atomic = "8")]
189        test_scalar_atomics!((
190            bool,
191            AtomicBool,
192            TestableAtomicBool,
193            atomic_bool,
194            atomic_bool_optim,
195            false,
196            true
197        ));
198        #[cfg(target_has_atomic = "8")]
199        test_int_atomics!(
200            (i8, AtomicI8, TestableAtomicI8, atomic_i8, atomic_i8_optim),
201            (u8, AtomicU8, TestableAtomicU8, atomic_u8, atomic_u8_optim)
202        );
203        #[cfg(target_has_atomic = "16")]
204        test_int_atomics!(
205            (
206                i16,
207                AtomicI16,
208                TestableAtomicI16,
209                atomic_i16,
210                atomic_i16_optim
211            ),
212            (
213                u16,
214                AtomicU16,
215                TestableAtomicU16,
216                atomic_u16,
217                atomic_u16_optim
218            )
219        );
220        #[cfg(target_has_atomic = "32")]
221        test_int_atomics!(
222            (
223                i32,
224                AtomicI32,
225                TestableAtomicI32,
226                atomic_i32,
227                atomic_i32_optim
228            ),
229            (
230                u32,
231                AtomicU32,
232                TestableAtomicU32,
233                atomic_u32,
234                atomic_u32_optim
235            )
236        );
237        #[cfg(all(target_has_atomic = "64", target_pointer_width = "64"))]
238        test_int_atomics!(
239            (
240                i64,
241                AtomicI64,
242                TestableAtomicI64,
243                atomic_i64,
244                atomic_i64_optim
245            ),
246            (
247                u64,
248                AtomicU64,
249                TestableAtomicU64,
250                atomic_u64,
251                atomic_u64_optim
252            )
253        );
254        #[cfg(target_has_atomic = "ptr")]
255        test_int_atomics!(
256            (
257                isize,
258                AtomicIsize,
259                TestableAtomicIsize,
260                atomic_isize,
261                atomic_isize_optim
262            ),
263            (
264                usize,
265                AtomicUsize,
266                TestableAtomicUsize,
267                atomic_usize,
268                atomic_usize_optim
269            )
270        );
271
272        make_testable_atomics!((*mut (), AtomicPtr<()>, TestableAtomicPtr));
273        //
274        #[test]
275        fn atomic_ptr() {
276            test_value(TestableAtomicPtr::default());
277        }
278        //
279        #[test]
280        #[ignore]
281        fn atomic_ptr_optim() {
282            test_unoptimized_value_type::<TestableAtomicPtr>();
283            test_unoptimized_cell(
284                AtomicPtr::<()>::new(core::ptr::null_mut()),
285                AtomicPtr::get_mut,
286            );
287        }
288    }
289}