1use crate::{
2 ghost::{
3 FnGhost,
4 perm::{Perm, PermTarget},
5 },
6 logic::FMap,
7 prelude::*,
8 std::sync::{
9 committer::Committer,
10 view::{AcquireSyncView, HasTimestamp, ReleaseSyncView, SyncView, Timestamp},
11 },
12};
13use core::sync::atomic::{Ordering as OrderingTy, fence};
14
15pub mod ordering {
17 use core::sync::atomic::Ordering as OrderingTy;
18
19 pub trait Ordering {
20 const ORDERING: OrderingTy;
21 }
22
23 pub trait LoadOrdering: Ordering {}
24 pub trait StoreOrdering: Ordering {}
25 pub trait UpdateOrdering: Ordering {
26 type Load: LoadOrdering;
27 type Store: StoreOrdering;
28 }
29
30 pub struct None;
31
32 macro_rules! impl_ordering {
33 ( $order:ident, load = $load:ident, store = $store:ident ) => {
34 pub struct $order;
35
36 impl Ordering for $order {
37 const ORDERING: OrderingTy = OrderingTy::$order;
38 }
39
40 impl UpdateOrdering for $order {
41 type Load = $load;
42 type Store = $store;
43 }
44 };
45 }
46
47 impl_ordering!(Relaxed, load = Relaxed, store = Relaxed);
48 impl_ordering!(Acquire, load = Acquire, store = Relaxed);
49 impl_ordering!(Release, load = Relaxed, store = Release);
50 impl_ordering!(AcqRel, load = Acquire, store = Release);
51
52 impl LoadOrdering for Relaxed {}
53 impl StoreOrdering for Relaxed {}
54 impl LoadOrdering for Acquire {}
55 impl StoreOrdering for Release {}
56}
57
58use ordering::{LoadOrdering, StoreOrdering, UpdateOrdering};
59
60const SEQ_CST: OrderingTy = OrderingTy::SeqCst;
61
62macro_rules! impl_atomic {
63 ($( ($type:ty, $atomic_type:ident $(< $T:ident >)?) ),+) => { $(
64
65 #[doc = concat!("Creusot wrapper around [`std::sync::atomic::", stringify!($atomic_type), "`].")]
66 pub struct $atomic_type $(< $T >)?(::core::sync::atomic::$atomic_type $(< $T >)?);
67
68 impl $(< $T >)? PermTarget for $atomic_type $(< $T >)? {
69 type Value<'a> = FMap<Timestamp, ($type, SyncView)> where Self: 'a;
70 type PermPayload = ();
71 }
72
73 impl $(< $T >)? HasTimestamp for $atomic_type $(< $T >)? {
74 #[logic(opaque)]
75 fn get_timestamp(self, _: SyncView) -> Timestamp {
76 dead
77 }
78
79 #[logic(law)]
80 #[requires(x <= y)]
81 #[ensures(self.get_timestamp(x) <= self.get_timestamp(y))]
82 #[trusted]
83 fn get_timestamp_monotonic(self, x: SyncView, y: SyncView) {}
84 }
85
86 impl $(< $T >)? $atomic_type $(< $T >)? {
87 #[ensures(result.1.val() == FMap::singleton(result.0.get_timestamp(^sync_view), (val, **sync_view)))]
88 #[ensures(*result.1.ward() == result.0)]
89 #[inline(always)]
90 #[trusted]
91 #[check(terminates)]
92 #[allow(unused_variables)]
93 pub fn new(val: $type, sync_view: Ghost<&mut SyncView>) -> (Self, Ghost<Perm<$atomic_type $(< $T >)?>>) {
94 (Self(core::sync::atomic::$atomic_type::new(val)), Ghost::conjure())
95 }
96
97 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::into_inner`].")]
98 #[requires(self == *own.ward())]
99 #[ensures(match own.val().get(*result.1) { Some((v, _)) => result.0 == v, None => false })]
100 #[ensures(self.get_timestamp(^sync_view) == *result.1)]
101 #[ensures(forall<t> match own.val().get(t) {
102 Some((_, view)) => t <= *result.1 && view <= ^sync_view,
103 None => true
104 })]
105 #[inline(always)]
106 #[trusted]
107 #[allow(unused_variables)]
108 pub fn into_inner(self, own: Ghost<Perm<$atomic_type $(< $T >)?>>, sync_view: Ghost<&mut SyncView>) -> ($type, Ghost<Timestamp>) {
109 (self.0.into_inner(), Ghost::conjure())
110 }
111
112
113 #[doc = "Clear the old unusable history, thanks to the full ownership of the atomic."]
114 #[requires(*self == *own.ward())]
115 #[ensures(match (*own).val().get(*result) {
116 Some((v, _)) => (^own).val() == FMap::singleton(*result, (v, **sync_view)),
117 None => false
118 })]
119 #[ensures(self.get_timestamp(^sync_view) == *result)]
120 #[ensures(forall<t> match own.val().get(t) {
121 Some((_, view)) => t <= *result && view <= ^sync_view ,
122 None => true
123 })]
124 #[ensures(*self == ^self)]
125 #[inline(always)]
126 #[trusted]
127 #[check(terminates)]
128 #[allow(unused_variables)]
129 pub fn refresh(&mut self, own: Ghost<&mut Perm<$atomic_type $(< $T >)?>>, sync_view: Ghost<&mut SyncView>) -> Ghost<Timestamp> {
130 Ghost::conjure()
131 }
132
133 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::compare_exchange`].")]
134 #[doc = ""]
135 #[doc = "The load and the store are always sequentially consistent."]
136 #[requires(forall<c: &mut Committer<Self, $type, _, _>>
137 !c.shot_store() ==> c.ward() == *self ==>
138 c.val_load().deep_model() == current.deep_model() ==>
139 c.val_store() == new ==>
140 f.precondition((Ok(c),)) && (f.postcondition_once((Ok(c),), ()) ==> (^c).shot_store())
141 )]
142 #[requires(forall<c: &Committer<Self, $type, _, _>>
143 !c.shot_store() ==> c.ward() == *self ==>
144 c.val_load().deep_model() != current.deep_model() ==>
146 f.precondition((Err(c),))
147 )]
148 #[ensures(
149 match result {
150 Ok(result) => {
151 exists<c: &mut Committer<Self, $type, _, _>>
152 !c.shot_store() && c.ward() == *self &&
153 c.val_load().deep_model() == current.deep_model() &&
154 c.val_store() == new &&
155 result == c.val_load() &&
156 f.postcondition_once((Ok(c),), ())
157 },
158 Err(result) => {
159 exists<c: &Committer<Self, $type, _, _>>
160 !c.shot_store() && c.ward() == *self &&
161 c.val_load().deep_model() != current.deep_model() &&
163 result == c.val_load() &&
164 f.postcondition_once((Err(c),), ())
165 }
166 }
167 )]
168 #[inline(always)]
169 #[trusted]
170 #[allow(unused_variables)]
171 pub fn compare_exchange<F, Success: UpdateOrdering, Failure: LoadOrdering>(&self, current: $type, new: $type, f: Ghost<F>) -> Result<$type, $type>
172 where
173 F: FnGhost + FnOnce(Result<
174 &mut Committer<Self, $type, Success::Load, Success::Store>,
175 &Committer<Self, $type, Failure, ordering::None>
176 >,
177 )
178 {
179 self.0.compare_exchange(
180 current,
181 new,
182 if cfg!(feature = "sc-drf") { SEQ_CST } else { Success::ORDERING },
183 if cfg!(feature = "sc-drf") { SEQ_CST } else { Failure::ORDERING }
184 )
185 }
186
187 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::compare_exchange_weak`].")]
188 #[doc = ""]
189 #[doc = "The load and the store are always sequentially consistent."]
190 #[requires(forall<c: &mut Committer<Self, $type, _, _>> !c.shot_store() ==> c.ward() == *self ==>
192 c.val_load().deep_model() == current.deep_model() ==>
193 c.val_store() == new ==>
194 f.precondition((Ok(c),)) && (f.postcondition_once((Ok(c),), ()) ==> (^c).shot_store())
195 )]
196 #[requires(forall<c: &Committer<Self, $type, _, _>>
197 !c.shot_store() ==> c.ward() == *self ==>
198 f.precondition((Err(c),))
199 )]
200 #[ensures(
201 match result {
202 Ok(result) => {
203 exists<c: &mut Committer<Self, $type, _, _>>
204 !c.shot_store() && c.ward() == *self &&
205 c.val_load().deep_model() == current.deep_model() &&
206 c.val_store() == new &&
207 result == c.val_load() &&
208 f.postcondition_once((Ok(c),), ())
209 },
210 Err(result) => {
211 exists<c: &Committer<Self, $type, _, _>>
212 !c.shot_store() && c.ward() == *self &&
213 result == c.val_load() &&
214 f.postcondition_once((Err(c),), ())
215 }
216 }
217 )]
218 #[inline(always)]
219 #[trusted]
220 #[allow(unused_variables)]
221 pub fn compare_exchange_weak<F, Success: UpdateOrdering, Failure: LoadOrdering>(&self, current: $type, new: $type, f: Ghost<F>) -> Result<$type, $type>
222 where
223 F: FnGhost + FnOnce(Result<
224 &mut Committer<Self, $type, Success::Load, Success::Store>,
225 &Committer<Self, $type, Failure, ordering::None>
226 >,
227 )
228 {
229 self.0.compare_exchange_weak(
230 current,
231 new,
232 if cfg!(feature = "sc-drf") { SEQ_CST } else { Success::ORDERING },
233 if cfg!(feature = "sc-drf") { SEQ_CST } else { Failure::ORDERING }
234 )
235 }
236
237 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::load`].")]
238 #[requires(forall<c: &Committer<Self, $type, Load, ordering::None>>
239 !c.shot_store() ==> c.ward() == *self ==> f.precondition((c,))
240 )]
241 #[ensures(exists<c: &Committer<Self, $type, Load, ordering::None>>
242 !c.shot_store() && c.ward() == *self && c.val_load() == result && f.postcondition_once((c,), ())
243 )]
244 #[inline(always)]
245 #[trusted]
246 #[allow(unused_variables)]
247 pub fn load<F, Load: LoadOrdering>(&self, f: Ghost<F>) -> $type
248 where
249 F: FnGhost + FnOnce(&Committer<Self, $type, Load, ordering::None>),
250 {
251 self.0.load(if cfg!(feature = "sc-drf") { SEQ_CST } else { Load::ORDERING })
253 }
254
255 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::store`].")]
256 #[requires(forall<c: &mut Committer<Self, $type, ordering::None, Store>>
257 !c.shot_store() ==> c.ward() == *self ==> c.val_store() == val ==>
258 f.precondition((c,)) && (f.postcondition_once((c,), ()) ==> (^c).shot_store())
259 )]
260 #[ensures(exists<c: &mut Committer<Self, $type, ordering::None, Store>>
261 !c.shot_store() && c.ward() == *self && c.val_store() == val &&
262 f.postcondition_once((c,), ())
263 )]
264 #[inline(always)]
265 #[trusted]
266 #[allow(unused_variables)]
267 pub fn store<F, Store: StoreOrdering>(&self, val: $type, f: Ghost<F>)
268 where
269 F: FnGhost + FnOnce(&mut Committer<Self, $type, ordering::None, Store>),
270 {
271 self.0.store(
272 val,
273 if cfg!(feature = "sc-drf") { SEQ_CST } else { Store::ORDERING },
274 )
275 }
276 }
277
278 )* };
279}
280
281macro_rules! impl_atomic_int {
282 ($( ($int_type:ty, $atomic_type:ident) ),+) => { $(
283
284 impl_atomic!(($int_type, $atomic_type));
285
286 impl $atomic_type {
287 #[doc = concat!("Wrapper for [`std::sync::atomic::", stringify!($atomic_type), "::fetch_add`].")]
288 #[requires(forall<c: &mut Committer<Self, $int_type, Ord::Load, Ord::Store>>
289 !c.shot_store() ==> c.ward() == *self ==> c.val_store() == val + c.val_load() ==>
290 f.precondition((c,)) && (f.postcondition_once((c,), ()) ==> (^c).shot_store())
291 )]
292 #[ensures(exists<c: &mut Committer<Self, $int_type, Ord::Load, Ord::Store>>
293 !c.shot_store() && c.ward() == *self && c.val_store() == val + c.val_load() &&
294 c.val_load() == result && f.postcondition_once((c,), ())
295 )]
296 #[inline(always)]
297 #[trusted]
298 #[allow(unused_variables)]
299 pub fn fetch_add<F, Ord: UpdateOrdering>(&self, val: $int_type, f: Ghost<F>) -> $int_type
300 where
301 F: FnGhost + FnOnce(&mut Committer<Self, $int_type, Ord::Load, Ord::Store>),
302 {
303 self.0.fetch_add(
304 val,
305 if cfg!(feature = "sc-drf") { SEQ_CST } else { Ord::ORDERING },
306 )
307 }
308 }
309
310 )* };
311}
312
313#[cfg(target_has_atomic = "8")]
314impl_atomic!((bool, AtomicBool));
315#[cfg(target_has_atomic = "ptr")]
316impl_atomic!((*mut T, AtomicPtr<T>));
317
318#[cfg(target_has_atomic = "8")]
319impl_atomic_int!((i8, AtomicI8), (u8, AtomicU8));
320#[cfg(target_has_atomic = "16")]
321impl_atomic_int!((i16, AtomicI16), (u16, AtomicU16));
322#[cfg(target_has_atomic = "32")]
323impl_atomic_int!((i32, AtomicI32), (u32, AtomicU32));
324#[cfg(target_has_atomic = "64")]
325impl_atomic_int!((i64, AtomicI64), (u64, AtomicU64));
326
327#[cfg(target_has_atomic = "ptr")]
332impl_atomic_int!((isize, AtomicIsize), (usize, AtomicUsize));
333
334#[ensures(*sync_view == result@)]
335#[trusted]
336#[allow(unused_variables)]
337pub fn fence_release(sync_view: Ghost<SyncView>) -> Ghost<ReleaseSyncView> {
338 fence(OrderingTy::Release);
339 Ghost::conjure()
340}
341
342#[ensures(acq_view@ == *result)]
343#[trusted]
344#[allow(unused_variables)]
345pub fn fence_acquire(acq_view: Ghost<AcquireSyncView>) -> Ghost<SyncView> {
346 fence(OrderingTy::Acquire);
347 Ghost::conjure()
348}
349
350#[ensures(acq_view@ == result@)]
351#[trusted]
352#[allow(unused_variables)]
353pub fn fence_acqrel(acq_view: Ghost<AcquireSyncView>) -> Ghost<ReleaseSyncView> {
354 fence(OrderingTy::AcqRel);
355 Ghost::conjure()
356}