use crate::kernels::{delta, EDGE_ROW0};
#[inline(always)]
fn opaque(x: u64) -> u64 {
#[cfg(target_arch = "aarch64")]
{
let mut x = x;
unsafe {
std::arch::asm!(
"/* {0} */",
inout(reg) x,
options(pure, nomem, nostack, preserves_flags),
);
}
x
}
#[cfg(not(target_arch = "aarch64"))]
x
}
#[cfg_attr(
not(all(target_arch = "aarch64", not(target_vendor = "apple"))),
allow(dead_code)
)]
#[inline(always)]
pub(crate) fn myers_step(eq: u64, vp: u64, vn: u64) -> (u64, u64) {
let sum = (eq & vp).wrapping_add(vp);
let x = sum | vp | eq;
let mh = vp & (eq | !sum);
let xv = eq | vn;
let m = xv | (vn << 1);
let xs = x << 1;
let s = xs & !(vn << 1);
let a = xs & !m;
((mh << 1) | a, xv & !s)
}
#[cfg_attr(
not(all(target_arch = "aarch64", not(target_vendor = "apple"))),
allow(dead_code)
)]
#[inline(always)]
pub(crate) fn multiword<const W: usize, I: Iterator<Item = [u64; W]>>(
m: usize,
pm_iter: I,
mut edges: Option<&mut [u8]>,
) -> isize {
let mut vp = [!0u64; W];
let mut vn = [0u64; W];
for (j, pm_row) in pm_iter.enumerate() {
let e = edges.as_ref().map_or(EDGE_ROW0, |e| e[j]);
let mut carry = e & 1 != 0;
let (mut below_ph, mut below_mh) = ((e >> 1 & 1) as u64, (e >> 2) as u64);
for k in 0..W {
let (eq, v_p, v_n) = (pm_row[k], vp[k], vn[k]);
let (sum, nc) = (eq & v_p).carrying_add(v_p, carry);
carry = nc;
let ph = v_n | !(sum | (v_p | eq));
let mh = v_p & (eq | !sum);
let xv = eq | v_n;
let ph_s = ph << 1 | below_ph;
vp[k] = opaque(mh << 1 | below_mh) | !(xv | ph_s);
vn[k] = ph_s & xv;
(below_ph, below_mh) = (opaque(ph >> 63), opaque(mh >> 63));
}
if let Some(e) = edges.as_deref_mut() {
e[j] = carry as u8 | (below_ph as u8) << 1 | (below_mh as u8) << 2;
}
}
delta(vp, vn, m)
}