Skip to main content

core_models/core_arch/
x86.rs

1//! A (partial) Rust-based model of [`core::arch::x86`] and [`core::arch::x86_64`].
2//!
3//! This module provides a purely Rust implementation of selected operations from
4//! `core::arch::x86` and `core::arch::x86_64`.
5//!
6//! # Guide — Adding a New Intrinsic to the `core_arch::x86` Model
7//!
8//! ## Introduction — Why & How We Model SIMD
9//!
10//! In order to verify code that uses SIMD, every intrinsic has to be modeled.  
11//! Your crate already provides the scaffolding:
12//!
13//! * **`src/core_arch/x86/opaque.rs`** — list of **empty** intrinsics (stubs).  
14//! * **`src/core_arch/x86/{sse2,avx,avx2,…}.rs`** — where *real* models belong.
15//!
16//! This guide shows an end‑to‑end path:
17//!
18//! 1. **Locate** the intrinsic in upstream docs.  
19//! 2. **Pick a representation** (bit‑vector, integer vector, or both).  
20//! 3. **Move** the item out of `opaque.rs` (if it is defined here).  
21//! 4. **Implement** the model and (optionally) an interpretation with a lift lemma.  
22//! 5. **Test**.  
23//!
24//! ## Choosing Your Semantic Representation
25//!
26//! | Representation | Good for | Extra work |
27//! |----------------|----------|------------|
28//! | **Bit‑vector** (`BitVec<256>`) | Bit-wise proofs, shuffles, masking | None |
29//! | **Integer vector** (`i32x8`, `i64x4`, …) | Lane‑wise integer reasoning | Add lift lemma |
30//!
31//! ## Driving Example – `_mm256_mul_epi32`
32//!
33//! We add the AVX2 "multiply packed 32‑bit integers" intrinsic.
34//!
35//!  1. *Locate* in <https://doc.rust-lang.org/stable/core/arch/x86/> → click **Source**. Path shows `core_arch/src/x86/avx2.rs`: this intrinsics needs to be added to the  `avx2` sub module of `x86.rs`.
36//!  2. **Delete the stub** from `opaque.rs`
37//!  3. **Implement** the bit‑vector spec. (file `x86.rs`, module `avx2`)
38//!  4. *(Optional)* add an `i32x8` interpretation + lift lemma. (file `x86/interpretations.rs`)
39//!  5. **Unit‑test** equivalence.
40//!
41//! ### (step 3) Bit‑Vector Model (if needed)
42//! In the case of `_mm256_mul_epi32` you probably don't want to have a bit vec model. You would have to write a bit vec addition primitive first.
43//! In this case, we just declare an opaque `_mm256_mul_epi32` in `x86::avx2`.
44//!
45//! ```compile_fail
46//! #[hax_lib::opaque]
47//! pub fn _mm256_mul_epi32(_: __m256i, _: __m256i) -> __m256i {
48//!     unimplemented!()
49//! }
50//! ```
51//!
52//! ### (step 4) Integer‑Vector Interpretation & Lift Lemma (if needed)
53//! In `minicore::core_arch::x86::interpretations::int_vec`, we add the following model:
54//!
55//! ```compile_fail
56//! pub fn _mm256_mul_epi32(x: i32x8, y: i32x8) -> i64x4 {
57//!     i64x4::from_fn(|i| (x[i * 2] as i64) * (y[i * 2] as i64))
58//! }
59//! ```
60//!
61//! And a lift lemma in `minicore::core_arch::x86::interpretations::int_vec::lemmas`:
62//! ```compile_fail
63//! mk_lift_lemma!(
64//!     _mm256_mul_epi32(x: __m256i, y: __m256i) ==
65//!     __m256i::from(super::_mm256_mul_epi32(super::i32x8::from(x), super::i32x8::from(y)))
66//! );
67//! ```
68//!
69//! ### (step 5) Unit Test
70//! In `minicore::core_arch::x86::interpretations::int_vec::tests`:
71//! ```compile_fail
72//! mk!(_mm256_mul_epi32(x: BitVec, y: BitVec));
73//! ```
74//!
75//! `mk!` will create a test function that tests that our model of `_mm256_mul_epi32` and its original definition are equivalent for 1000 random values of `x` and `y`.
76//!
77#![allow(clippy::too_many_arguments)]
78
79pub mod interpretations;
80use crate::abstractions::{bit::*, bitvec::*, funarr::*};
81
82pub(crate) mod upstream {
83    #[cfg(target_arch = "x86")]
84    pub use core::arch::x86::*;
85    #[cfg(target_arch = "x86_64")]
86    pub use core::arch::x86_64::*;
87}
88
89/// Conversions impls between `BitVec<N>` and `__mNi` types.
90#[hax_lib::exclude]
91#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
92mod conversions {
93    use super::upstream::{
94        __m128i, __m256, __m256i, _mm256_castps_si256, _mm256_castsi256_ps, _mm256_loadu_si256,
95        _mm256_storeu_si256, _mm_loadu_si128, _mm_storeu_si128,
96    };
97    use super::BitVec;
98
99    impl From<BitVec<256>> for __m256i {
100        fn from(bv: BitVec<256>) -> __m256i {
101            let bv: &[u8] = &bv.to_vec()[..];
102            unsafe { _mm256_loadu_si256(bv.as_ptr() as *const _) }
103        }
104    }
105    impl From<BitVec<256>> for __m256 {
106        fn from(bv: BitVec<256>) -> __m256 {
107            let bv: &[u8] = &bv.to_vec()[..];
108            unsafe { _mm256_castsi256_ps(_mm256_loadu_si256(bv.as_ptr() as *const _)) }
109        }
110    }
111
112    impl From<BitVec<128>> for __m128i {
113        fn from(bv: BitVec<128>) -> __m128i {
114            let slice: &[u8] = &bv.to_vec()[..];
115            unsafe { _mm_loadu_si128(slice.as_ptr() as *const __m128i) }
116        }
117    }
118
119    impl From<__m256i> for BitVec<256> {
120        fn from(vec: __m256i) -> BitVec<256> {
121            let mut v = [0u8; 32];
122            unsafe {
123                _mm256_storeu_si256(v.as_mut_ptr() as *mut _, vec);
124            }
125            BitVec::from_slice(&v[..], 8)
126        }
127    }
128
129    impl From<__m256> for BitVec<256> {
130        fn from(vec: __m256) -> BitVec<256> {
131            let mut v = [0u8; 32];
132            unsafe {
133                _mm256_storeu_si256(v.as_mut_ptr() as *mut _, _mm256_castps_si256(vec));
134            }
135            BitVec::from_slice(&v[..], 8)
136        }
137    }
138
139    impl From<__m128i> for BitVec<128> {
140        fn from(vec: __m128i) -> BitVec<128> {
141            let mut v = [0u8; 16];
142            unsafe {
143                _mm_storeu_si128(v.as_mut_ptr() as *mut _, vec);
144            }
145            BitVec::from_slice(&v[..], 8)
146        }
147    }
148}
149
150#[hax_lib::fstar::replace(
151    r#"
152    unfold type t_e_ee_m256i = $:{__m256i}
153    unfold type t_e_ee_m128i = $:{__m128i}
154"#
155)]
156const _: () = {};
157
158/// 256-bit wide integer vector type.
159/// Models `core::arch::x86::__m256i` or `core::arch::x86_64::__m256i` (the __m256i type defined by Intel, representing a 256-bit SIMD register).
160#[allow(non_camel_case_types)]
161pub type __m256i = BitVec<256>;
162
163/// 128-bit wide integer vector type.
164/// Models `core::arch::x86::__m128i` or `core::arch::x86_64::__m128i` (the __m128i type defined by Intel, representing a 128-bit SIMD register).
165#[allow(non_camel_case_types)]
166pub type __m128i = BitVec<128>;
167
168/// 256-bit wide vector type, which can be interpreted as 8 32 bit floating point values.
169/// Models `core::arch::x86::__m256` or `core::arch::x86_64::__m256`, but since we do not have use and fully support floating points yet, it is treated the same as __m256i.
170#[allow(non_camel_case_types)]
171pub type __m256 = __m256i;
172
173pub use ssse3::*;
174pub mod ssse3 {
175    use super::*;
176    #[hax_lib::opaque]
177    pub fn _mm_shuffle_epi8(vector: __m128i, indexes: __m128i) -> __m128i {
178        let indexes = indexes.to_vec().try_into().unwrap();
179        extra::mm_shuffle_epi8_u8_array(vector, indexes)
180    }
181}
182pub use sse2::*;
183pub mod sse2 {
184    /// This intrinsics is not extracted via hax currently since it cannot hanlde raw pointers.
185    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadu_si128&ig_expand=4106)
186    #[hax_lib::exclude]
187    pub unsafe fn _mm_loadu_si128(_mem_addr: *const __m128i) -> __m128i {
188        unimplemented!()
189    }
190
191    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_packs_epi16)
192    #[hax_lib::opaque]
193    pub fn _mm_packs_epi16(_: __m128i, _: __m128i) -> __m128i {
194        unimplemented!()
195    }
196
197    use super::*;
198    #[hax_lib::opaque]
199    pub fn _mm_set_epi8(
200        _e15: i8,
201        _e14: i8,
202        _e13: i8,
203        _e12: i8,
204        _e11: i8,
205        _e10: i8,
206        _e9: i8,
207        _e8: i8,
208        _e7: i8,
209        _e6: i8,
210        _e5: i8,
211        _e4: i8,
212        _e3: i8,
213        _e2: i8,
214        _e1: i8,
215        _e0: i8,
216    ) -> __m128i {
217        todo!()
218    }
219
220    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set1_epi16)
221    #[hax_lib::opaque]
222    pub fn _mm_set1_epi16(_: i16) -> __m128i {
223        unimplemented!()
224    }
225    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set_epi32)
226    #[hax_lib::opaque]
227    pub fn _mm_set_epi32(_: i32, _: i32, _: i32, _: i32) -> __m128i {
228        unimplemented!()
229    }
230
231    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_epi16)
232    #[hax_lib::opaque]
233    pub fn _mm_add_epi16(_: __m128i, _: __m128i) -> __m128i {
234        unimplemented!()
235    }
236    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_epi16)
237    #[hax_lib::opaque]
238    pub fn _mm_sub_epi16(_: __m128i, _: __m128i) -> __m128i {
239        unimplemented!()
240    }
241    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mullo_epi16)
242    #[hax_lib::opaque]
243    pub fn _mm_mullo_epi16(_: __m128i, _: __m128i) -> __m128i {
244        unimplemented!()
245    }
246
247    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhi_epi16)
248    #[hax_lib::opaque]
249    pub fn _mm_mulhi_epi16(_: __m128i, _: __m128i) -> __m128i {
250        unimplemented!()
251    }
252    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_epi64)
253    #[hax_lib::opaque]
254    pub fn _mm_srli_epi64<const IMM8: i32>(_: __m128i) -> __m128i {
255        unimplemented!()
256    }
257
258    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movemask_epi8)
259    #[hax_lib::opaque]
260    pub fn _mm_movemask_epi8(_: __m128i) -> i32 {
261        unimplemented!()
262    }
263
264    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_unpacklo_epi64)
265    #[hax_lib::opaque]
266    pub fn _mm_unpacklo_epi64(_: __m128i, _: __m128i) -> __m128i {
267        unimplemented!()
268    }
269
270    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_unpackhi_epi64)
271    #[hax_lib::opaque]
272    pub fn _mm_unpackhi_epi64(_: __m128i, _: __m128i) -> __m128i {
273        unimplemented!()
274    }
275
276    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi32)
277    #[hax_lib::opaque]
278    pub fn _mm_shuffle_epi32<const IMM8: i32>(_: __m128i) -> __m128i {
279        unimplemented!()
280    }
281
282    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_si128)
283    #[hax_lib::opaque]
284    pub fn _mm_srli_si128<const IMM8: i32>(_: __m128i) -> __m128i {
285        unimplemented!()
286    }
287
288    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_slli_si128)
289    #[hax_lib::opaque]
290    pub fn _mm_slli_si128<const IMM8: i32>(_: __m128i) -> __m128i {
291        unimplemented!()
292    }
293
294    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_xor_si128)
295    #[hax_lib::opaque]
296    pub fn _mm_xor_si128(_: __m128i, _: __m128i) -> __m128i {
297        unimplemented!()
298    }
299
300    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_setzero_si128)
301    #[hax_lib::opaque]
302    pub fn _mm_setzero_si128() -> __m128i {
303        unimplemented!()
304    }
305}
306
307pub use avx::*;
308pub mod avx {
309    /// This intrinsics is not extracted via hax currently since it cannot hanlde raw pointers.
310    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_storeu_si256)
311    #[hax_lib::exclude]
312    pub unsafe fn _mm256_storeu_si256(_mem_addr: *mut __m256i, _a: __m256i) {
313        unimplemented!()
314    }
315
316    /// This intrinsics is not extracted via hax currently since it cannot hanlde raw pointers.
317    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_loadu_si256)
318    #[hax_lib::exclude]
319    pub unsafe fn _mm256_loadu_si256(_mem_addr: *const __m256i) -> __m256i {
320        unimplemented!()
321    }
322
323    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_set1_epi64x)
324    #[hax_lib::opaque]
325    pub fn _mm256_set1_epi64x(_: i64) -> __m256i {
326        unimplemented!()
327    }
328    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_set_epi64x)
329    #[hax_lib::opaque]
330    pub fn _mm256_set_epi64x(_: i64, _: i64, _: i64, _: i64) -> __m256i {
331        unimplemented!()
332    }
333    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_blendv_ps)
334    #[hax_lib::opaque]
335    pub fn _mm256_blendv_ps(_: __m256, _: __m256, _: __m256) -> __m256 {
336        unimplemented!()
337    }
338    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_castsi128_si256)
339    #[hax_lib::opaque]
340    pub fn _mm256_castsi128_si256(_: __m128i) -> __m256i {
341        unimplemented!()
342    }
343    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_testz_si256)
344    #[hax_lib::opaque]
345    pub fn _mm256_testz_si256(_: __m256i, _: __m256i) -> i32 {
346        unimplemented!()
347    }
348    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_castsi256_ps)
349    #[hax_lib::opaque]
350    pub fn _mm256_castsi256_ps(_: __m256i) -> __m256 {
351        unimplemented!()
352    }
353    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_castps_si256)
354    #[hax_lib::opaque]
355    pub fn _mm256_castps_si256(_: __m256) -> __m256i {
356        unimplemented!()
357    }
358    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_movemask_ps)
359    #[hax_lib::opaque]
360    pub fn _mm256_movemask_ps(_: __m256) -> i32 {
361        unimplemented!()
362    }
363
364    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_setzero_si256)
365    #[hax_lib::opaque]
366    pub fn _mm256_setzero_si256() -> __m256i {
367        BitVec::from_fn(|_| Bit::Zero)
368    }
369
370    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_set_m128i)
371    #[hax_lib::opaque]
372    pub fn _mm256_set_m128i(hi: __m128i, lo: __m128i) -> __m256i {
373        BitVec::from_fn(|i| if i < 128 { lo[i] } else { hi[i - 128] })
374    }
375
376    pub use super::*;
377    pub fn _mm256_castsi256_si128(vector: __m256i) -> __m128i {
378        BitVec::from_fn(|i| vector[i])
379    }
380
381    /// This is opaque to Hax: it is defined only via the integer
382    /// interpretation. See `interpretations::int_vec::_mm256_set1_epi32`.
383    #[hax_lib::opaque]
384    pub fn _mm256_set1_epi32(_: i32) -> __m256i {
385        unimplemented!()
386    }
387
388    /// This is opaque to Hax: we have lemmas about this intrinsics
389    /// composed with others. See e.g. `_rw_mm256_sllv_epi32`.
390    #[hax_lib::opaque]
391    pub fn _mm256_set_epi32(
392        _e0: i32,
393        _e1: i32,
394        _e2: i32,
395        _e3: i32,
396        _e4: i32,
397        _e5: i32,
398        _e6: i32,
399        _e7: i32,
400    ) -> __m256i {
401        todo!()
402    }
403
404    /// This is opaque to Hax: we have lemmas about this intrinsics
405    /// composed with others. See e.g. `_rw_mm256_mullo_epi16_shifts`.
406    #[hax_lib::opaque]
407    pub fn _mm256_set_epi16(
408        _e00: i16,
409        _e01: i16,
410        _e02: i16,
411        _e03: i16,
412        _e04: i16,
413        _e05: i16,
414        _e06: i16,
415        _e07: i16,
416        _e08: i16,
417        _e09: i16,
418        _e10: i16,
419        _e11: i16,
420        _e12: i16,
421        _e13: i16,
422        _e14: i16,
423        _e15: i16,
424    ) -> __m256i {
425        todo!()
426    }
427
428    /// This is opaque to Hax: we have lemmas about this intrinsics
429    /// composed with others. See e.g. `_rw_mm256_shuffle_epi8`.
430    #[hax_lib::opaque]
431    pub fn _mm256_set_epi8(
432        _e00: i8,
433        _e01: i8,
434        _e02: i8,
435        _e03: i8,
436        _e04: i8,
437        _e05: i8,
438        _e06: i8,
439        _e07: i8,
440        _e08: i8,
441        _e09: i8,
442        _e10: i8,
443        _e11: i8,
444        _e12: i8,
445        _e13: i8,
446        _e14: i8,
447        _e15: i8,
448        _e16: i8,
449        _e17: i8,
450        _e18: i8,
451        _e19: i8,
452        _e20: i8,
453        _e21: i8,
454        _e22: i8,
455        _e23: i8,
456        _e24: i8,
457        _e25: i8,
458        _e26: i8,
459        _e27: i8,
460        _e28: i8,
461        _e29: i8,
462        _e30: i8,
463        _e31: i8,
464    ) -> __m256i {
465        todo!()
466    }
467    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_set1_epi16)
468    #[hax_lib::opaque]
469    pub fn _mm256_set1_epi16(_: i16) -> __m256i {
470        unimplemented!()
471    }
472}
473pub use avx2::*;
474pub mod avx2 {
475    use super::*;
476
477    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_blend_epi32)
478    #[hax_lib::opaque]
479    pub fn _mm256_blend_epi32<const IMM8: i32>(_: __m256i, _: __m256i) -> __m256i {
480        unimplemented!()
481    }
482    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_shuffle_epi32)
483    #[hax_lib::opaque]
484    pub fn _mm256_shuffle_epi32<const MASK: i32>(_: __m256i) -> __m256i {
485        unimplemented!()
486    }
487    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sub_epi32)
488    #[hax_lib::opaque]
489    pub fn _mm256_sub_epi32(_: __m256i, _: __m256i) -> __m256i {
490        unimplemented!()
491    }
492    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mul_epi32)
493    #[hax_lib::opaque]
494    pub fn _mm256_mul_epi32(_: __m256i, _: __m256i) -> __m256i {
495        unimplemented!()
496    }
497
498    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_add_epi16)
499    #[hax_lib::opaque]
500    pub fn _mm256_add_epi16(_: __m256i, _: __m256i) -> __m256i {
501        unimplemented!()
502    }
503    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_madd_epi16)
504    #[hax_lib::opaque]
505    pub fn _mm256_madd_epi16(_: __m256i, _: __m256i) -> __m256i {
506        unimplemented!()
507    }
508    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_add_epi32)
509    #[hax_lib::opaque]
510    pub fn _mm256_add_epi32(_: __m256i, _: __m256i) -> __m256i {
511        unimplemented!()
512    }
513    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_add_epi64)
514    #[hax_lib::opaque]
515    pub fn _mm256_add_epi64(_: __m256i, _: __m256i) -> __m256i {
516        unimplemented!()
517    }
518    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_abs_epi32)
519    #[hax_lib::opaque]
520    pub fn _mm256_abs_epi32(_: __m256i) -> __m256i {
521        unimplemented!()
522    }
523    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sub_epi16)
524    #[hax_lib::opaque]
525    pub fn _mm256_sub_epi16(_: __m256i, _: __m256i) -> __m256i {
526        unimplemented!()
527    }
528
529    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_cmpgt_epi16)
530    #[hax_lib::opaque]
531    pub fn _mm256_cmpgt_epi16(_: __m256i, _: __m256i) -> __m256i {
532        unimplemented!()
533    }
534    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_cmpgt_epi32)
535    #[hax_lib::opaque]
536    pub fn _mm256_cmpgt_epi32(_: __m256i, _: __m256i) -> __m256i {
537        unimplemented!()
538    }
539    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_cmpeq_epi32)
540    #[hax_lib::opaque]
541    pub fn _mm256_cmpeq_epi32(_: __m256i, _: __m256i) -> __m256i {
542        unimplemented!()
543    }
544    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sign_epi32)
545    #[hax_lib::opaque]
546    pub fn _mm256_sign_epi32(_: __m256i, _: __m256i) -> __m256i {
547        unimplemented!()
548    }
549
550    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mullo_epi32)
551    #[hax_lib::opaque]
552    pub fn _mm256_mullo_epi32(_: __m256i, _: __m256i) -> __m256i {
553        unimplemented!()
554    }
555    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhi_epi16)
556    #[hax_lib::opaque]
557    pub fn _mm256_mulhi_epi16(_: __m256i, _: __m256i) -> __m256i {
558        unimplemented!()
559    }
560    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mul_epu32)
561    #[hax_lib::opaque]
562    pub fn _mm256_mul_epu32(_: __m256i, _: __m256i) -> __m256i {
563        unimplemented!()
564    }
565    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_and_si256)
566    #[hax_lib::opaque]
567    pub fn _mm256_and_si256(_: __m256i, _: __m256i) -> __m256i {
568        unimplemented!()
569    }
570    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_or_si256)
571    #[hax_lib::opaque]
572    pub fn _mm256_or_si256(_: __m256i, _: __m256i) -> __m256i {
573        unimplemented!()
574    }
575
576    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_xor_si256)
577    #[hax_lib::opaque]
578    pub fn _mm256_xor_si256(_: __m256i, _: __m256i) -> __m256i {
579        unimplemented!()
580    }
581    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srai_epi16)
582    #[hax_lib::opaque]
583    pub fn _mm256_srai_epi16<const IMM8: i32>(_: __m256i) -> __m256i {
584        unimplemented!()
585    }
586    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srai_epi32)
587    #[hax_lib::opaque]
588    pub fn _mm256_srai_epi32<const IMM8: i32>(_: __m256i) -> __m256i {
589        unimplemented!()
590    }
591    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srli_epi16)
592    #[hax_lib::opaque]
593    pub fn _mm256_srli_epi16<const IMM8: i32>(_: __m256i) -> __m256i {
594        unimplemented!()
595    }
596    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srli_epi32)
597    #[hax_lib::opaque]
598    pub fn _mm256_srli_epi32<const IMM8: i32>(_: __m256i) -> __m256i {
599        unimplemented!()
600    }
601
602    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_slli_epi32)
603    #[hax_lib::opaque]
604    pub fn _mm256_slli_epi32<const IMM8: i32>(_: __m256i) -> __m256i {
605        unimplemented!()
606    }
607    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permute4x64_epi64)
608    #[hax_lib::opaque]
609    pub fn _mm256_permute4x64_epi64<const IMM8: i32>(_: __m256i) -> __m256i {
610        unimplemented!()
611    }
612    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_unpackhi_epi64)
613    #[hax_lib::opaque]
614    pub fn _mm256_unpackhi_epi64(_: __m256i, _: __m256i) -> __m256i {
615        unimplemented!()
616    }
617    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_unpacklo_epi32)
618    #[hax_lib::opaque]
619    pub fn _mm256_unpacklo_epi32(_: __m256i, _: __m256i) -> __m256i {
620        unimplemented!()
621    }
622    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_unpackhi_epi32)
623    #[hax_lib::opaque]
624    pub fn _mm256_unpackhi_epi32(_: __m256i, _: __m256i) -> __m256i {
625        unimplemented!()
626    }
627
628    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_cvtepi16_epi32)
629    #[hax_lib::opaque]
630    pub fn _mm256_cvtepi16_epi32(_: __m128i) -> __m256i {
631        unimplemented!()
632    }
633
634    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_packs_epi32)
635    #[hax_lib::opaque]
636    pub fn _mm256_packs_epi32(_: __m256i, _: __m256i) -> __m256i {
637        unimplemented!()
638    }
639    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_inserti128_si256)
640    #[hax_lib::opaque]
641    pub fn _mm256_inserti128_si256<const IMM8: i32>(_: __m256i, _: __m128i) -> __m256i {
642        unimplemented!()
643    }
644    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_blend_epi16)
645    #[hax_lib::opaque]
646    pub fn _mm256_blend_epi16<const IMM8: i32>(_: __m256i, _: __m256i) -> __m256i {
647        unimplemented!()
648    }
649
650    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srlv_epi64)
651    #[hax_lib::opaque]
652    pub fn _mm256_srlv_epi64(_: __m256i, _: __m256i) -> __m256i {
653        unimplemented!()
654    }
655    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sllv_epi32)
656    #[hax_lib::opaque]
657    pub fn _mm_sllv_epi32(_: __m128i, _: __m128i) -> __m128i {
658        unimplemented!()
659    }
660    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_slli_epi64)
661    #[hax_lib::opaque]
662    pub fn _mm256_slli_epi64<const IMM8: i32>(_: __m256i) -> __m256i {
663        unimplemented!()
664    }
665
666    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_bsrli_epi128)
667    /// NOTE: the bsrli here is different from intel specification. In the intel specification, if an IMM8 is given whose first 8 bits are higher than 15, it fixes it to 16.
668    /// However, the Rust implementation erroneously takes the input modulo 16. Thus, instead of shifting by 16 bits at an input of 16, it shifts by 0.
669    /// We are currently modelling the Rust implementation.
670    #[hax_lib::opaque]
671    pub fn _mm256_bsrli_epi128<const IMM8: i32>(_: __m256i) -> __m256i {
672        unimplemented!()
673    }
674    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_andnot_si256)
675    #[hax_lib::opaque]
676    pub fn _mm256_andnot_si256(_: __m256i, _: __m256i) -> __m256i {
677        unimplemented!()
678    }
679
680    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_unpacklo_epi64)
681    #[hax_lib::opaque]
682    pub fn _mm256_unpacklo_epi64(_: __m256i, _: __m256i) -> __m256i {
683        unimplemented!()
684    }
685    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permute2x128_si256)
686    #[hax_lib::opaque]
687    pub fn _mm256_permute2x128_si256<const IMM8: i32>(_: __m256i, _: __m256i) -> __m256i {
688        unimplemented!()
689    }
690
691    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_si128)
692    #[hax_lib::exclude]
693    pub fn _mm_storeu_si128(output: *mut __m128i, a: __m128i) {
694        // This is equivalent to `*output = a`
695        let mut out = [0u8; 128];
696        extra::mm_storeu_bytes_si128(&mut out, a);
697        unsafe {
698            *(output.as_mut().unwrap()) = BitVec::from_slice(&out, 8);
699        }
700    }
701    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_slli_epi16)
702    pub fn _mm256_slli_epi16<const SHIFT_BY: i32>(vector: __m256i) -> __m256i {
703        vector.chunked_shift::<16, 16>(FunArray::from_fn(|_| SHIFT_BY as i128))
704    }
705    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srli_epi64)
706    pub fn _mm256_srli_epi64<const SHIFT_BY: i32>(vector: __m256i) -> __m256i {
707        vector.chunked_shift::<64, 4>(FunArray::from_fn(|_| -(SHIFT_BY as i128)))
708    }
709    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mullo_epi16)
710    #[hax_lib::opaque]
711    pub fn _mm256_mullo_epi16(_vector: __m256i, _shifts: __m256i) -> __m256i {
712        todo!()
713    }
714    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sllv_epi32)
715    #[hax_lib::opaque]
716    pub fn _mm256_sllv_epi32(vector: __m256i, counts: __m256i) -> __m256i {
717        extra::mm256_sllv_epi32_u32_array(vector, counts.to_vec().try_into().unwrap())
718    }
719    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_srlv_epi32)
720    #[hax_lib::opaque]
721    pub fn _mm256_srlv_epi32(vector: __m256i, counts: __m256i) -> __m256i {
722        extra::mm256_srlv_epi32_u32_array(vector, counts.to_vec().try_into().unwrap())
723    }
724    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permutevar8x32_epi32)
725    #[hax_lib::opaque]
726    pub fn _mm256_permutevar8x32_epi32(a: __m256i, b: __m256i) -> __m256i {
727        extra::mm256_permutevar8x32_epi32_u32_array(a, b.to_vec().try_into().unwrap())
728    }
729    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_extracti128_si256)
730    pub fn _mm256_extracti128_si256<const IMM8: i32>(vector: __m256i) -> __m128i {
731        BitVec::from_fn(|i| vector[i + if IMM8 == 0 { 0 } else { 128 }])
732    }
733    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_shuffle_epi8)
734    #[hax_lib::opaque]
735    pub fn _mm256_shuffle_epi8(vector: __m256i, indexes: __m256i) -> __m256i {
736        let indexes = indexes.to_vec().try_into().unwrap();
737        extra::mm256_shuffle_epi8_i8_array(vector, indexes)
738    }
739}
740
741pub use other::*;
742pub mod other {
743    use super::*;
744
745    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128)
746    #[hax_lib::opaque]
747    pub fn _mm_aeskeygenassist_si128(_: __m128i, _: i32) -> __m128i {
748        unimplemented!()
749    }
750
751    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128)
752    #[hax_lib::opaque]
753    pub fn _mm_aesenclast_si128(_: __m128i, _: __m128i) -> __m128i {
754        unimplemented!()
755    }
756
757    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128)
758    #[hax_lib::opaque]
759    pub fn _mm_aesenc_si128(_: __m128i, _: __m128i) -> __m128i {
760        unimplemented!()
761    }
762
763    /// [Intel Documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128)
764    #[hax_lib::opaque]
765    pub fn _mm_clmulepi64_si128(_: __m128i, _: __m128i, _: i32) -> __m128i {
766        unimplemented!()
767    }
768}
769/// Rewrite lemmas
770const _: () = {
771    #[hax_lib::fstar::before("[@@ $REWRITE_RULE ]")]
772    #[hax_lib::lemma]
773    #[hax_lib::opaque]
774    fn _rw_mm256_sllv_epi32(
775        vector: __m256i,
776        b7: i32,
777        b6: i32,
778        b5: i32,
779        b4: i32,
780        b3: i32,
781        b2: i32,
782        b1: i32,
783        b0: i32,
784    ) -> Proof<
785        {
786            hax_lib::prop::eq(
787                _mm256_sllv_epi32(vector, _mm256_set_epi32(b7, b6, b5, b4, b3, b2, b1, b0)),
788                extra::mm256_sllv_epi32_u32(
789                    vector, b7 as u32, b6 as u32, b5 as u32, b4 as u32, b3 as u32, b2 as u32,
790                    b1 as u32, b0 as u32,
791                ),
792            )
793        },
794    > {
795    }
796
797    #[hax_lib::fstar::before("[@@ $REWRITE_RULE ]")]
798    #[hax_lib::lemma]
799    #[hax_lib::opaque]
800    fn _rw_mm256_srlv_epi32(
801        vector: __m256i,
802        b7: i32,
803        b6: i32,
804        b5: i32,
805        b4: i32,
806        b3: i32,
807        b2: i32,
808        b1: i32,
809        b0: i32,
810    ) -> Proof<
811        {
812            hax_lib::prop::eq(
813                _mm256_srlv_epi32(vector, _mm256_set_epi32(b7, b6, b5, b4, b3, b2, b1, b0)),
814                extra::mm256_srlv_epi32_u32(
815                    vector, b7 as u32, b6 as u32, b5 as u32, b4 as u32, b3 as u32, b2 as u32,
816                    b1 as u32, b0 as u32,
817                ),
818            )
819        },
820    > {
821    }
822
823    #[hax_lib::fstar::before("[@@ $REWRITE_RULE ]")]
824    #[hax_lib::lemma]
825    #[hax_lib::opaque]
826    fn _rw_mm256_permutevar8x32_epi32(
827        vector: __m256i,
828        b7: i32,
829        b6: i32,
830        b5: i32,
831        b4: i32,
832        b3: i32,
833        b2: i32,
834        b1: i32,
835        b0: i32,
836    ) -> Proof<
837        {
838            hax_lib::prop::eq(
839                _mm256_permutevar8x32_epi32(
840                    vector,
841                    _mm256_set_epi32(b7, b6, b5, b4, b3, b2, b1, b0),
842                ),
843                extra::mm256_permutevar8x32_epi32_u32(
844                    vector, b7 as u32, b6 as u32, b5 as u32, b4 as u32, b3 as u32, b2 as u32,
845                    b1 as u32, b0 as u32,
846                ),
847            )
848        },
849    > {
850    }
851
852    #[hax_lib::fstar::replace(
853        r#"
854[@@ Core_models.Abstractions.Bitvec.v_REWRITE_RULE ]
855
856assume
857val e___e_rw_mm256_mullo_epi16_shifts':
858    vector: $:{__m256i} ->
859    s15: (n: $:{u8} {v n < 16}) ->
860    s14: (n: $:{u8} {v n < 16}) ->
861    s13: (n: $:{u8} {v n < 16}) ->
862    s12: (n: $:{u8} {v n < 16}) ->
863    s11: (n: $:{u8} {v n < 16}) ->
864    s10: (n: $:{u8} {v n < 16}) ->
865    s9: (n: $:{u8} {v n < 16}) ->
866    s8: (n: $:{u8} {v n < 16}) ->
867    s7: (n: $:{u8} {v n < 16}) ->
868    s6: (n: $:{u8} {v n < 16}) ->
869    s5: (n: $:{u8} {v n < 16}) ->
870    s4: (n: $:{u8} {v n < 16}) ->
871    s3: (n: $:{u8} {v n < 16}) ->
872    s2: (n: $:{u8} {v n < 16}) ->
873    s1: (n: $:{u8} {v n < 16}) ->
874    s0: (n: $:{u8} {v n < 16})
875  -> Lemma
876    (ensures
877      ($_mm256_mullo_epi16 vector
878          ($_mm256_set_epi16 (${1i16} <<! s15 <: i16)
879              (${1i16} <<! s14 <: i16) (${1i16} <<! s13 <: i16) (${1i16} <<! s12 <: i16)
880              (${1i16} <<! s11 <: i16) (${1i16} <<! s10 <: i16) (${1i16} <<! s9 <: i16)
881              (${1i16} <<! s8 <: i16) (${1i16} <<! s7 <: i16) (${1i16} <<! s6 <: i16)
882              (${1i16} <<! s5 <: i16) (${1i16} <<! s4 <: i16) (${1i16} <<! s3 <: i16)
883              (${1i16} <<! s2 <: i16) (${1i16} <<! s1 <: i16) (${1i16} <<! s0 <: i16)
884            )
885        ) ==
886      (${extra::mm256_mullo_epi16_shifts} vector s15 s14 s13 s12 s11 s10 s9 s8 s7
887          s6 s5 s4 s3 s2 s1 s0))
888
889let ${_rw_mm256_mullo_epi16_shifts} = e___e_rw_mm256_mullo_epi16_shifts'
890    "#
891    )]
892    // Note: this is replace with F* code because we need to refine the input of the lemma.
893    pub fn _rw_mm256_mullo_epi16_shifts() {}
894
895    #[hax_lib::fstar::before("[@@ $REWRITE_RULE ]")]
896    #[hax_lib::lemma]
897    #[hax_lib::opaque]
898    #[allow(unused_variables)]
899    fn _rw_mm_shuffle_epi8(
900        vector: __m128i,
901        e15: i8,
902        e14: i8,
903        e13: i8,
904        e12: i8,
905        e11: i8,
906        e10: i8,
907        e9: i8,
908        e8: i8,
909        e7: i8,
910        e6: i8,
911        e5: i8,
912        e4: i8,
913        e3: i8,
914        e2: i8,
915        e1: i8,
916        e0: i8,
917    ) -> Proof<
918        {
919            hax_lib::prop::eq(
920                _mm_shuffle_epi8(
921                    vector,
922                    _mm_set_epi8(
923                        e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0,
924                    ),
925                ),
926                extra::mm_shuffle_epi8_u8(
927                    vector, e15 as u8, e14 as u8, e13 as u8, e12 as u8, e11 as u8, e10 as u8,
928                    e9 as u8, e8 as u8, e7 as u8, e6 as u8, e5 as u8, e4 as u8, e3 as u8, e2 as u8,
929                    e1 as u8, e0 as u8,
930                ),
931            )
932        },
933    > {
934    }
935
936    #[hax_lib::fstar::before("[@@ $REWRITE_RULE ]")]
937    #[hax_lib::lemma]
938    #[hax_lib::opaque]
939    #[allow(unused_variables)]
940    fn _rw_mm256_shuffle_epi8(
941        vector: __m256i,
942        byte31: i8,
943        byte30: i8,
944        byte29: i8,
945        byte28: i8,
946        byte27: i8,
947        byte26: i8,
948        byte25: i8,
949        byte24: i8,
950        byte23: i8,
951        byte22: i8,
952        byte21: i8,
953        byte20: i8,
954        byte19: i8,
955        byte18: i8,
956        byte17: i8,
957        byte16: i8,
958        byte15: i8,
959        byte14: i8,
960        byte13: i8,
961        byte12: i8,
962        byte11: i8,
963        byte10: i8,
964        byte9: i8,
965        byte8: i8,
966        byte7: i8,
967        byte6: i8,
968        byte5: i8,
969        byte4: i8,
970        byte3: i8,
971        byte2: i8,
972        byte1: i8,
973        byte0: i8,
974    ) -> Proof<
975        {
976            hax_lib::prop::eq(
977                _mm256_shuffle_epi8(
978                    vector,
979                    _mm256_set_epi8(
980                        byte31, byte30, byte29, byte28, byte27, byte26, byte25, byte24, byte23,
981                        byte22, byte21, byte20, byte19, byte18, byte17, byte16, byte15, byte14,
982                        byte13, byte12, byte11, byte10, byte9, byte8, byte7, byte6, byte5, byte4,
983                        byte3, byte2, byte1, byte0,
984                    ),
985                ),
986                extra::mm256_shuffle_epi8_i8(
987                    vector, byte31, byte30, byte29, byte28, byte27, byte26, byte25, byte24, byte23,
988                    byte22, byte21, byte20, byte19, byte18, byte17, byte16, byte15, byte14, byte13,
989                    byte12, byte11, byte10, byte9, byte8, byte7, byte6, byte5, byte4, byte3, byte2,
990                    byte1, byte0,
991                ),
992            )
993        },
994    > {
995    }
996};
997
998pub mod extra {
999    use super::*;
1000
1001    pub fn mm256_sllv_epi32_u32_array(
1002        vector: BitVec<256>,
1003        counts: FunArray<8, u32>,
1004    ) -> BitVec<256> {
1005        vector.chunked_shift::<32, 8>(FunArray::from_fn(|i| counts[i] as i128))
1006    }
1007
1008    pub fn mm256_sllv_epi32_u32(
1009        vector: BitVec<256>,
1010        b7: u32,
1011        b6: u32,
1012        b5: u32,
1013        b4: u32,
1014        b3: u32,
1015        b2: u32,
1016        b1: u32,
1017        b0: u32,
1018    ) -> BitVec<256> {
1019        mm256_sllv_epi32_u32_array(
1020            vector,
1021            FunArray::from_fn(|i| match i {
1022                7 => b7,
1023                6 => b6,
1024                5 => b5,
1025                4 => b4,
1026                3 => b3,
1027                2 => b2,
1028                1 => b1,
1029                0 => b0,
1030                _ => unreachable!(),
1031            }),
1032        )
1033    }
1034
1035    pub fn mm256_srlv_epi32_u32_array(
1036        vector: BitVec<256>,
1037        counts: FunArray<8, u32>,
1038    ) -> BitVec<256> {
1039        vector.chunked_shift::<32, 8>(FunArray::from_fn(|i| -(counts[i] as i128)))
1040    }
1041
1042    pub fn mm256_srlv_epi32_u32(
1043        vector: BitVec<256>,
1044        b7: u32,
1045        b6: u32,
1046        b5: u32,
1047        b4: u32,
1048        b3: u32,
1049        b2: u32,
1050        b1: u32,
1051        b0: u32,
1052    ) -> BitVec<256> {
1053        mm256_srlv_epi32_u32_array(
1054            vector,
1055            FunArray::from_fn(|i| match i {
1056                7 => b7,
1057                6 => b6,
1058                5 => b5,
1059                4 => b4,
1060                3 => b3,
1061                2 => b2,
1062                1 => b1,
1063                0 => b0,
1064                _ => unreachable!(),
1065            }),
1066        )
1067    }
1068
1069    pub fn mm256_permutevar8x32_epi32_u32_array(
1070        a: BitVec<256>,
1071        b: FunArray<8, u32>,
1072    ) -> BitVec<256> {
1073        BitVec::from_fn(|i| {
1074            let j = i / 32;
1075            let index = ((b[j] % 8) as u64) * 32;
1076            a[index + i % 32]
1077        })
1078    }
1079
1080    pub fn mm256_permutevar8x32_epi32_u32(
1081        vector: BitVec<256>,
1082        b7: u32,
1083        b6: u32,
1084        b5: u32,
1085        b4: u32,
1086        b3: u32,
1087        b2: u32,
1088        b1: u32,
1089        b0: u32,
1090    ) -> BitVec<256> {
1091        mm256_permutevar8x32_epi32_u32_array(
1092            vector,
1093            FunArray::from_fn(|i| match i {
1094                7 => b7,
1095                6 => b6,
1096                5 => b5,
1097                4 => b4,
1098                3 => b3,
1099                2 => b2,
1100                1 => b1,
1101                0 => b0,
1102                _ => unreachable!(),
1103            }),
1104        )
1105    }
1106
1107    pub fn mm_shuffle_epi8_u8_array(vector: BitVec<128>, indexes: FunArray<16, u8>) -> BitVec<128> {
1108        BitVec::from_fn(|i| {
1109            let nth = i / 8;
1110            let index = indexes[nth];
1111            if index > 127 {
1112                Bit::Zero
1113            } else {
1114                let index = (index % 16) as u64;
1115                vector[index * 8 + i % 8]
1116            }
1117        })
1118    }
1119
1120    pub fn mm_shuffle_epi8_u8(
1121        vector: BitVec<128>,
1122        b15: u8,
1123        b14: u8,
1124        b13: u8,
1125        b12: u8,
1126        b11: u8,
1127        b10: u8,
1128        b9: u8,
1129        b8: u8,
1130        b7: u8,
1131        b6: u8,
1132        b5: u8,
1133        b4: u8,
1134        b3: u8,
1135        b2: u8,
1136        b1: u8,
1137        b0: u8,
1138    ) -> BitVec<128> {
1139        let indexes = FunArray::from_fn(|i| match i {
1140            15 => b15,
1141            14 => b14,
1142            13 => b13,
1143            12 => b12,
1144            11 => b11,
1145            10 => b10,
1146            9 => b9,
1147            8 => b8,
1148            7 => b7,
1149            6 => b6,
1150            5 => b5,
1151            4 => b4,
1152            3 => b3,
1153            2 => b2,
1154            1 => b1,
1155            0 => b0,
1156            _ => unreachable!(),
1157        });
1158        mm_shuffle_epi8_u8_array(vector, indexes)
1159    }
1160
1161    pub fn mm256_shuffle_epi8_i8_array(
1162        vector: BitVec<256>,
1163        indexes: FunArray<32, i8>,
1164    ) -> BitVec<256> {
1165        BitVec::from_fn(|i| {
1166            let nth = i / 8;
1167            let index = indexes[nth];
1168            if index < 0 {
1169                Bit::Zero
1170            } else {
1171                let index = (index % 16) as u64;
1172                vector[if i < 128 { 0 } else { 128 } + index * 8 + i % 8]
1173            }
1174        })
1175    }
1176
1177    pub fn mm256_shuffle_epi8_i8(
1178        vector: BitVec<256>,
1179        byte31: i8,
1180        byte30: i8,
1181        byte29: i8,
1182        byte28: i8,
1183        byte27: i8,
1184        byte26: i8,
1185        byte25: i8,
1186        byte24: i8,
1187        byte23: i8,
1188        byte22: i8,
1189        byte21: i8,
1190        byte20: i8,
1191        byte19: i8,
1192        byte18: i8,
1193        byte17: i8,
1194        byte16: i8,
1195        byte15: i8,
1196        byte14: i8,
1197        byte13: i8,
1198        byte12: i8,
1199        byte11: i8,
1200        byte10: i8,
1201        byte9: i8,
1202        byte8: i8,
1203        byte7: i8,
1204        byte6: i8,
1205        byte5: i8,
1206        byte4: i8,
1207        byte3: i8,
1208        byte2: i8,
1209        byte1: i8,
1210        byte0: i8,
1211    ) -> BitVec<256> {
1212        let indexes = FunArray::from_fn(|i| match i {
1213            31 => byte31,
1214            30 => byte30,
1215            29 => byte29,
1216            28 => byte28,
1217            27 => byte27,
1218            26 => byte26,
1219            25 => byte25,
1220            24 => byte24,
1221            23 => byte23,
1222            22 => byte22,
1223            21 => byte21,
1224            20 => byte20,
1225            19 => byte19,
1226            18 => byte18,
1227            17 => byte17,
1228            16 => byte16,
1229            15 => byte15,
1230            14 => byte14,
1231            13 => byte13,
1232            12 => byte12,
1233            11 => byte11,
1234            10 => byte10,
1235            9 => byte9,
1236            8 => byte8,
1237            7 => byte7,
1238            6 => byte6,
1239            5 => byte5,
1240            4 => byte4,
1241            3 => byte3,
1242            2 => byte2,
1243            1 => byte1,
1244            0 => byte0,
1245            _ => unreachable!(),
1246        });
1247        mm256_shuffle_epi8_i8_array(vector, indexes)
1248    }
1249
1250    pub fn mm256_mullo_epi16_shifts(
1251        vector: __m256i,
1252        s15: u8,
1253        s14: u8,
1254        s13: u8,
1255        s12: u8,
1256        s11: u8,
1257        s10: u8,
1258        s9: u8,
1259        s8: u8,
1260        s7: u8,
1261        s6: u8,
1262        s5: u8,
1263        s4: u8,
1264        s3: u8,
1265        s2: u8,
1266        s1: u8,
1267        s0: u8,
1268    ) -> __m256i {
1269        let shifts = FunArray::<16, _>::from_fn(|i| match i {
1270            15 => s15,
1271            14 => s14,
1272            13 => s13,
1273            12 => s12,
1274            11 => s11,
1275            10 => s10,
1276            9 => s9,
1277            8 => s8,
1278            7 => s7,
1279            6 => s6,
1280            5 => s5,
1281            4 => s4,
1282            3 => s3,
1283            2 => s2,
1284            1 => s1,
1285            0 => s0,
1286            _ => unreachable!(),
1287        });
1288        mm256_mullo_epi16_shifts_array(vector, shifts)
1289    }
1290    pub fn mm256_mullo_epi16_shifts_array(vector: __m256i, shifts: FunArray<16, u8>) -> __m256i {
1291        BitVec::from_fn(|i| {
1292            let nth_bit = i % 16;
1293            let nth_i16 = i / 16;
1294
1295            let shift = shifts[nth_i16] as u64;
1296
1297            if nth_bit >= shift {
1298                vector[nth_i16 * 16 + nth_bit - shift]
1299            } else {
1300                Bit::Zero
1301            }
1302        })
1303    }
1304
1305    #[hax_lib::exclude]
1306    pub fn mm_storeu_bytes_si128(output: &mut [u8], vector: BitVec<128>) {
1307        output.copy_from_slice(&vector.to_vec()[..]);
1308    }
1309}
1310
1311/// Tests of equivalence between `safe::*` and `upstream::*`.
1312#[cfg(all(test, any(target_arch = "x86", target_arch = "x86_64")))]
1313mod tests {
1314    use super::*;
1315
1316    /// Number of tests to run for each function
1317    const N: usize = 1000;
1318
1319    #[test]
1320    fn mm256_slli_epi16() {
1321        macro_rules! mk {
1322                ($($shift: literal)*) => {
1323                    $(for _ in 0..N {
1324                        let input = BitVec::<256>::rand();
1325                        assert_eq!(
1326                            super::_mm256_slli_epi16::<$shift>(input),
1327                            unsafe {upstream::_mm256_slli_epi16::<$shift>(input.into()).into()}
1328                        );
1329                    })*
1330                };
1331            }
1332        mk!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15);
1333    }
1334
1335    #[test]
1336    fn mm256_srli_epi64() {
1337        macro_rules! mk {
1338                ($($shift: literal)*) => {
1339                    $(for _ in 0..N {
1340                        let input = BitVec::<256>::rand();
1341                        assert_eq!(
1342                            super::_mm256_srli_epi64::<$shift>(input),
1343                            unsafe{upstream::_mm256_srli_epi64::<$shift>(input.into()).into()}
1344                        );
1345                    })*
1346                };
1347            }
1348        mk!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63);
1349    }
1350
1351    #[test]
1352    fn mm256_sllv_epi32() {
1353        for _ in 0..N {
1354            let vector: BitVec<256> = BitVec::rand();
1355            let counts: BitVec<256> = BitVec::rand();
1356            assert_eq!(super::_mm256_sllv_epi32(vector, counts), unsafe {
1357                upstream::_mm256_sllv_epi32(vector.into(), counts.into()).into()
1358            });
1359        }
1360    }
1361
1362    #[test]
1363    fn mm256_srlv_epi32() {
1364        for _ in 0..N {
1365            let vector: BitVec<256> = BitVec::rand();
1366            let counts: BitVec<256> = BitVec::rand();
1367            assert_eq!(super::_mm256_srlv_epi32(vector, counts), unsafe {
1368                upstream::_mm256_srlv_epi32(vector.into(), counts.into()).into()
1369            });
1370        }
1371    }
1372
1373    #[test]
1374    fn mm256_permutevar8x32_epi32() {
1375        for _ in 0..N {
1376            let vector: BitVec<256> = BitVec::rand();
1377            let counts: BitVec<256> = BitVec::rand();
1378            assert_eq!(super::_mm256_permutevar8x32_epi32(vector, counts), unsafe {
1379                upstream::_mm256_permutevar8x32_epi32(vector.into(), counts.into()).into()
1380            });
1381        }
1382    }
1383
1384    #[test]
1385    fn mm256_castsi256_si128() {
1386        for _ in 0..N {
1387            let vector: BitVec<256> = BitVec::rand();
1388            assert_eq!(super::_mm256_castsi256_si128(vector), unsafe {
1389                upstream::_mm256_castsi256_si128(vector.into()).into()
1390            });
1391        }
1392    }
1393
1394    #[test]
1395    fn mm256_extracti128_si256() {
1396        for _ in 0..N {
1397            let vector: BitVec<256> = BitVec::rand();
1398            assert_eq!(super::_mm256_extracti128_si256::<0>(vector), unsafe {
1399                upstream::_mm256_extracti128_si256::<0>(vector.into()).into()
1400            });
1401            assert_eq!(super::_mm256_extracti128_si256::<1>(vector), unsafe {
1402                upstream::_mm256_extracti128_si256::<1>(vector.into()).into()
1403            });
1404        }
1405    }
1406
1407    #[test]
1408    fn mm_shuffle_epi8() {
1409        for _ in 0..N {
1410            let a: BitVec<128> = BitVec::rand();
1411            let b: BitVec<128> = BitVec::rand();
1412
1413            assert_eq!(super::_mm_shuffle_epi8(a, b), unsafe {
1414                upstream::_mm_shuffle_epi8(a.into(), b.into()).into()
1415            });
1416        }
1417    }
1418
1419    #[test]
1420    fn mm256_shuffle_epi8() {
1421        for _ in 0..N {
1422            let a: BitVec<256> = BitVec::rand();
1423            let b: BitVec<256> = BitVec::rand();
1424
1425            assert_eq!(super::_mm256_shuffle_epi8(a, b), unsafe {
1426                upstream::_mm256_shuffle_epi8(a.into(), b.into()).into()
1427            });
1428        }
1429    }
1430
1431    #[test]
1432    fn mm256_mullo_epi16_shifts() {
1433        pub fn upsteam_mm256_mullo_epi16_shifts(
1434            vector: upstream::__m256i,
1435            s15: u8,
1436            s14: u8,
1437            s13: u8,
1438            s12: u8,
1439            s11: u8,
1440            s10: u8,
1441            s9: u8,
1442            s8: u8,
1443            s7: u8,
1444            s6: u8,
1445            s5: u8,
1446            s4: u8,
1447            s3: u8,
1448            s2: u8,
1449            s1: u8,
1450            s0: u8,
1451        ) -> upstream::__m256i {
1452            unsafe {
1453                upstream::_mm256_mullo_epi16(
1454                    vector,
1455                    upstream::_mm256_set_epi16(
1456                        1i16 << s15,
1457                        1i16 << s14,
1458                        1i16 << s13,
1459                        1i16 << s12,
1460                        1i16 << s11,
1461                        1i16 << s10,
1462                        1i16 << s9,
1463                        1i16 << s8,
1464                        1i16 << s7,
1465                        1i16 << s6,
1466                        1i16 << s5,
1467                        1i16 << s4,
1468                        1i16 << s3,
1469                        1i16 << s2,
1470                        1i16 << s1,
1471                        1i16 << s0,
1472                    ),
1473                )
1474            }
1475        }
1476        for _ in 0..N {
1477            let a: BitVec<256> = BitVec::rand();
1478            let s15: u8 = rand::random::<u8>() % 16;
1479            let s14: u8 = rand::random::<u8>() % 16;
1480            let s13: u8 = rand::random::<u8>() % 16;
1481            let s12: u8 = rand::random::<u8>() % 16;
1482            let s11: u8 = rand::random::<u8>() % 16;
1483            let s10: u8 = rand::random::<u8>() % 16;
1484            let s9: u8 = rand::random::<u8>() % 16;
1485            let s8: u8 = rand::random::<u8>() % 16;
1486            let s7: u8 = rand::random::<u8>() % 16;
1487            let s6: u8 = rand::random::<u8>() % 16;
1488            let s5: u8 = rand::random::<u8>() % 16;
1489            let s4: u8 = rand::random::<u8>() % 16;
1490            let s3: u8 = rand::random::<u8>() % 16;
1491            let s2: u8 = rand::random::<u8>() % 16;
1492            let s1: u8 = rand::random::<u8>() % 16;
1493            let s0: u8 = rand::random::<u8>() % 16;
1494
1495            assert_eq!(
1496                super::extra::mm256_mullo_epi16_shifts(
1497                    a, s15, s14, s13, s12, s11, s10, s9, s8, s7, s6, s5, s4, s3, s2, s1, s0,
1498                ),
1499                upsteam_mm256_mullo_epi16_shifts(
1500                    a.into(),
1501                    s15,
1502                    s14,
1503                    s13,
1504                    s12,
1505                    s11,
1506                    s10,
1507                    s9,
1508                    s8,
1509                    s7,
1510                    s6,
1511                    s5,
1512                    s4,
1513                    s3,
1514                    s2,
1515                    s1,
1516                    s0,
1517                )
1518                .into()
1519            );
1520        }
1521    }
1522}