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