1use crate::{
2 ghost::Plain,
3 logic::ops::{AddLogic, MulLogic, NegLogic, NthBitLogic, SubLogic},
4 prelude::*,
5};
6
7macro_rules! mach_int {
8 ($t:ty, $ty_nm:expr, $zero:expr, $to_int:literal) => {
9 impl View for $t {
10 type ViewTy = Int;
11 #[logic]
12 #[builtin(concat!($ty_nm, $to_int))]
13 fn view(self) -> Self::ViewTy {
14 dead
15 }
16 }
17
18 impl DeepModel for $t {
19 type DeepModelTy = Int;
20 #[logic(open, inline)]
21 fn deep_model(self) -> Self::DeepModelTy {
22 pearlite! { self@ }
23 }
24 }
25
26 impl Plain for $t {
27 #[trusted]
28 #[ensures(*result == *snap)]
29 #[check(ghost)]
30 #[allow(unused_variables)]
31 fn into_ghost(snap: Snapshot<Self>) -> Ghost<Self> {
32 Ghost::conjure()
33 }
34 }
35
36 extern_spec! {
37 impl Default for $t {
38 #[check(ghost)]
39 #[ensures(result == $zero)]
40 fn default() -> $t { 0 }
41 }
42
43 impl Clone for $t {
44 #[check(ghost)]
45 #[ensures(result == *self)]
46 fn clone(&self) -> $t {
47 *self
48 }
49 }
50 }
51
52 impl AddLogic for $t {
53 type Output = Self;
54 #[logic]
55 #[builtin(concat!($ty_nm, ".add"))]
56 #[allow(unused_variables)]
57 fn add(self, other: Self) -> Self {
58 dead
59 }
60 }
61
62 impl SubLogic for $t {
63 type Output = Self;
64 #[logic]
65 #[builtin(concat!($ty_nm, ".sub"))]
66 #[allow(unused_variables)]
67 fn sub(self, other: Self) -> Self {
68 dead
69 }
70 }
71
72 impl MulLogic for $t {
73 type Output = Self;
74 #[logic]
75 #[builtin(concat!($ty_nm, ".mul"))]
76 #[allow(unused_variables)]
77 fn mul(self, other: Self) -> Self {
78 dead
79 }
80 }
81
82 impl NegLogic for $t {
83 type Output = Self;
84 #[logic]
85 #[builtin(concat!($ty_nm, ".neg"))]
86 fn neg(self) -> Self {
87 dead
88 }
89 }
90
91 impl NthBitLogic for $t {
92 #[logic]
93 #[builtin(concat!($ty_nm, ".nth"))]
94 #[allow(unused_variables)]
95 fn nth_bit(self, n: Int) -> bool {
96 dead
97 }
98 }
99 };
100}
101
102mach_int!(u8, "creusot.int.UInt8$BW$", 0u8, ".t'int");
103mach_int!(u16, "creusot.int.UInt16$BW$", 0u16, ".t'int");
104mach_int!(u32, "creusot.int.UInt32$BW$", 0u32, ".t'int");
105mach_int!(u64, "creusot.int.UInt64$BW$", 0u64, ".t'int");
106mach_int!(u128, "creusot.int.UInt128$BW$", 0u128, ".t'int");
107#[cfg(target_pointer_width = "64")]
108mach_int!(usize, "creusot.int.UInt64$BW$", 0usize, ".t'int");
109#[cfg(target_pointer_width = "32")]
110mach_int!(usize, "creusot.int.UInt32$BW$", 0usize, ".t'int");
111#[cfg(target_pointer_width = "16")]
112mach_int!(usize, "creusot.int.UInt16$BW$", 0usize, ".t'int");
113
114mach_int!(i8, "creusot.int.Int8$BW$", 0i8, ".to_int");
115mach_int!(i16, "creusot.int.Int16$BW$", 0i16, ".to_int");
116mach_int!(i32, "creusot.int.Int32$BW$", 0i32, ".to_int");
117mach_int!(i64, "creusot.int.Int64$BW$", 0i64, ".to_int");
118mach_int!(i128, "creusot.int.Int128$BW$", 0i128, ".to_int");
119#[cfg(target_pointer_width = "64")]
120mach_int!(isize, "creusot.int.Int64$BW$", 0isize, ".to_int");
121#[cfg(target_pointer_width = "32")]
122mach_int!(isize, "creusot.int.Int32$BW$", 0isize, ".to_int");
123#[cfg(target_pointer_width = "16")]
124mach_int!(isize, "creusot.int.Int16$BW$", 0isize, ".to_int");
125
126macro_rules! spec_type {
129 ($type:ty) => {
130 spec_op_common!($type, +, checked_add, wrapping_add, saturating_add, overflowing_add, unchecked_add);
132 spec_op_common!($type, -, checked_sub, wrapping_sub, saturating_sub, overflowing_sub, unchecked_sub);
133 spec_op_common!($type, *, checked_mul, wrapping_mul, saturating_mul, overflowing_mul, unchecked_mul);
134
135 extern_spec! {
136 impl $type {
137 #[allow(dead_code)]
138 #[check(ghost)]
139 #[ensures(result == -self)]
140 fn wrapping_neg(self) -> $type;
141 }
142 }
143
144 extern_spec! {
148 impl $type {
149 #[allow(dead_code)]
150 #[check(ghost)]
151 #[ensures((result == None) == (rhs@ == 0 || (self@ == $type::MIN@ && rhs@ == -1)))]
153 #[ensures(forall<r: $type> result == Some(r) ==> r@ == self@ / rhs@)]
155 fn checked_div(self, rhs: $type) -> Option<$type>;
156
157 #[allow(dead_code)]
158 #[check(ghost)]
159 #[requires(rhs@ != 0)]
161 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result@ == self@)]
163 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result@ == self@ / rhs@)]
165 fn wrapping_div(self, rhs: $type) -> $type;
166
167 #[allow(dead_code)]
168 #[check(ghost)]
169 #[requires(rhs@ != 0)]
171 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result@ == $type::MIN@)]
173 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result@ == self@ / rhs@)]
175 fn saturating_div(self, rhs: $type) -> $type;
176
177 #[allow(dead_code)]
178 #[check(ghost)]
179 #[requires(rhs@ != 0)]
181 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result.0@ == self@)]
183 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result.0@ == self@ / rhs@)]
185 #[ensures(result.1 == (self@ == $type::MIN@ && rhs@ == -1))]
187 fn overflowing_div(self, rhs: $type) -> ($type, bool);
188 }
189 }
190 };
191}
192
193pub trait NumExt {
194 #[logic]
195 fn leading_zeros_logic(self) -> u32;
196
197 #[logic]
198 fn trailing_zeros_logic(self) -> u32;
199
200 #[logic]
201 fn leading_ones_logic(self) -> u32;
202
203 #[logic]
204 fn trailing_ones_logic(self) -> u32;
205}
206
207macro_rules! spec_unsized {
208 ($type:ty, $zero:expr, $one:expr) => {
209 spec_type!($type);
210
211 impl NumExt for $type {
212 #[logic(opaque)]
213 #[trusted]
214 #[ensures(result <= $type::BITS)]
215 #[ensures((result != $type::BITS) == (self >> ($type::BITS - result - 1u32) == $one))]
216 #[ensures((result == $type::BITS) == (self == $zero))]
217 fn leading_zeros_logic(self) -> u32 {
218 dead
219 }
220
221 #[logic(opaque)]
222 #[trusted]
223 #[ensures(result <= $type::BITS)]
224 #[ensures((result != $type::BITS) == (self << ($type::BITS - result - 1u32) == $one << ($type::BITS - 1u32)))]
225 #[ensures((result == $type::BITS) == (self == $zero))]
226 fn trailing_zeros_logic(self) -> u32 {
227 dead
228 }
229
230 #[logic(opaque)]
231 #[trusted]
232 #[ensures(result <= $type::BITS)]
233 #[ensures((result != $type::BITS) == (!self >> ($type::BITS - result - 1u32) == $zero))]
234 #[ensures((result == $type::BITS) == (self == $type::MAX))]
235 fn leading_ones_logic(self) -> u32 {
236 dead
237 }
238
239 #[logic(opaque)]
240 #[trusted]
241 #[ensures(result <= $type::BITS)]
242 #[ensures((result == $type::BITS) == (!self << ($type::BITS - result - 1u32) == $one << ($type::BITS - 1u32)))]
243 #[ensures((result == $type::BITS) == (self == $type::MAX))]
244 fn trailing_ones_logic(self) -> u32 {
245 dead
246 }
247 }
248
249 extern_spec! {
250 impl $type {
251 #[check(ghost)]
252 #[ensures(if self == $zero { result == (self == $zero) } else { result == (self@ % rhs@ == 0) })]
253 fn is_multiple_of(self, rhs: Self) -> bool;
254
255 #[check(ghost)]
256 #[ensures(result == (self != $zero && self & (self - $one) == $zero))]
257 fn is_power_of_two(self) -> bool;
258
259 #[check(ghost)]
260 #[ensures(result == self.leading_zeros_logic())]
261 fn leading_zeros(self) -> u32;
262
263 #[check(ghost)]
264 #[ensures(result == self.trailing_zeros_logic())]
265 fn trailing_zeros(self) -> u32;
266
267 #[check(ghost)]
268 #[ensures(result == self.leading_ones_logic())]
269 fn leading_ones(self) -> u32;
270
271 #[check(ghost)]
272 #[ensures(result == self.trailing_ones_logic())]
273 fn trailing_ones(self) -> u32;
274 }
275 }
276 };
277}
278
279macro_rules! spec_op_common {
283 (
284 $type:ty,
285 $op:tt,
286 $checked:ident,
287 $wrapping:ident,
288 $saturating:ident,
289 $overflowing:ident,
290 $unchecked:ident
291 ) => {
292 extern_spec! {
293 impl $type {
294 #[allow(dead_code)]
298 #[check(ghost)]
299 #[ensures(
301 (result == None)
302 == ((self@ $op rhs@) < $type::MIN@ || (self@ $op rhs@) > $type::MAX@)
303 )]
304 #[ensures(forall<r: $type> result == Some(r) ==> r@ == (self@ $op rhs@))]
306 fn $checked(self, rhs: $type) -> Option<$type>;
307
308 #[allow(dead_code)]
310 #[check(ghost)]
311 #[ensures(result == self $op rhs)]
312 fn $wrapping(self, rhs: $type) -> $type;
313
314 #[allow(dead_code)]
317 #[check(ghost)]
318 #[ensures(
320 (self@ $op rhs@) >= $type::MIN@ && (self@ $op rhs@) <= $type::MAX@
321 ==> result@ == (self@ $op rhs@)
322 )]
323 #[ensures((self@ $op rhs@) < $type::MIN@ ==> result@ == $type::MIN@)]
325 #[ensures((self@ $op rhs@) > $type::MAX@ ==> result@ == $type::MAX@)]
326 fn $saturating(self, rhs: $type) -> $type;
327
328 #[allow(dead_code)]
331 #[check(ghost)]
332 #[ensures(
334 (self@ $op rhs@) >= $type::MIN@ && (self@ $op rhs@) <= $type::MAX@
335 ==> result.0@ == (self@ $op rhs@)
336 )]
337 #[ensures(
341 exists<k: Int> result.0@ == (self@ $op rhs@) + k * ($type::MAX@ - $type::MIN@ + 1)
342 )]
343 #[ensures(
345 result.1 == ((self@ $op rhs@) < $type::MIN@ || (self@ $op rhs@) > $type::MAX@)
346 )]
347 fn $overflowing(self, rhs: $type) -> ($type, bool);
348
349 #[check(ghost)]
350 #[requires($type::MIN@ <= self@ $op rhs@ && self@ $op rhs@ <= $type::MAX@)]
351 #[ensures(result@ == self@ $op rhs@)]
352 unsafe fn $unchecked(self, rhs: $type) -> $type;
353 }
354 }
355 };
356}
357
358macro_rules! spec_abs_diff {
361 ($unsigned:ty, $signed:ty) => {
362 extern_spec! {
363 impl $unsigned {
364 #[allow(dead_code)]
365 #[check(ghost)]
366 #[ensures(result@ == self@.abs_diff(other@))]
367 fn abs_diff(self, other: $unsigned) -> $unsigned;
368 }
369
370 impl $signed {
371 #[allow(dead_code)]
372 #[check(ghost)]
373 #[ensures(result@ == self@.abs_diff(other@))]
374 fn abs_diff(self, other: $signed) -> $unsigned;
375 }
376 }
377 };
378}
379
380spec_unsized!(u8, 0u8, 1u8);
381spec_unsized!(u16, 0u16, 1u16);
382spec_unsized!(u32, 0u32, 1u32);
383spec_unsized!(u64, 0u64, 1u64);
384spec_unsized!(u128, 0u128, 1u128);
385spec_unsized!(usize, 0usize, 1usize);
386
387spec_type!(i8);
388spec_type!(i16);
389spec_type!(i32);
390spec_type!(i64);
391spec_type!(i128);
392spec_type!(isize);
393
394spec_abs_diff!(u8, i8);
395spec_abs_diff!(u16, i16);
396spec_abs_diff!(u32, i32);
397spec_abs_diff!(u64, i64);
398spec_abs_diff!(u128, i128);
399spec_abs_diff!(usize, isize);