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