1use std::{
5 arch::x86_64::*,
6 mem,
7 ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr},
8};
9
10use binius_utils::{
11 DeserializeBytes, SerializationError, SerializeBytes,
12 bytes::{Buf, BufMut},
13 serialization::{assert_enough_data_for, assert_enough_space_for},
14};
15use bytemuck::{Pod, Zeroable};
16use rand::{
17 distr::{Distribution, StandardUniform},
18 prelude::*,
19};
20use seq_macro::seq;
21
22use crate::{
23 BinaryField,
24 arch::portable::packed::PackedPrimitiveType,
25 underlier::{
26 Divisible, SmallU, UnderlierType, impl_divisible_bitmask, impl_divisible_self, mapget,
27 },
28};
29
30pub const fn m128i_from_u128(x: u128) -> __m128i {
31 let _: [(); align_of::<u128>()] = [(); align_of::<__m128i>()];
33 unsafe { mem::transmute(x) }
34}
35
36#[derive(Copy, Clone)]
38#[repr(transparent)]
39pub struct M128(pub(super) __m128i);
40
41impl M128 {
42 #[inline(always)]
43 pub const fn from_u128(val: u128) -> Self {
44 Self(m128i_from_u128(val))
45 }
46}
47
48impl From<__m128i> for M128 {
49 #[inline(always)]
50 fn from(value: __m128i) -> Self {
51 Self(value)
52 }
53}
54
55impl From<u128> for M128 {
56 fn from(value: u128) -> Self {
57 Self(m128i_from_u128(value))
58 }
59}
60
61impl From<u64> for M128 {
62 fn from(value: u64) -> Self {
63 Self::from(value as u128)
64 }
65}
66
67impl From<u32> for M128 {
68 fn from(value: u32) -> Self {
69 Self::from(value as u128)
70 }
71}
72
73impl From<u16> for M128 {
74 fn from(value: u16) -> Self {
75 Self::from(value as u128)
76 }
77}
78
79impl From<u8> for M128 {
80 fn from(value: u8) -> Self {
81 Self::from(value as u128)
82 }
83}
84
85impl<const N: usize> From<SmallU<N>> for M128 {
86 fn from(value: SmallU<N>) -> Self {
87 Self::from(value.val() as u128)
88 }
89}
90
91impl From<M128> for u128 {
92 fn from(value: M128) -> Self {
93 let mut result = 0u128;
94 unsafe {
95 assert_eq!(align_of::<u128>(), 16);
97 _mm_store_si128(&raw mut result as *mut __m128i, value.0)
98 };
99 result
100 }
101}
102
103impl From<M128> for __m128i {
104 #[inline(always)]
105 fn from(value: M128) -> Self {
106 value.0
107 }
108}
109
110impl SerializeBytes for M128 {
111 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
112 assert_enough_space_for(&write_buf, std::mem::size_of::<Self>())?;
113
114 let raw_value: u128 = (*self).into();
115
116 write_buf.put_u128_le(raw_value);
117 Ok(())
118 }
119}
120
121impl DeserializeBytes for M128 {
122 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
123 where
124 Self: Sized,
125 {
126 assert_enough_data_for(&read_buf, std::mem::size_of::<Self>())?;
127
128 let raw_value = read_buf.get_u128_le();
129
130 Ok(Self::from(raw_value))
131 }
132}
133
134impl_divisible_bitmask!(M128, 1, 2, 4);
135
136impl Default for M128 {
137 #[inline(always)]
138 fn default() -> Self {
139 Self(unsafe { _mm_setzero_si128() })
140 }
141}
142
143impl BitAnd for M128 {
144 type Output = Self;
145
146 #[inline(always)]
147 fn bitand(self, rhs: Self) -> Self::Output {
148 Self(unsafe { _mm_and_si128(self.0, rhs.0) })
149 }
150}
151
152impl BitAndAssign for M128 {
153 #[inline(always)]
154 fn bitand_assign(&mut self, rhs: Self) {
155 *self = *self & rhs
156 }
157}
158
159impl BitOr for M128 {
160 type Output = Self;
161
162 #[inline(always)]
163 fn bitor(self, rhs: Self) -> Self::Output {
164 Self(unsafe { _mm_or_si128(self.0, rhs.0) })
165 }
166}
167
168impl BitOrAssign for M128 {
169 #[inline(always)]
170 fn bitor_assign(&mut self, rhs: Self) {
171 *self = *self | rhs
172 }
173}
174
175impl BitXor for M128 {
176 type Output = Self;
177
178 #[inline(always)]
179 fn bitxor(self, rhs: Self) -> Self::Output {
180 Self(unsafe { _mm_xor_si128(self.0, rhs.0) })
181 }
182}
183
184impl BitXorAssign for M128 {
185 #[inline(always)]
186 fn bitxor_assign(&mut self, rhs: Self) {
187 *self = *self ^ rhs;
188 }
189}
190
191impl Not for M128 {
192 type Output = Self;
193
194 fn not(self) -> Self::Output {
195 const ONES: M128 = M128::from_u128(u128::MAX);
196
197 self ^ ONES
198 }
199}
200
201const fn max_i32(left: i32, right: i32) -> i32 {
203 if left > right { left } else { right }
204}
205
206macro_rules! bitshift_128b {
211 ($val:expr, $shift:ident, $byte_shift:ident, $bit_shift_64:ident, $bit_shift_64_opposite:ident, $or:ident) => {
212 unsafe {
213 let carry = $byte_shift($val, 8);
214 seq!(N in 64..128 {
215 if $shift == N {
216 return $bit_shift_64(
217 carry,
218 crate::arch::x86_64::m128::max_i32((N - 64) as i32, 0) as _,
219 ).into();
220 }
221 });
222 seq!(N in 0..64 {
223 if $shift == N {
224 let carry = $bit_shift_64_opposite(
225 carry,
226 crate::arch::x86_64::m128::max_i32((64 - N) as i32, 0) as _,
227 );
228
229 let val = $bit_shift_64($val, N);
230 return $or(val, carry).into();
231 }
232 });
233
234 return Default::default()
235 }
236 };
237}
238
239impl Shr<usize> for M128 {
240 type Output = Self;
241
242 #[inline(always)]
243 fn shr(self, rhs: usize) -> Self::Output {
244 bitshift_128b!(self.0, rhs, _mm_bsrli_si128, _mm_srli_epi64, _mm_slli_epi64, _mm_or_si128)
247 }
248}
249
250impl Shl<usize> for M128 {
251 type Output = Self;
252
253 #[inline(always)]
254 fn shl(self, rhs: usize) -> Self::Output {
255 bitshift_128b!(self.0, rhs, _mm_bslli_si128, _mm_slli_epi64, _mm_srli_epi64, _mm_or_si128);
258 }
259}
260
261impl PartialEq for M128 {
262 fn eq(&self, other: &Self) -> bool {
263 unsafe {
264 let neq = _mm_xor_si128(self.0, other.0);
265 _mm_test_all_zeros(neq, neq) == 1
266 }
267 }
268}
269
270impl Eq for M128 {}
271
272impl PartialOrd for M128 {
273 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
274 Some(self.cmp(other))
275 }
276}
277
278impl Ord for M128 {
279 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
280 u128::from(*self).cmp(&u128::from(*other))
281 }
282}
283
284impl std::hash::Hash for M128 {
285 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
286 u128::from(*self).hash(state);
287 }
288}
289
290impl std::fmt::LowerHex for M128 {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 std::fmt::LowerHex::fmt(&u128::from(*self), f)
293 }
294}
295
296impl Distribution<M128> for StandardUniform {
297 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> M128 {
298 M128(rng.random())
299 }
300}
301
302impl std::fmt::Display for M128 {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 let data: u128 = (*self).into();
305 write!(f, "{data:02X?}")
306 }
307}
308
309impl std::fmt::Debug for M128 {
310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 write!(f, "M128({self})")
312 }
313}
314
315impl UnderlierType for M128 {
316 const LOG_BITS: usize = 7;
317 const ZERO: Self = { Self::from_u128(0) };
318 const ONE: Self = { Self::from_u128(1) };
319 const ONES: Self = { Self::from_u128(u128::MAX) };
320
321 #[inline(always)]
322 fn interleave(self, other: Self, log_block_len: usize) -> (Self, Self) {
323 unsafe {
324 let (c, d) = interleave_bits(
325 Into::<Self>::into(self).into(),
326 Into::<Self>::into(other).into(),
327 log_block_len,
328 );
329 (Self::from(c), Self::from(d))
330 }
331 }
332}
333
334unsafe impl Zeroable for M128 {}
335
336unsafe impl Pod for M128 {}
337
338unsafe impl Send for M128 {}
339
340unsafe impl Sync for M128 {}
341
342impl<Scalar: BinaryField> From<__m128i> for PackedPrimitiveType<M128, Scalar> {
343 fn from(value: __m128i) -> Self {
344 M128::from(value).into()
345 }
346}
347
348impl<Scalar: BinaryField> From<u128> for PackedPrimitiveType<M128, Scalar> {
349 fn from(value: u128) -> Self {
350 M128::from(value).into()
351 }
352}
353
354impl<Scalar: BinaryField> From<PackedPrimitiveType<M128, Scalar>> for __m128i {
355 fn from(value: PackedPrimitiveType<M128, Scalar>) -> Self {
356 value.to_underlier().into()
357 }
358}
359
360#[inline]
361unsafe fn interleave_bits(a: __m128i, b: __m128i, log_block_len: usize) -> (__m128i, __m128i) {
362 match log_block_len {
363 0 => unsafe {
364 let mask = _mm_set1_epi8(0x55i8);
365 interleave_bits_imm::<1>(a, b, mask)
366 },
367 1 => unsafe {
368 let mask = _mm_set1_epi8(0x33i8);
369 interleave_bits_imm::<2>(a, b, mask)
370 },
371 2 => unsafe {
372 let mask = _mm_set1_epi8(0x0fi8);
373 interleave_bits_imm::<4>(a, b, mask)
374 },
375 3 => unsafe {
376 let shuffle = _mm_set_epi8(15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0);
377 let a = _mm_shuffle_epi8(a, shuffle);
378 let b = _mm_shuffle_epi8(b, shuffle);
379 let a_prime = _mm_unpacklo_epi8(a, b);
380 let b_prime = _mm_unpackhi_epi8(a, b);
381 (a_prime, b_prime)
382 },
383 4 => unsafe {
384 let shuffle = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0);
385 let a = _mm_shuffle_epi8(a, shuffle);
386 let b = _mm_shuffle_epi8(b, shuffle);
387 let a_prime = _mm_unpacklo_epi16(a, b);
388 let b_prime = _mm_unpackhi_epi16(a, b);
389 (a_prime, b_prime)
390 },
391 5 => unsafe {
392 let shuffle = _mm_set_epi8(15, 14, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8, 3, 2, 1, 0);
393 let a = _mm_shuffle_epi8(a, shuffle);
394 let b = _mm_shuffle_epi8(b, shuffle);
395 let a_prime = _mm_unpacklo_epi32(a, b);
396 let b_prime = _mm_unpackhi_epi32(a, b);
397 (a_prime, b_prime)
398 },
399 6 => unsafe {
400 let a_prime = _mm_unpacklo_epi64(a, b);
401 let b_prime = _mm_unpackhi_epi64(a, b);
402 (a_prime, b_prime)
403 },
404 _ => panic!("unsupported block length"),
405 }
406}
407
408#[inline]
409unsafe fn interleave_bits_imm<const BLOCK_LEN: i32>(
410 a: __m128i,
411 b: __m128i,
412 mask: __m128i,
413) -> (__m128i, __m128i) {
414 unsafe {
415 let t = _mm_and_si128(_mm_xor_si128(_mm_srli_epi64::<BLOCK_LEN>(a), b), mask);
416 let a_prime = _mm_xor_si128(a, _mm_slli_epi64::<BLOCK_LEN>(t));
417 let b_prime = _mm_xor_si128(b, t);
418 (a_prime, b_prime)
419 }
420}
421
422impl_divisible_self!(M128);
426
427impl Divisible<u128> for M128 {
428 const LOG_N: usize = 0;
429
430 #[inline]
431 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = u128> + Send + Clone {
432 std::iter::once(u128::from(value))
433 }
434
435 #[inline]
436 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = u128> + Send + Clone + '_ {
437 std::iter::once(u128::from(*value))
438 }
439
440 #[inline]
441 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = u128> + Send + Clone + '_ {
442 slice.iter().map(|&v| u128::from(v))
443 }
444
445 #[inline]
446 unsafe fn get_unchecked(&self, _index: usize) -> u128 {
447 u128::from(*self)
448 }
449
450 #[inline]
451 unsafe fn set_unchecked(&mut self, _index: usize, val: u128) {
452 *self = Self::from(val);
453 }
454
455 #[inline]
456 fn broadcast(val: u128) -> Self {
457 Self::from(val)
458 }
459
460 #[inline]
461 fn from_iter(mut iter: impl Iterator<Item = u128>) -> Self {
462 iter.next().map(Self::from).unwrap_or(Self::ZERO)
463 }
464}
465
466impl Divisible<u64> for M128 {
467 const LOG_N: usize = 1;
468
469 #[inline]
470 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = u64> + Send + Clone {
471 mapget::value_iter(value)
472 }
473
474 #[inline]
475 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = u64> + Send + Clone + '_ {
476 mapget::value_iter(*value)
477 }
478
479 #[inline]
480 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = u64> + Send + Clone + '_ {
481 mapget::slice_iter(slice)
482 }
483
484 #[inline]
485 unsafe fn get_unchecked(&self, index: usize) -> u64 {
486 unsafe {
487 match index {
488 0 => _mm_extract_epi64(self.0, 0) as u64,
489 1 => _mm_extract_epi64(self.0, 1) as u64,
490 _ => core::hint::unreachable_unchecked(),
491 }
492 }
493 }
494
495 #[inline]
496 unsafe fn set_unchecked(&mut self, index: usize, val: u64) {
497 *self = unsafe {
498 match index {
499 0 => Self(_mm_insert_epi64(self.0, val as i64, 0)),
500 1 => Self(_mm_insert_epi64(self.0, val as i64, 1)),
501 _ => core::hint::unreachable_unchecked(),
502 }
503 };
504 }
505
506 #[inline]
507 fn broadcast(val: u64) -> Self {
508 unsafe { Self(_mm_set1_epi64x(val as i64)) }
509 }
510
511 #[inline]
512 fn from_iter(iter: impl Iterator<Item = u64>) -> Self {
513 let mut result = Self::ZERO;
514 let arr: &mut [u64; 2] = bytemuck::cast_mut(&mut result);
515 for (i, val) in iter.take(2).enumerate() {
516 arr[i] = val;
517 }
518 result
519 }
520}
521
522impl Divisible<u32> for M128 {
523 const LOG_N: usize = 2;
524
525 #[inline]
526 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = u32> + Send + Clone {
527 mapget::value_iter(value)
528 }
529
530 #[inline]
531 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = u32> + Send + Clone + '_ {
532 mapget::value_iter(*value)
533 }
534
535 #[inline]
536 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = u32> + Send + Clone + '_ {
537 mapget::slice_iter(slice)
538 }
539
540 #[inline]
541 unsafe fn get_unchecked(&self, index: usize) -> u32 {
542 unsafe {
543 match index {
544 0 => _mm_extract_epi32(self.0, 0) as u32,
545 1 => _mm_extract_epi32(self.0, 1) as u32,
546 2 => _mm_extract_epi32(self.0, 2) as u32,
547 3 => _mm_extract_epi32(self.0, 3) as u32,
548 _ => core::hint::unreachable_unchecked(),
549 }
550 }
551 }
552
553 #[inline]
554 unsafe fn set_unchecked(&mut self, index: usize, val: u32) {
555 *self = unsafe {
556 match index {
557 0 => Self(_mm_insert_epi32(self.0, val as i32, 0)),
558 1 => Self(_mm_insert_epi32(self.0, val as i32, 1)),
559 2 => Self(_mm_insert_epi32(self.0, val as i32, 2)),
560 3 => Self(_mm_insert_epi32(self.0, val as i32, 3)),
561 _ => core::hint::unreachable_unchecked(),
562 }
563 };
564 }
565
566 #[inline]
567 fn broadcast(val: u32) -> Self {
568 unsafe { Self(_mm_set1_epi32(val as i32)) }
569 }
570
571 #[inline]
572 fn from_iter(iter: impl Iterator<Item = u32>) -> Self {
573 let mut result = Self::ZERO;
574 let arr: &mut [u32; 4] = bytemuck::cast_mut(&mut result);
575 for (i, val) in iter.take(4).enumerate() {
576 arr[i] = val;
577 }
578 result
579 }
580}
581
582impl Divisible<u16> for M128 {
583 const LOG_N: usize = 3;
584
585 #[inline]
586 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = u16> + Send + Clone {
587 mapget::value_iter(value)
588 }
589
590 #[inline]
591 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = u16> + Send + Clone + '_ {
592 mapget::value_iter(*value)
593 }
594
595 #[inline]
596 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = u16> + Send + Clone + '_ {
597 mapget::slice_iter(slice)
598 }
599
600 #[inline]
601 unsafe fn get_unchecked(&self, index: usize) -> u16 {
602 unsafe {
603 match index {
604 0 => _mm_extract_epi16(self.0, 0) as u16,
605 1 => _mm_extract_epi16(self.0, 1) as u16,
606 2 => _mm_extract_epi16(self.0, 2) as u16,
607 3 => _mm_extract_epi16(self.0, 3) as u16,
608 4 => _mm_extract_epi16(self.0, 4) as u16,
609 5 => _mm_extract_epi16(self.0, 5) as u16,
610 6 => _mm_extract_epi16(self.0, 6) as u16,
611 7 => _mm_extract_epi16(self.0, 7) as u16,
612 _ => core::hint::unreachable_unchecked(),
613 }
614 }
615 }
616
617 #[inline]
618 unsafe fn set_unchecked(&mut self, index: usize, val: u16) {
619 *self = unsafe {
620 match index {
621 0 => Self(_mm_insert_epi16(self.0, val as i32, 0)),
622 1 => Self(_mm_insert_epi16(self.0, val as i32, 1)),
623 2 => Self(_mm_insert_epi16(self.0, val as i32, 2)),
624 3 => Self(_mm_insert_epi16(self.0, val as i32, 3)),
625 4 => Self(_mm_insert_epi16(self.0, val as i32, 4)),
626 5 => Self(_mm_insert_epi16(self.0, val as i32, 5)),
627 6 => Self(_mm_insert_epi16(self.0, val as i32, 6)),
628 7 => Self(_mm_insert_epi16(self.0, val as i32, 7)),
629 _ => core::hint::unreachable_unchecked(),
630 }
631 };
632 }
633
634 #[inline]
635 fn broadcast(val: u16) -> Self {
636 unsafe { Self(_mm_set1_epi16(val as i16)) }
637 }
638
639 #[inline]
640 fn from_iter(iter: impl Iterator<Item = u16>) -> Self {
641 let mut result = Self::ZERO;
642 let arr: &mut [u16; 8] = bytemuck::cast_mut(&mut result);
643 for (i, val) in iter.take(8).enumerate() {
644 arr[i] = val;
645 }
646 result
647 }
648}
649
650impl Divisible<u8> for M128 {
651 const LOG_N: usize = 4;
652
653 #[inline]
654 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = u8> + Send + Clone {
655 mapget::value_iter(value)
656 }
657
658 #[inline]
659 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = u8> + Send + Clone + '_ {
660 mapget::value_iter(*value)
661 }
662
663 #[inline]
664 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = u8> + Send + Clone + '_ {
665 mapget::slice_iter(slice)
666 }
667
668 #[inline]
669 unsafe fn get_unchecked(&self, index: usize) -> u8 {
670 unsafe {
671 match index {
672 0 => _mm_extract_epi8(self.0, 0) as u8,
673 1 => _mm_extract_epi8(self.0, 1) as u8,
674 2 => _mm_extract_epi8(self.0, 2) as u8,
675 3 => _mm_extract_epi8(self.0, 3) as u8,
676 4 => _mm_extract_epi8(self.0, 4) as u8,
677 5 => _mm_extract_epi8(self.0, 5) as u8,
678 6 => _mm_extract_epi8(self.0, 6) as u8,
679 7 => _mm_extract_epi8(self.0, 7) as u8,
680 8 => _mm_extract_epi8(self.0, 8) as u8,
681 9 => _mm_extract_epi8(self.0, 9) as u8,
682 10 => _mm_extract_epi8(self.0, 10) as u8,
683 11 => _mm_extract_epi8(self.0, 11) as u8,
684 12 => _mm_extract_epi8(self.0, 12) as u8,
685 13 => _mm_extract_epi8(self.0, 13) as u8,
686 14 => _mm_extract_epi8(self.0, 14) as u8,
687 15 => _mm_extract_epi8(self.0, 15) as u8,
688 _ => core::hint::unreachable_unchecked(),
689 }
690 }
691 }
692
693 #[inline]
694 unsafe fn set_unchecked(&mut self, index: usize, val: u8) {
695 *self = unsafe {
696 match index {
697 0 => Self(_mm_insert_epi8(self.0, val as i32, 0)),
698 1 => Self(_mm_insert_epi8(self.0, val as i32, 1)),
699 2 => Self(_mm_insert_epi8(self.0, val as i32, 2)),
700 3 => Self(_mm_insert_epi8(self.0, val as i32, 3)),
701 4 => Self(_mm_insert_epi8(self.0, val as i32, 4)),
702 5 => Self(_mm_insert_epi8(self.0, val as i32, 5)),
703 6 => Self(_mm_insert_epi8(self.0, val as i32, 6)),
704 7 => Self(_mm_insert_epi8(self.0, val as i32, 7)),
705 8 => Self(_mm_insert_epi8(self.0, val as i32, 8)),
706 9 => Self(_mm_insert_epi8(self.0, val as i32, 9)),
707 10 => Self(_mm_insert_epi8(self.0, val as i32, 10)),
708 11 => Self(_mm_insert_epi8(self.0, val as i32, 11)),
709 12 => Self(_mm_insert_epi8(self.0, val as i32, 12)),
710 13 => Self(_mm_insert_epi8(self.0, val as i32, 13)),
711 14 => Self(_mm_insert_epi8(self.0, val as i32, 14)),
712 15 => Self(_mm_insert_epi8(self.0, val as i32, 15)),
713 _ => core::hint::unreachable_unchecked(),
714 }
715 };
716 }
717
718 #[inline]
719 fn broadcast(val: u8) -> Self {
720 unsafe { Self(_mm_set1_epi8(val as i8)) }
721 }
722
723 #[inline]
724 fn from_iter(iter: impl Iterator<Item = u8>) -> Self {
725 let mut result = Self::ZERO;
726 let arr: &mut [u8; 16] = bytemuck::cast_mut(&mut result);
727 for (i, val) in iter.take(16).enumerate() {
728 arr[i] = val;
729 }
730 result
731 }
732}
733
734#[cfg(test)]
735mod tests {
736 use binius_utils::bytes::BytesMut;
737 use proptest::{arbitrary::any, proptest};
738 use rand::prelude::*;
739
740 use super::*;
741
742 fn check_roundtrip<T>(val: M128)
743 where
744 T: From<M128>,
745 M128: From<T>,
746 {
747 assert_eq!(M128::from(T::from(val)), val);
748 }
749
750 #[test]
751 fn test_constants() {
752 assert_eq!(M128::default(), M128::ZERO);
753 assert_eq!(M128::from(0u128), M128::ZERO);
754 assert_eq!(M128::from(1u128), M128::ONE);
755 }
756
757 fn get(value: M128, log_block_len: usize, index: usize) -> M128 {
758 (value >> (index << log_block_len)) & M128::from(1u128 << log_block_len)
759 }
760
761 proptest! {
762 #[test]
763 fn test_conversion(a in any::<u128>()) {
764 check_roundtrip::<u128>(a.into());
765 check_roundtrip::<__m128i>(a.into());
766 }
767
768 #[test]
769 fn test_binary_bit_operations(a in any::<u128>(), b in any::<u128>()) {
770 assert_eq!(M128::from(a & b), M128::from(a) & M128::from(b));
771 assert_eq!(M128::from(a | b), M128::from(a) | M128::from(b));
772 assert_eq!(M128::from(a ^ b), M128::from(a) ^ M128::from(b));
773 }
774
775 #[test]
776 fn test_negate(a in any::<u128>()) {
777 assert_eq!(M128::from(!a), !M128::from(a))
778 }
779
780 #[test]
781 fn test_shifts(a in any::<u128>(), b in 0..128usize) {
782 assert_eq!(M128::from(a << b), M128::from(a) << b);
783 assert_eq!(M128::from(a >> b), M128::from(a) >> b);
784 }
785
786 #[test]
787 fn test_interleave_bits(a in any::<u128>(), b in any::<u128>(), height in 0usize..7) {
788 let a = M128::from(a);
789 let b = M128::from(b);
790
791 let (c, d) = unsafe {interleave_bits(a.0, b.0, height)};
792 let (c, d) = (M128::from(c), M128::from(d));
793
794 for i in (0..128>>height).step_by(2) {
795 assert_eq!(get(c, height, i), get(a, height, i));
796 assert_eq!(get(c, height, i+1), get(b, height, i));
797 assert_eq!(get(d, height, i), get(a, height, i+1));
798 assert_eq!(get(d, height, i+1), get(b, height, i+1));
799 }
800 }
801 }
802
803 #[test]
804 fn test_fill_with_bit() {
805 assert_eq!(M128::fill_with_bit(1), M128::from(u128::MAX));
806 assert_eq!(M128::fill_with_bit(0), M128::from(0u128));
807 }
808
809 #[test]
810 fn test_eq() {
811 let a = M128::from(0u128);
812 let b = M128::from(42u128);
813 let c = M128::from(u128::MAX);
814
815 assert_eq!(a, a);
816 assert_eq!(b, b);
817 assert_eq!(c, c);
818
819 assert_ne!(a, b);
820 assert_ne!(a, c);
821 assert_ne!(b, c);
822 }
823
824 #[test]
825 fn test_serialize_and_deserialize_m128() {
826 let mut rng = StdRng::from_seed([0; 32]);
827
828 let original_value = M128::from(rng.random::<u128>());
829
830 let mut buf = BytesMut::new();
831 original_value.serialize(&mut buf).unwrap();
832
833 let deserialized_value = M128::deserialize(buf.freeze()).unwrap();
834
835 assert_eq!(original_value, deserialized_value);
836 }
837}