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, FixedSizeSerializeBytes, 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 divisible::{Divisible, impl_divisible_memcast, impl_divisible_self},
25 packed_fields::primitive::PackedPrimitiveType,
26 underlier::{SmallU, Underlier, impl_divisible_bitmask},
27};
28
29pub const fn m128i_from_u128(x: u128) -> __m128i {
30 let _: [(); align_of::<u128>()] = [(); align_of::<__m128i>()];
32 unsafe { mem::transmute(x) }
33}
34
35#[derive(Copy, Clone)]
37#[repr(transparent)]
38pub struct M128(pub(super) __m128i);
39
40impl M128 {
41 #[inline(always)]
42 pub const fn from_u128(val: u128) -> Self {
43 Self(m128i_from_u128(val))
44 }
45}
46
47impl From<__m128i> for M128 {
48 #[inline(always)]
49 fn from(value: __m128i) -> Self {
50 Self(value)
51 }
52}
53
54impl From<u128> for M128 {
55 fn from(value: u128) -> Self {
56 Self(m128i_from_u128(value))
57 }
58}
59
60impl From<u64> for M128 {
61 fn from(value: u64) -> Self {
62 Self::from(value as u128)
63 }
64}
65
66impl From<u32> for M128 {
67 fn from(value: u32) -> Self {
68 Self::from(value as u128)
69 }
70}
71
72impl From<u16> for M128 {
73 fn from(value: u16) -> Self {
74 Self::from(value as u128)
75 }
76}
77
78impl From<u8> for M128 {
79 fn from(value: u8) -> Self {
80 Self::from(value as u128)
81 }
82}
83
84impl<const N: usize> From<SmallU<N>> for M128 {
85 fn from(value: SmallU<N>) -> Self {
86 Self::from(value.val() as u128)
87 }
88}
89
90impl From<M128> for u128 {
91 fn from(value: M128) -> Self {
92 const {
93 assert!(
94 align_of::<u128>() == 16,
95 "the store below needs a 16-byte aligned destination"
96 );
97 }
98 let mut result = 0u128;
99 unsafe {
100 _mm_store_si128(&raw mut result as *mut __m128i, value.0);
102 };
103 result
104 }
105}
106
107impl From<M128> for __m128i {
108 #[inline(always)]
109 fn from(value: M128) -> Self {
110 value.0
111 }
112}
113
114impl SerializeBytes for M128 {
115 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
116 assert_enough_space_for(&write_buf, std::mem::size_of::<Self>())?;
117
118 let raw_value: u128 = (*self).into();
119
120 write_buf.put_u128_le(raw_value);
121 Ok(())
122 }
123}
124
125impl DeserializeBytes for M128 {
126 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
127 where
128 Self: Sized,
129 {
130 assert_enough_data_for(&read_buf, std::mem::size_of::<Self>())?;
131
132 let raw_value = read_buf.get_u128_le();
133
134 Ok(Self::from(raw_value))
135 }
136}
137
138impl FixedSizeSerializeBytes for M128 {
139 const BYTE_SIZE: usize = 16;
140}
141
142impl_divisible_bitmask!(M128, 1, 2, 4);
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 Underlier 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);
432
433impl_divisible_memcast!(
434 M128,
435 u128 => |val| M128::from(val),
436 u64 => |val| unsafe { M128(_mm_set1_epi64x(val as i64)) },
437 u32 => |val| unsafe { M128(_mm_set1_epi32(val as i32)) },
438 u16 => |val| unsafe { M128(_mm_set1_epi16(val as i16)) },
439 u8 => |val| unsafe { M128(_mm_set1_epi8(val as i8)) },
440);
441
442#[cfg(test)]
443mod tests {
444 use binius_utils::bytes::BytesMut;
445 use proptest::{arbitrary::any, proptest};
446 use rand::prelude::*;
447
448 use super::*;
449
450 fn check_roundtrip<T>(val: M128)
451 where
452 T: From<M128>,
453 M128: From<T>,
454 {
455 assert_eq!(M128::from(T::from(val)), val);
456 }
457
458 #[test]
459 fn test_constants() {
460 assert_eq!(M128::default(), M128::ZERO);
461 assert_eq!(M128::from(0u128), M128::ZERO);
462 assert_eq!(M128::from(1u128), M128::ONE);
463 }
464
465 fn get(value: M128, log_block_len: usize, index: usize) -> M128 {
466 (value >> (index << log_block_len)) & M128::from(1u128 << log_block_len)
467 }
468
469 proptest! {
470 #[test]
471 fn test_conversion(a in any::<u128>()) {
472 check_roundtrip::<u128>(a.into());
473 check_roundtrip::<__m128i>(a.into());
474 }
475
476 #[test]
477 fn test_binary_bit_operations(a in any::<u128>(), b in any::<u128>()) {
478 assert_eq!(M128::from(a & b), M128::from(a) & M128::from(b));
479 assert_eq!(M128::from(a | b), M128::from(a) | M128::from(b));
480 assert_eq!(M128::from(a ^ b), M128::from(a) ^ M128::from(b));
481 }
482
483 #[test]
484 fn test_negate(a in any::<u128>()) {
485 assert_eq!(M128::from(!a), !M128::from(a));
486 }
487
488 #[test]
489 fn test_shifts(a in any::<u128>(), b in 0..128usize) {
490 assert_eq!(M128::from(a << b), M128::from(a) << b);
491 assert_eq!(M128::from(a >> b), M128::from(a) >> b);
492 }
493
494 #[test]
495 fn test_interleave_bits(a in any::<u128>(), b in any::<u128>(), height in 0usize..7) {
496 let a = M128::from(a);
497 let b = M128::from(b);
498
499 let (c, d) = unsafe {interleave_bits(a.0, b.0, height)};
500 let (c, d) = (M128::from(c), M128::from(d));
501
502 for i in (0..128>>height).step_by(2) {
503 assert_eq!(get(c, height, i), get(a, height, i));
504 assert_eq!(get(c, height, i+1), get(b, height, i));
505 assert_eq!(get(d, height, i), get(a, height, i+1));
506 assert_eq!(get(d, height, i+1), get(b, height, i+1));
507 }
508 }
509 }
510
511 #[test]
512 fn test_eq() {
513 let a = M128::from(0u128);
514 let b = M128::from(42u128);
515 let c = M128::from(u128::MAX);
516
517 assert_eq!(a, a);
518 assert_eq!(b, b);
519 assert_eq!(c, c);
520
521 assert_ne!(a, b);
522 assert_ne!(a, c);
523 assert_ne!(b, c);
524 }
525
526 #[test]
527 fn test_serialize_and_deserialize_m128() {
528 let mut rng = StdRng::from_seed([0; 32]);
529
530 let original_value = M128::from(rng.random::<u128>());
531
532 let mut buf = BytesMut::new();
533 original_value.serialize(&mut buf).unwrap();
534
535 let deserialized_value = M128::deserialize(buf.freeze()).unwrap();
536
537 assert_eq!(original_value, deserialized_value);
538 }
539}