1use crate::{
2 ghost::Plain,
3 logic::ops::{AddLogic, MulLogic, NegLogic, NthBitLogic, SubLogic},
4 prelude::*,
5};
6#[cfg(doc)]
8use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
9
10macro_rules! mach_int {
11 ($t:ty, $ty_nm:expr, $zero:expr, $to_int:literal) => {
12 impl View for $t {
13 type ViewTy = Int;
14 #[logic]
15 #[builtin(concat!($ty_nm, $to_int))]
16 fn view(self) -> Self::ViewTy {
17 dead
18 }
19 }
20
21 impl DeepModel for $t {
22 type DeepModelTy = Int;
23 #[logic(open, inline)]
24 fn deep_model(self) -> Self::DeepModelTy {
25 pearlite! { self@ }
26 }
27 }
28
29 impl Plain for $t {
30 #[trusted]
31 #[ensures(*result == *snap)]
32 #[check(ghost)]
33 #[allow(unused_variables)]
34 fn into_ghost(snap: Snapshot<Self>) -> Ghost<Self> {
35 Ghost::conjure()
36 }
37 }
38
39 extern_spec! {
40 impl Default for $t {
41 #[check(ghost)]
42 #[ensures(result == $zero)]
43 fn default() -> $t { 0 }
44 }
45
46 impl Clone for $t {
47 #[check(ghost)]
48 #[ensures(result == *self)]
49 fn clone(&self) -> $t {
50 *self
51 }
52 }
53 }
54
55 impl AddLogic for $t {
56 type Output = Self;
57 #[logic]
58 #[builtin(concat!($ty_nm, ".add"))]
59 #[allow(unused_variables)]
60 fn add_logic(self, other: Self) -> Self {
61 dead
62 }
63 }
64
65 impl SubLogic for $t {
66 type Output = Self;
67 #[logic]
68 #[builtin(concat!($ty_nm, ".sub"))]
69 #[allow(unused_variables)]
70 fn sub_logic(self, other: Self) -> Self {
71 dead
72 }
73 }
74
75 impl MulLogic for $t {
76 type Output = Self;
77 #[logic]
78 #[builtin(concat!($ty_nm, ".mul"))]
79 #[allow(unused_variables)]
80 fn mul_logic(self, other: Self) -> Self {
81 dead
82 }
83 }
84
85 impl NegLogic for $t {
86 type Output = Self;
87 #[logic]
88 #[builtin(concat!($ty_nm, ".neg"))]
89 fn neg_logic(self) -> Self {
90 dead
91 }
92 }
93
94 impl NthBitLogic for $t {
95 #[logic]
96 #[builtin(concat!($ty_nm, ".nth"))]
97 #[allow(unused_variables)]
98 fn nth_bit(self, n: Int) -> bool {
99 dead
100 }
101 }
102 };
103}
104
105mach_int!(u8, "creusot.int.UInt8$BW$", 0u8, ".t'int");
106mach_int!(u16, "creusot.int.UInt16$BW$", 0u16, ".t'int");
107mach_int!(u32, "creusot.int.UInt32$BW$", 0u32, ".t'int");
108mach_int!(u64, "creusot.int.UInt64$BW$", 0u64, ".t'int");
109mach_int!(u128, "creusot.int.UInt128$BW$", 0u128, ".t'int");
110#[cfg(target_pointer_width = "64")]
111mach_int!(usize, "creusot.int.UInt64$BW$", 0usize, ".t'int");
112#[cfg(target_pointer_width = "32")]
113mach_int!(usize, "creusot.int.UInt32$BW$", 0usize, ".t'int");
114#[cfg(target_pointer_width = "16")]
115mach_int!(usize, "creusot.int.UInt16$BW$", 0usize, ".t'int");
116
117mach_int!(i8, "creusot.int.Int8$BW$", 0i8, ".to_int");
118mach_int!(i16, "creusot.int.Int16$BW$", 0i16, ".to_int");
119mach_int!(i32, "creusot.int.Int32$BW$", 0i32, ".to_int");
120mach_int!(i64, "creusot.int.Int64$BW$", 0i64, ".to_int");
121mach_int!(i128, "creusot.int.Int128$BW$", 0i128, ".to_int");
122#[cfg(target_pointer_width = "64")]
123mach_int!(isize, "creusot.int.Int64$BW$", 0isize, ".to_int");
124#[cfg(target_pointer_width = "32")]
125mach_int!(isize, "creusot.int.Int32$BW$", 0isize, ".to_int");
126#[cfg(target_pointer_width = "16")]
127mach_int!(isize, "creusot.int.Int16$BW$", 0isize, ".to_int");
128
129macro_rules! spec_type {
132 ($type:ty) => {
133 spec_op_common!{$type, +, checked_add, wrapping_add, saturating_add, overflowing_add, unchecked_add}
135 spec_op_common!{$type, -, checked_sub, wrapping_sub, saturating_sub, overflowing_sub, unchecked_sub}
136 spec_op_common!{$type, *, checked_mul, wrapping_mul, saturating_mul, overflowing_mul, unchecked_mul}
137 spec_impl_common!{$type}
138 spec_div_rem!{$type}
139
140 extern_spec! {
141 impl $type {
142 #[allow(dead_code)]
143 #[check(ghost)]
144 #[ensures(result == -self)]
145 fn wrapping_neg(self) -> $type;
146 }
147 }
148
149 extern_spec! {
153 impl $type {
154 #[allow(dead_code)]
155 #[check(ghost)]
156 #[ensures((result == None) == (rhs@ == 0 || (self@ == $type::MIN@ && rhs@ == -1)))]
158 #[ensures(forall<r: $type> result == Some(r) ==> r@ == self@ / rhs@)]
160 fn checked_div(self, rhs: $type) -> Option<$type>;
161
162 #[allow(dead_code)]
163 #[check(ghost)]
164 #[requires(rhs@ != 0)]
166 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result@ == self@)]
168 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result@ == self@ / rhs@)]
170 fn wrapping_div(self, rhs: $type) -> $type;
171
172 #[allow(dead_code)]
173 #[check(ghost)]
174 #[requires(rhs@ != 0)]
176 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result@ == $type::MIN@)]
178 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result@ == self@ / rhs@)]
180 fn saturating_div(self, rhs: $type) -> $type;
181
182 #[allow(dead_code)]
183 #[check(ghost)]
184 #[requires(rhs@ != 0)]
186 #[ensures((self@ == $type::MIN@ && rhs@ == -1) ==> result.0@ == self@)]
188 #[ensures((self@ == $type::MIN@ && rhs@ == -1) || result.0@ == self@ / rhs@)]
190 #[ensures(result.1 == (self@ == $type::MIN@ && rhs@ == -1))]
192 fn overflowing_div(self, rhs: $type) -> ($type, bool);
193 }
194 }
195 };
196}
197
198pub trait NumExt {
199 #[logic]
200 fn leading_zeros_logic(self) -> u32;
201
202 #[logic]
203 fn trailing_zeros_logic(self) -> u32;
204
205 #[logic]
206 fn leading_ones_logic(self) -> u32;
207
208 #[logic]
209 fn trailing_ones_logic(self) -> u32;
210}
211
212macro_rules! spec_unsized {
213 ($type:ty, $zero:expr, $one:expr) => {
214 spec_type!($type);
215
216 impl NumExt for $type {
217 #[logic(opaque)]
218 #[trusted]
219 #[ensures(result <= $type::BITS)]
220 #[ensures((result != $type::BITS) == (self >> ($type::BITS - result - 1u32) == $one))]
221 #[ensures((result == $type::BITS) == (self == $zero))]
222 fn leading_zeros_logic(self) -> u32 {
223 dead
224 }
225
226 #[logic(opaque)]
227 #[trusted]
228 #[ensures(result <= $type::BITS)]
229 #[ensures((result != $type::BITS) == (self << ($type::BITS - result - 1u32) == $one << ($type::BITS - 1u32)))]
230 #[ensures((result == $type::BITS) == (self == $zero))]
231 fn trailing_zeros_logic(self) -> u32 {
232 dead
233 }
234
235 #[logic(opaque)]
236 #[trusted]
237 #[ensures(result <= $type::BITS)]
238 #[ensures((result != $type::BITS) == (!self >> ($type::BITS - result - 1u32) == $zero))]
239 #[ensures((result == $type::BITS) == (self == $type::MAX))]
240 fn leading_ones_logic(self) -> u32 {
241 dead
242 }
243
244 #[logic(opaque)]
245 #[trusted]
246 #[ensures(result <= $type::BITS)]
247 #[ensures((result == $type::BITS) == (!self << ($type::BITS - result - 1u32) == $one << ($type::BITS - 1u32)))]
248 #[ensures((result == $type::BITS) == (self == $type::MAX))]
249 fn trailing_ones_logic(self) -> u32 {
250 dead
251 }
252 }
253
254 extern_spec! {
255 impl $type {
256 #[check(ghost)]
257 #[ensures(if self == $zero { result == (self == $zero) } else { result == (self@ % rhs@ == 0) })]
258 fn is_multiple_of(self, rhs: Self) -> bool;
259
260 #[check(ghost)]
261 #[ensures(result == (self != $zero && self & (self - $one) == $zero))]
262 fn is_power_of_two(self) -> bool;
263
264 #[check(ghost)]
265 #[ensures(result == self.leading_zeros_logic())]
266 fn leading_zeros(self) -> u32;
267
268 #[check(ghost)]
269 #[ensures(result == self.trailing_zeros_logic())]
270 fn trailing_zeros(self) -> u32;
271
272 #[check(ghost)]
273 #[ensures(result == self.leading_ones_logic())]
274 fn leading_ones(self) -> u32;
275
276 #[check(ghost)]
277 #[ensures(result == self.trailing_ones_logic())]
278 fn trailing_ones(self) -> u32;
279 }
280 }
281 };
282}
283
284macro_rules! spec_op_common {
288 (
289 $type:ty,
290 $op:tt,
291 $checked:ident,
292 $wrapping:ident,
293 $saturating:ident,
294 $overflowing:ident,
295 $unchecked:ident
296 ) => {
297 extern_spec! {
298 impl $type {
299 #[allow(dead_code)]
303 #[check(ghost)]
304 #[ensures(
306 (result == None)
307 == ((self@ $op rhs@) < $type::MIN@ || (self@ $op rhs@) > $type::MAX@)
308 )]
309 #[ensures(forall<r: $type> result == Some(r) ==> r@ == (self@ $op rhs@))]
311 fn $checked(self, rhs: $type) -> Option<$type>;
312
313 #[allow(dead_code)]
315 #[check(ghost)]
316 #[ensures(result == self $op rhs)]
317 fn $wrapping(self, rhs: $type) -> $type;
318
319 #[allow(dead_code)]
322 #[check(ghost)]
323 #[ensures(
325 (self@ $op rhs@) >= $type::MIN@ && (self@ $op rhs@) <= $type::MAX@
326 ==> result@ == (self@ $op rhs@)
327 )]
328 #[ensures((self@ $op rhs@) < $type::MIN@ ==> result@ == $type::MIN@)]
330 #[ensures((self@ $op rhs@) > $type::MAX@ ==> result@ == $type::MAX@)]
331 fn $saturating(self, rhs: $type) -> $type;
332
333 #[allow(dead_code)]
336 #[check(ghost)]
337 #[ensures(
339 (self@ $op rhs@) >= $type::MIN@ && (self@ $op rhs@) <= $type::MAX@
340 ==> result.0@ == (self@ $op rhs@)
341 )]
342 #[ensures(
346 exists<k: Int> result.0@ == (self@ $op rhs@) + k * ($type::MAX@ - $type::MIN@ + 1)
347 )]
348 #[ensures(
350 result.1 == ((self@ $op rhs@) < $type::MIN@ || (self@ $op rhs@) > $type::MAX@)
351 )]
352 fn $overflowing(self, rhs: $type) -> ($type, bool);
353
354 #[check(ghost)]
355 #[requires($type::MIN@ <= self@ $op rhs@ && self@ $op rhs@ <= $type::MAX@)]
356 #[ensures(result@ == self@ $op rhs@)]
357 unsafe fn $unchecked(self, rhs: $type) -> $type;
358 }
359 }
360 };
361}
362
363macro_rules! spec_impl_common {
364 ($type:ty) => {
365 spec_impl_common!{Add, add, +, AddAssign, add_assign, +=, $type}
366 spec_impl_common!{Sub, sub, -, SubAssign, sub_assign, -=, $type}
367 spec_impl_common!{Mul, mul, *, MulAssign, mul_assign, *=, $type}
368 };
369 ($op_trait:ident, $op_method:ident, $op:tt, $op_assign_trait:ident, $op_assign_method:ident, $op_assign:tt, $type:ty) => {
370 spec_impl_common!{@ $op_trait, $op_method, $op, $type, $type, $type}
371 spec_impl_common!{@ $op_trait, $op_method, $op, $type, $type, &$type}
372 spec_impl_common!{@ $op_trait, $op_method, $op, $type, &$type, $type}
373 spec_impl_common!{@ $op_trait, $op_method, $op, $type, &$type, &$type}
374 spec_impl_common!{@assign $op_assign_trait, $op_assign_method, $op_assign, $op, $type, $type}
375 spec_impl_common!{@assign $op_assign_trait, $op_assign_method, $op_assign, $op, $type, &$type}
376 };
377 (@ $op_trait:ident, $op_method:ident, $op:tt, $type:ty, $lhs:ty, $rhs:ty) => {
378 extern_spec! {
379 impl core::ops::$op_trait<$rhs> for $lhs {
380 #[requires($type::MIN@ <= self@ $op rhs@ && self@ $op rhs@ <= $type::MAX@)]
381 #[ensures(result@ == self@ $op rhs@)]
382 fn $op_method(self, rhs: $rhs) -> $type {
383 self $op rhs
384 }
385 }
386 }
387 };
388 (@assign $op_assign_trait:ident, $op_assign_method:ident, $op_assign:tt, $op:tt, $type:ty, $rhs:ty) => {
389 extern_spec! {
390 impl core::ops::$op_assign_trait<$rhs> for $type {
391 #[requires($type::MIN@ <= self@ $op rhs@ && self@ $op rhs@ <= $type::MAX@)]
392 #[ensures((^self)@ == self@ $op rhs@)]
393 fn $op_assign_method(&mut self, rhs: $rhs) {
394 *self $op_assign rhs
395 }
396 }
397 }
398 }
399}
400
401macro_rules! spec_div_rem {
402 ($type:ty) => {
403 spec_div_rem!{@ Div, div, /, $type}
404 spec_div_rem!{@ Rem, rem, %, $type}
405 spec_div_rem!{@assign DivAssign, div_assign, /=, /, $type}
406 spec_div_rem!{@assign RemAssign, rem_assign, %=, %, $type}
407 };
408 (@ $divrem_trait:ident, $divrem_method:ident, $op:tt, $type:ty) => {
409 spec_div_rem!{@ $divrem_trait, $divrem_method, $op, $type, $type, $type}
410 spec_div_rem!{@ $divrem_trait, $divrem_method, $op, $type, $type, &$type}
411 spec_div_rem!{@ $divrem_trait, $divrem_method, $op, $type, &$type, $type}
412 spec_div_rem!{@ $divrem_trait, $divrem_method, $op, $type, &$type, &$type}
413 };
414 (@ $divrem_trait:ident, $divrem_method:ident, $op:tt, $type:ty, $lhs:ty, $rhs:ty) => {
415 extern_spec! {
416 impl core::ops::$divrem_trait<$rhs> for $lhs {
417 #[requires(rhs@ != 0)]
418 #[requires(!(self@ == $type::MIN@ && rhs@ == -1))]
419 #[ensures(result@ == self@ $op rhs@)]
420 fn $divrem_method(self, rhs: $rhs) -> $type {
421 self $op rhs
422 }
423 }
424 }
425 };
426 (@assign $divrem_assign_trait:ident, $divrem_assign_method:ident, $op_assign:tt, $op:tt, $type:ty) => {
427 spec_div_rem!{@assign $divrem_assign_trait, $divrem_assign_method, $op_assign, $op, $type, $type}
428 spec_div_rem!{@assign $divrem_assign_trait, $divrem_assign_method, $op_assign, $op, $type, &$type}
429 };
430 (@assign $divrem_assign_trait:ident, $divrem_assign_method:ident, $op_assign:tt, $op:tt, $type:ty, $rhs:ty) => {
431 extern_spec! {
432 impl core::ops::$divrem_assign_trait<$rhs> for $type {
433 #[requires(rhs@ != 0)]
434 #[requires(!(*self == $type::MIN && rhs@ == -1))]
435 #[ensures((^self)@ == self@ $op rhs@)]
436 fn $divrem_assign_method(&mut self, rhs: $rhs) {
437 *self $op_assign rhs
438 }
439 }
440 }
441 };
442}
443
444macro_rules! spec_abs_diff {
447 ($unsigned:ty, $signed:ty) => {
448 extern_spec! {
449 impl $unsigned {
450 #[allow(dead_code)]
451 #[check(ghost)]
452 #[ensures(result@ == self@.abs_diff(other@))]
453 fn abs_diff(self, other: $unsigned) -> $unsigned;
454 }
455
456 impl $signed {
457 #[allow(dead_code)]
458 #[check(ghost)]
459 #[ensures(result@ == self@.abs_diff(other@))]
460 fn abs_diff(self, other: $signed) -> $unsigned;
461 }
462 }
463 };
464}
465
466spec_unsized!(u8, 0u8, 1u8);
467spec_unsized!(u16, 0u16, 1u16);
468spec_unsized!(u32, 0u32, 1u32);
469spec_unsized!(u64, 0u64, 1u64);
470spec_unsized!(u128, 0u128, 1u128);
471spec_unsized!(usize, 0usize, 1usize);
472
473spec_type!(i8);
474spec_type!(i16);
475spec_type!(i32);
476spec_type!(i64);
477spec_type!(i128);
478spec_type!(isize);
479
480spec_abs_diff!(u8, i8);
481spec_abs_diff!(u16, i16);
482spec_abs_diff!(u32, i32);
483spec_abs_diff!(u64, i64);
484spec_abs_diff!(u128, i128);
485spec_abs_diff!(usize, isize);