1pub const WIDTH: usize = 16;
2#[macro_use]
3mod cfg_macros;
4
5#[cfg(all(mirai, not(feature = "verify")))]
6compile_error!(
7 "To run mirai on `swift-check` you must enable the `verify` feature: \n\
8 `cargo mirai --tests --features verify`"
9);
10
11macro_rules! impl_bit_ops {
12 ($ident:ident) => {
13 impl core::ops::BitAnd for $ident {
14 type Output = Self;
15
16 #[inline(always)]
17 fn bitand(self, rhs: Self) -> Self::Output {
18 $ident(self.0 & rhs.0)
19 }
20 }
21
22 impl core::ops::BitOr for $ident {
23 type Output = Self;
24
25 #[inline(always)]
26 fn bitor(self, rhs: Self) -> Self::Output {
27 $ident(self.0 | rhs.0)
28 }
29 }
30 };
31}
32
33cfg_verify!(
34 pub(crate) fn is_aligned(ptr: *const Ptr) -> bool {
35 byte_ptr(ptr).align_offset(WIDTH) == 0
36 }
37 macro_rules! contract {
38 ($kind:ident!($args:expr)) => {
39 mirai_annotations::$kind!($args)
40 };
41 ($expr:expr) => {
42 $expr
43 };
44 }
45);
46
47cfg_runtime!(
48 #[allow(unused_macros)]
49 macro_rules! contract {
50 ($kind:ident!($args:expr)) => {};
51 ($expr:expr) => {};
52 }
53);
54
55cfg_neon!(
56 pub mod aarch64;
57 pub use aarch64 as arch;
58);
59
60cfg_sse!(
61 pub mod x86_64;
62 pub use x86_64 as arch;
63);
64
65cfg_simd128!(
66 pub mod wasm;
67 pub use wasm as arch;
68);
69
70cfg_fallback!(
71 pub mod fallback;
72 pub use fallback as arch;
73);
74
75#[doc(hidden)]
76pub use arch::{
77 eq, not, xor, or, and, splat, byte_ptr, simd_ptr, load_partial, load_aligned, maybe_aligned_load
78};
79
80#[doc(hidden)]
81pub use arch::{MoveMask, Ptr, STEP, STEP_SIZE};
82
83pub use arch::Vector;
84pub use arch::{load, load_unchecked};
85
86cfg_simd!(
87 #[doc(hidden)]
88 pub mod simd_scan;
89 #[doc(hidden)]
90 pub use simd_scan as scan;
91);
92
93cfg_fallback!(
94 #[doc(hidden)]
95 pub mod fallback_scan;
96 #[doc(hidden)]
97 pub use fallback_scan as scan;
98);
99
100cfg_i8!(
101 macro_rules! impl_cmp {
102 (
103 $CONST:ident,
104 overflow => $handle_overflow:expr,
105 default => $handle_non_overflow:expr
106 $(, max => $handle_max:expr)?
107 $(, min => $handle_min:expr)?
108 $(,)?
109 ) => {
110 match $CONST {
111 $(255 => $handle_max,)?
112 128..=255 => $handle_overflow,
113 $(0 => $handle_min,)?
114 _ => $handle_non_overflow
115 }
116 };
117 }
118
119 macro_rules! impl_gt {
120 ($MIN:ident, $gt:ident, $handle_max:expr $(, $handle_min:expr)? $(,)?) => {
121 impl_cmp!(
122 $MIN,
123 overflow => {
124 move |data| {
126 and(
127 arch::less_than(data, splat(0)),
128 arch::$gt(data, splat($MIN))
129 )
130 }
131 },
132 default => {
133 move |data| {
136 or(
137 arch::less_than(data, splat(0)),
138 arch::$gt(data, splat($MIN))
139 )
140 }
141 },
142 max => $handle_max
143 $(, min => $handle_min)?
144 )
145 };
146 }
147
148 #[doc(hidden)] #[inline(always)]
149 pub const fn greater_than<const MIN: u8>() -> impl Fn(Vector) -> Vector {
150 unsafe { impl_gt!(
151 MIN,
152 greater_than,
153 move |_| { splat(0) }
154 ) }
155 }
156
157 #[doc(hidden)] #[inline(always)]
158 pub const fn greater_than_or_eq<const MIN: u8>() -> impl Fn(Vector) -> Vector {
159 unsafe { impl_gt!(
160 MIN,
161 greater_than_or_eq,
162 move |data| { eq(data, splat(255)) },
163 move |_| {
164 splat(0xFF)
166 }
167 ) }
168 }
169
170 macro_rules! impl_lt {
171 ($MAX:ident, $lt:ident, $handle_min:expr $(, $handle_max:expr)? $(,)?) => {
172 impl_cmp!(
173 $MAX,
174 overflow => move |data| unsafe {
175 or(
177 arch::greater_than_or_eq(data, splat(0)),
178 arch::$lt(data, splat($MAX))
179 )
180 },
181 default => move |data| unsafe {
182 and(
185 arch::greater_than_or_eq(data, splat(0)),
186 arch::$lt(data, splat(MAX))
187 )
188 },
189 $(max => $handle_max,)?
190 min => $handle_min
191 )
192 };
193 }
194
195 #[doc(hidden)] #[inline(always)]
196 pub const fn less_than<const MAX: u8>() -> impl Fn(Vector) -> Vector {
197 impl_lt!(
198 MAX,
199 less_than,
200 move |_| unsafe {
201 splat(0)
203 }
204 )
205 }
206
207 #[doc(hidden)] #[inline(always)]
208 pub const fn less_than_or_eq<const MAX: u8>() -> impl Fn(Vector) -> Vector {
209 impl_lt!(
210 MAX,
211 less_than_or_eq,
212 move |data| unsafe {
213 eq(data, splat(0))
215 },
216 move |_| unsafe {
217 splat(0xFF)
219 }
220 )
221 }
222
223 macro_rules! impl_range_cast {
224 ($MIN:ident, $MAX:ident, $gt:ident, $lt:ident, $eq:expr, $max_128:expr) => {
225 match ($MIN, $MAX) {
226 _ if $MIN == $MAX => $eq,
227 (0..=127, 129..=255) => {
228 move |data| unsafe {
230 or(
231 arch::$gt(data, splat($MIN)),
232 arch::$lt(data, splat($MAX))
233 )
234 }
235 },
236 (0..=127, 128) => $max_128,
237 _ => {
238 move |data| unsafe {
240 and(
241 arch::$gt(data, splat($MIN)),
242 arch::$lt(data, splat($MAX))
243 )
244 }
245 }
246 }
247 };
248 }
249
250 #[doc(hidden)] #[inline(always)]
251 pub const fn range<const MIN: u8, const MAX: u8>() -> impl Fn(Vector) -> Vector {
252 impl_range_cast!(MIN, MAX, greater_than_or_eq, less_than_or_eq,
253 move |data| unsafe { eq(data, splat(MIN)) },
254 move |data| unsafe {
255 or(
256 arch::greater_than_or_eq(data, splat(MIN)),
257 eq(data, splat(MAX))
258 )
259 }
260 )
261 }
262
263 #[doc(hidden)] #[inline(always)]
264 pub const fn exclusive_range<const MIN: u8, const MAX: u8>() -> impl Fn(Vector) -> Vector {
265 if MIN.abs_diff(MAX) == 1 {
266 move |_data: Vector| -> Vector { unsafe { splat(0) } }
267 } else {
268 impl_range_cast!(
269 MIN, MAX, greater_than, less_than, move |_| unsafe { splat(0) },
270 move |data| unsafe { arch::greater_than(data, splat(MIN)) }
271 )
272 }
273 }
274);
275
276cfg_u8!(
277 #[doc(hidden)] #[inline(always)]
278 pub const fn less_than<const MAX: u8>() -> impl Fn(Vector) -> Vector {
279 match MAX {
280 0 => move |_| unsafe {
281 splat(0)
283 },
284 _ => move |data| unsafe {
285 arch::less_than(data, splat(MAX))
286 }
287 }
288 }
289
290 #[doc(hidden)] #[inline(always)]
291 pub const fn less_than_or_eq<const MAX: u8>() -> impl Fn(Vector) -> Vector {
292 match MAX {
293 255 => move |_| unsafe {
294 splat(0xFF)
296 },
297 _ => move |data| unsafe {
298 arch::less_than_or_eq(data, splat(MAX))
299 }
300 }
301 }
302
303 #[doc(hidden)] #[inline(always)]
304 pub const fn greater_than<const MIN: u8>() -> impl Fn(Vector) -> Vector {
305 match MIN {
306 255 => move |_| unsafe {
307 splat(0)
309 },
310 _ => move |data| unsafe {
311 arch::greater_than(data, splat(MIN))
312 }
313 }
314 }
315
316 #[doc(hidden)] #[inline(always)]
317 pub const fn greater_than_or_eq<const MIN: u8>() -> impl Fn(Vector) -> Vector {
318 match MIN {
319 0 => move |_| unsafe {
320 splat(0xFF)
322 },
323 _ => move |data| unsafe {
324 arch::greater_than_or_eq(data, splat(MIN))
325 }
326 }
327 }
328
329 #[doc(hidden)] #[inline(always)]
330 pub const fn range<const MIN: u8, const MAX: u8>() -> impl Fn(Vector) -> Vector {
331 match (MIN, MAX) {
332 _ if MIN == MAX => move |data| unsafe { eq(data, splat(MIN)) },
333 _ => move |data| unsafe {
334 and(
335 arch::greater_than_or_eq(data, splat(MIN)),
336 arch::less_than_or_eq(data, splat(MAX))
337 )
338 }
339 }
340 }
341
342 #[doc(hidden)] #[inline(always)]
343 pub const fn exclusive_range<const MIN: u8, const MAX: u8>() -> impl Fn(Vector) -> Vector {
344 match (MIN, MAX, MIN.abs_diff(MAX)) {
345 (_, _, 1) |
346 (_, _, _) if MIN == MAX => move |_| unsafe { splat(0) },
347 _ => move |data| unsafe {
348 and(
349 arch::greater_than(data, splat(MIN)),
350 arch::less_than(data, splat(MAX))
351 )
352 }
353 }
354 }
355);