mod gld_avx2;
mod gld_sse;
mod m31_avx2;
mod m31_sse;
mod qm31_avx2;
pub use gld_avx2::{
add_assign_gld_avx2, mul_add_gld_avx2, mul_assign_gld_avx2, mul_elementwise_gld_avx2,
mul_into_gld_avx2, sub_assign_gld_avx2,
};
pub use gld_sse::{
add_assign_gld_sse42, mul_add_gld_sse42, mul_assign_gld_sse42, mul_elementwise_gld_sse42,
mul_into_gld_sse42, sub_assign_gld_sse42,
};
pub use m31_avx2::{
add_assign_m31_avx2, mul_add_m31_avx2, mul_assign_m31_avx2, mul_elementwise_m31_avx2,
mul_into_m31_avx2, sub_assign_m31_avx2,
};
pub use m31_sse::{
add_assign_m31_sse42, mul_add_m31_sse42, mul_assign_m31_sse42, mul_elementwise_m31_sse42,
mul_into_m31_sse42, sub_assign_m31_sse42,
};
pub use qm31_avx2::{
add_assign_qm31_avx2, mul_add_qm31_avx2, mul_assign_qm31_avx2, mul_elementwise_qm31_avx2,
mul_into_qm31_avx2, sub_assign_qm31_avx2,
};
use crate::field::{goldilocks, mersenne31};
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
#[allow(clippy::cast_possible_wrap)]
const M31_P: i32 = mersenne31::MODULUS as i32; #[allow(clippy::cast_possible_wrap)]
const GLD_P: i64 = goldilocks::MODULUS as i64; #[allow(clippy::cast_possible_wrap)]
const GLD_PM1: i64 = (goldilocks::MODULUS - 1) as i64; const EPS: i64 = 0xFFFF_FFFF;
#[inline]
fn check_equal(name: &str, left_name: &str, left: usize, right_name: &str, right: usize) {
assert_eq!(
left, right,
"{name}: {left_name} is {left} bytes but {right_name} is {right} bytes"
);
}
#[inline]
fn check_elem_multiple(name: &str, len: usize, elem_bytes: usize) {
assert!(
len.is_multiple_of(elem_bytes),
"{name}: buffer of {len} bytes is not a whole number of {elem_bytes}-byte elements"
);
}
#[archmage::rite(v2)]
fn m31_mulmod128(a: __m128i, b: __m128i, p: __m128i) -> __m128i {
let a_odd = _mm_srli_epi64::<31>(a);
let b_odd = _mm_shuffle_epi32::<0b11_11_01_01>(b);
let prod_odd_dbl = _mm_mul_epu32(a_odd, b_odd);
let prod_evn = _mm_mul_epu32(a, b);
let prod_odd_lo = _mm_slli_epi64::<31>(prod_odd_dbl);
let prod_evn_hi = _mm_srli_epi64::<31>(prod_evn);
let lo_dirty = _mm_blend_epi16::<0b1100_1100>(prod_evn, prod_odd_lo);
let hi = _mm_blend_epi16::<0b1100_1100>(prod_evn_hi, prod_odd_dbl);
let lo = _mm_and_si128(lo_dirty, p);
let t = _mm_add_epi32(lo, hi);
_mm_min_epu32(t, _mm_sub_epi32(t, p))
}