1use std::sync::atomic::AtomicUsize;
9
10pub trait AtomicElisionExt {
12 type IntType;
13
14 fn elision_compare_exchange_acquire(
16 &self,
17 current: Self::IntType,
18 new: Self::IntType,
19 ) -> Result<Self::IntType, Self::IntType>;
20
21 fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType;
23}
24
25#[inline]
27pub fn have_elision() -> bool {
28 cfg!(all(
29 feature = "hardware-lock-elision",
30 not(miri),
31 any(target_arch = "x86", target_arch = "x86_64"),
32 ))
33}
34
35#[cfg(not(all(
38 feature = "hardware-lock-elision",
39 not(miri),
40 any(target_arch = "x86", target_arch = "x86_64")
41)))]
42impl AtomicElisionExt for AtomicUsize {
43 type IntType = usize;
44
45 #[inline]
46 fn elision_compare_exchange_acquire(&self, _: usize, _: usize) -> Result<usize, usize> {
47 unreachable!();
48 }
49
50 #[inline]
51 fn elision_fetch_sub_release(&self, _: usize) -> usize {
52 unreachable!();
53 }
54}
55
56#[cfg(all(
57 feature = "hardware-lock-elision",
58 not(miri),
59 any(target_arch = "x86", target_arch = "x86_64")
60))]
61impl AtomicElisionExt for AtomicUsize {
62 type IntType = usize;
63
64 #[inline]
65 fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
66 unsafe {
67 use core::arch::asm;
68 let prev: usize;
69 #[cfg(target_pointer_width = "32")]
70 asm!(
71 "xacquire",
72 "lock",
73 "cmpxchg [{:e}], {:e}",
74 in(reg) self,
75 in(reg) new,
76 inout("eax") current => prev,
77 );
78 #[cfg(target_pointer_width = "64")]
79 asm!(
80 "xacquire",
81 "lock",
82 "cmpxchg [{}], {}",
83 in(reg) self,
84 in(reg) new,
85 inout("rax") current => prev,
86 );
87 if prev == current {
88 Ok(prev)
89 } else {
90 Err(prev)
91 }
92 }
93 }
94
95 #[inline]
96 fn elision_fetch_sub_release(&self, val: usize) -> usize {
97 unsafe {
98 use core::arch::asm;
99 let prev: usize;
100 #[cfg(target_pointer_width = "32")]
101 asm!(
102 "xrelease",
103 "lock",
104 "xadd [{:e}], {:e}",
105 in(reg) self,
106 inout(reg) val.wrapping_neg() => prev,
107 );
108 #[cfg(target_pointer_width = "64")]
109 asm!(
110 "xrelease",
111 "lock",
112 "xadd [{}], {}",
113 in(reg) self,
114 inout(reg) val.wrapping_neg() => prev,
115 );
116 prev
117 }
118 }
119}