#[inline]
pub(super) unsafe fn mul_1(r: *mut u64, x: *const u64, n: usize, y: u64) -> u64 {
let mut carry = 0;
unsafe {
for i in 0..n {
let p = u128::from(*x.add(i)) * u128::from(y) + u128::from(carry);
*r.add(i) = p as u64;
carry = (p >> 64) as u64;
}
}
carry
}
#[inline]
#[allow(
dead_code,
reason = "the kernel where the portable code is the kernels', and on x86_64 without BMI2"
)]
pub(crate) unsafe fn mul_1_bytes(r: *mut u8, x: *const u8, n: usize, y: u64) -> u64 {
let mut carry = 0;
unsafe {
for i in 0..n {
let xi = u64::from_le_bytes(x.add(8 * i).cast::<[u8; 8]>().read());
let p = u128::from(xi) * u128::from(y) + u128::from(carry);
r.add(8 * i)
.cast::<[u8; 8]>()
.write((p as u64).to_le_bytes());
carry = (p >> 64) as u64;
}
}
carry
}
#[inline]
pub(super) unsafe fn addmul_1(r: *mut u64, x: *const u64, n: usize, y: u64) -> u64 {
let mut carry = 0;
unsafe {
for i in 0..n {
let p =
u128::from(*x.add(i)) * u128::from(y) + u128::from(*r.add(i)) + u128::from(carry);
*r.add(i) = p as u64;
carry = (p >> 64) as u64;
}
}
carry
}
#[inline]
pub(super) unsafe fn mul_basecase(r: *mut u64, x: *const u64, nx: usize, y: *const u64, ny: usize) {
unsafe {
*r.add(nx) = mul_1(r, x, nx, *y);
for j in 1..ny {
*r.add(nx + j) = addmul_1(r.add(j), x, nx, *y.add(j));
}
}
}
#[inline]
pub(super) unsafe fn sqr_basecase(r: *mut u64, x: *const u64, n: usize) {
unsafe {
if n == 1 {
let p = u128::from(*x) * u128::from(*x);
*r = p as u64;
*r.add(1) = (p >> 64) as u64;
return;
}
*r.add(n) = mul_1(r.add(1), x.add(1), n - 1, *x);
for i in 1..n - 1 {
*r.add(n + i) = addmul_1(r.add(2 * i + 1), x.add(i + 1), n - i - 1, *x.add(i));
}
*r = 0;
*r.add(2 * n - 1) = 0;
double_and_add_squares(r, x, n);
}
}
#[inline]
pub(super) unsafe fn double_and_add_squares(r: *mut u64, x: *const u64, n: usize) {
unsafe {
let mut top = 0;
for i in 0..2 * n {
let v = *r.add(i);
*r.add(i) = (v << 1) | top;
top = v >> 63;
}
let mut carry = 0u64;
for i in 0..n {
let p = u128::from(*x.add(i)) * u128::from(*x.add(i));
let lo = u128::from(*r.add(2 * i)) + u128::from(p as u64) + u128::from(carry);
*r.add(2 * i) = lo as u64;
let hi = u128::from(*r.add(2 * i + 1)) + (p >> 64) + (lo >> 64);
*r.add(2 * i + 1) = hi as u64;
carry = (hi >> 64) as u64;
}
}
}
#[cfg_attr(target_arch = "aarch64", allow(dead_code))]
#[inline]
pub(super) unsafe fn divexact_finish(r: *mut u64, n: usize) {
let (mut q, mut borrow) = (0u64, false);
unsafe {
for i in 0..n {
let (v, b1) = q.overflowing_sub(*r.add(i));
let (v, b2) = v.overflowing_sub(u64::from(borrow));
*r.add(i) = v;
q = v;
borrow = b1 | b2;
}
}
}