| 1 | use crate::sync::atomic::Ordering; |
| 2 | |
| 3 | #[cfg (test)] |
| 4 | use stdarch_test::assert_instr; |
| 5 | |
| 6 | /// Compares and exchange 16 bytes (128 bits) of data atomically. |
| 7 | /// |
| 8 | /// This intrinsic corresponds to the `cmpxchg16b` instruction on `x86_64` |
| 9 | /// processors. It performs an atomic compare-and-swap, updating the `ptr` |
| 10 | /// memory location to `val` if the current value in memory equals `old`. |
| 11 | /// |
| 12 | /// # Return value |
| 13 | /// |
| 14 | /// This function returns the previous value at the memory location. If it is |
| 15 | /// equal to `old` then the memory was updated to `new`. |
| 16 | /// |
| 17 | /// # Memory Orderings |
| 18 | /// |
| 19 | /// This atomic operation has the same semantics of memory orderings as |
| 20 | /// `AtomicUsize::compare_exchange` does, only operating on 16 bytes of memory |
| 21 | /// instead of just a pointer. |
| 22 | /// |
| 23 | /// The failure ordering must be [`Ordering::SeqCst`], [`Ordering::Acquire`] or |
| 24 | /// [`Ordering::Relaxed`]. |
| 25 | /// |
| 26 | /// For more information on memory orderings here see the `compare_exchange` |
| 27 | /// documentation for other `Atomic*` types in the standard library. |
| 28 | /// |
| 29 | /// # Unsafety |
| 30 | /// |
| 31 | /// This method is unsafe because it takes a raw pointer and will attempt to |
| 32 | /// read and possibly write the memory at the pointer. The pointer must also be |
| 33 | /// aligned on a 16-byte boundary. |
| 34 | /// |
| 35 | /// This method also requires the `cmpxchg16b` CPU feature to be available at |
| 36 | /// runtime to work correctly. If the CPU running the binary does not actually |
| 37 | /// support `cmpxchg16b` and the program enters an execution path that |
| 38 | /// eventually would reach this function the behavior is undefined. |
| 39 | #[inline ] |
| 40 | #[cfg_attr (miri, track_caller)] // even without panics, this helps for Miri backtraces |
| 41 | #[cfg_attr (test, assert_instr(cmpxchg16b, success = Ordering::SeqCst, failure = Ordering::SeqCst))] |
| 42 | #[target_feature (enable = "cmpxchg16b" )] |
| 43 | #[stable (feature = "cmpxchg16b_intrinsic" , since = "1.67.0" )] |
| 44 | pub unsafe fn cmpxchg16b( |
| 45 | dst: *mut u128, |
| 46 | old: u128, |
| 47 | new: u128, |
| 48 | success: Ordering, |
| 49 | failure: Ordering, |
| 50 | ) -> u128 { |
| 51 | use crate::{intrinsics, sync::atomic::Ordering::*}; |
| 52 | |
| 53 | debug_assert!(dst as usize % 16 == 0); |
| 54 | |
| 55 | // Copied from `atomic_compare_exchange` in `core`. |
| 56 | // https://github.com/rust-lang/rust/blob/f8a2e49/library/core/src/sync/atomic.rs#L3046-L3079 |
| 57 | let (val, _ok) = match (success, failure) { |
| 58 | (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), |
| 59 | (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), |
| 60 | (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), |
| 61 | (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), |
| 62 | (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), |
| 63 | (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), |
| 64 | (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), |
| 65 | (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), |
| 66 | (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), |
| 67 | (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), |
| 68 | (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), |
| 69 | (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), |
| 70 | (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), |
| 71 | (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), |
| 72 | (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), |
| 73 | (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering" ), |
| 74 | (_, Release) => panic!("there is no such thing as a release failure ordering" ), |
| 75 | |
| 76 | // `atomic::Ordering` is non_exhaustive. It warns when `core_arch` is built as a part of `core`. |
| 77 | #[allow (unreachable_patterns)] |
| 78 | (_, _) => unreachable!(), |
| 79 | }; |
| 80 | val |
| 81 | } |
| 82 | |