use super::aig::{Aig, FALSE, L, TRUE};
use crate::BitVec;
pub type Bits = Vec<L>;
pub fn konst(v: &BitVec) -> Bits {
(0..v.width().bits())
.map(|i| if v.bit(i) == Some(true) { TRUE } else { FALSE })
.collect()
}
pub fn small(w: usize, v: u64) -> Bits {
(0..w)
.map(|i| {
if i < 64 && (v >> i) & 1 == 1 {
TRUE
} else {
FALSE
}
})
.collect()
}
pub fn not(g: &mut Aig, a: &[L]) -> Bits {
let _ = g;
a.iter().map(|&x| x ^ 1).collect()
}
pub fn and(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
a.iter().zip(b).map(|(&x, &y)| g.and(x, y)).collect()
}
pub fn or(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
a.iter().zip(b).map(|(&x, &y)| g.or(x, y)).collect()
}
pub fn xor(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
a.iter().zip(b).map(|(&x, &y)| g.xor(x, y)).collect()
}
pub fn mux(g: &mut Aig, c: L, t: &[L], e: &[L]) -> Bits {
t.iter().zip(e).map(|(&x, &y)| g.mux(c, x, y)).collect()
}
pub fn add_carry(g: &mut Aig, a: &[L], b: &[L], cin: L) -> (Bits, L) {
let mut c = cin;
let mut out = Vec::with_capacity(a.len());
for (&x, &y) in a.iter().zip(b) {
let s = g.xor(x, y);
out.push(g.xor(s, c));
c = g.maj(x, y, c);
}
(out, c)
}
pub fn add(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
add_carry(g, a, b, FALSE).0
}
pub fn sub(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
let nb = not(g, b);
add_carry(g, a, &nb, TRUE).0
}
pub fn neg(g: &mut Aig, a: &[L]) -> Bits {
let z = vec![FALSE; a.len()];
sub(g, &z, a)
}
pub fn ult(g: &mut Aig, a: &[L], b: &[L]) -> L {
let nb = not(g, b);
let (_, carry) = add_carry(g, a, &nb, TRUE);
carry ^ 1
}
pub fn ule(g: &mut Aig, a: &[L], b: &[L]) -> L {
ult(g, b, a) ^ 1
}
pub fn slt(g: &mut Aig, a: &[L], b: &[L]) -> L {
let mut a2 = a.to_vec();
let mut b2 = b.to_vec();
if let (Some(x), Some(y)) = (a2.last_mut(), b2.last_mut()) {
*x ^= 1;
*y ^= 1;
}
ult(g, &a2, &b2)
}
pub fn sle(g: &mut Aig, a: &[L], b: &[L]) -> L {
slt(g, b, a) ^ 1
}
pub fn eq(g: &mut Aig, a: &[L], b: &[L]) -> L {
let bits: Vec<L> = a.iter().zip(b).map(|(&x, &y)| g.xnor(x, y)).collect();
g.and_all(&bits)
}
pub fn mul(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
let w = a.len();
let mut acc = vec![FALSE; w];
for (i, &bi) in b.iter().enumerate() {
if bi == FALSE {
continue;
}
let mut part = vec![FALSE; w];
for j in 0..w - i {
part[i + j] = g.and(a[j], bi);
}
acc = add(g, &acc, &part);
}
acc
}
pub fn udivrem(g: &mut Aig, a: &[L], b: &[L]) -> (Bits, Bits) {
let w = a.len();
let mut r: Bits = vec![FALSE; w + 1];
let mut bw = b.to_vec();
bw.push(FALSE);
let mut q = vec![FALSE; w];
for i in (0..w).rev() {
let mut shifted = vec![a[i]];
shifted.extend_from_slice(&r[..w]);
let ge = ult(g, &shifted, &bw) ^ 1;
let diff = sub(g, &shifted, &bw);
r = mux(g, ge, &diff, &shifted);
q[i] = ge;
}
r.truncate(w);
(q, r)
}
fn abs(g: &mut Aig, a: &[L]) -> (Bits, L) {
let s = *a.last().unwrap_or(&FALSE);
let n = neg(g, a);
(mux(g, s, &n, a), s)
}
pub fn sdiv(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
let (ua, sa) = abs(g, a);
let (ub, sb) = abs(g, b);
let (q, _) = udivrem(g, &ua, &ub);
let differ = g.xor(sa, sb);
let nq = neg(g, &q);
mux(g, differ, &nq, &q)
}
pub fn srem(g: &mut Aig, a: &[L], b: &[L]) -> Bits {
let (ua, sa) = abs(g, a);
let (ub, _) = abs(g, b);
let (_, r) = udivrem(g, &ua, &ub);
let nr = neg(g, &r);
mux(g, sa, &nr, &r)
}
fn at_least(g: &mut Aig, s: &[L], w: usize) -> L {
let k = small(s.len(), w as u64);
if s.len() < 64 && (w as u64) >> s.len() != 0 {
return FALSE;
}
ult(g, s, &k) ^ 1
}
pub fn shift(g: &mut Aig, a: &[L], s: &[L], left: bool, fill: L) -> Bits {
let w = a.len();
let mut cur = a.to_vec();
let mut k = 0;
while (1usize << k) < w && k < s.len() {
let amt = 1usize << k;
let moved: Bits = (0..w)
.map(|i| {
if left {
if i >= amt { cur[i - amt] } else { FALSE }
} else if i + amt < w {
cur[i + amt]
} else {
fill
}
})
.collect();
cur = mux(g, s[k], &moved, &cur);
k += 1;
}
let over = at_least(g, s, w);
let all = vec![if left { FALSE } else { fill }; w];
mux(g, over, &all, &cur)
}
pub fn rotate(g: &mut Aig, a: &[L], s: &[L], left: bool) -> Bits {
let w = a.len();
let r = if w.is_power_of_two() {
let k = w.trailing_zeros() as usize;
let mut r: Bits = s.iter().copied().take(k).collect();
r.resize(k.max(1), FALSE);
r
} else {
let wk = small(s.len(), w as u64);
let (_, r) = udivrem(g, s, &wk);
r
};
let mut cur = a.to_vec();
for (k, &bit) in r.iter().enumerate() {
if k >= 64 || (1u64 << k) as usize >= 2 * w {
break;
}
let amt = (1usize << k) % w;
if amt == 0 {
continue;
}
let moved: Bits = (0..w)
.map(|i| {
if left {
cur[(i + w - amt) % w]
} else {
cur[(i + amt) % w]
}
})
.collect();
cur = mux(g, bit, &moved, &cur);
}
cur
}
pub fn count(g: &mut Aig, bits: &[L], w: usize) -> Bits {
let mut vals: Vec<Bits> = bits
.iter()
.map(|&b| {
let mut v = vec![FALSE; w];
if w > 0 {
v[0] = b;
}
v
})
.collect();
if vals.is_empty() {
return vec![FALSE; w];
}
while vals.len() > 1 {
let mut next = Vec::with_capacity(vals.len().div_ceil(2));
for pair in vals.chunks(2) {
next.push(if pair.len() == 2 {
add(g, &pair[0], &pair[1])
} else {
pair[0].clone()
});
}
vals = next;
}
vals.pop().unwrap_or_default()
}
pub fn popcnt(g: &mut Aig, a: &[L]) -> Bits {
count(g, a, a.len())
}
pub fn clz(g: &mut Aig, a: &[L]) -> Bits {
let mut flags = Vec::with_capacity(a.len());
let mut all_zero = TRUE;
for &b in a.iter().rev() {
all_zero = g.and(all_zero, b ^ 1);
flags.push(all_zero);
}
count(g, &flags, a.len())
}
pub fn ctz(g: &mut Aig, a: &[L]) -> Bits {
let mut flags = Vec::with_capacity(a.len());
let mut all_zero = TRUE;
for &b in a {
all_zero = g.and(all_zero, b ^ 1);
flags.push(all_zero);
}
count(g, &flags, a.len())
}
pub fn bswap(a: &[L]) -> Bits {
let w = a.len();
(0..w).map(|k| a[(w / 8 - 1 - k / 8) * 8 + k % 8]).collect()
}
pub fn bitrev(a: &[L]) -> Bits {
a.iter().rev().copied().collect()
}
pub fn mulhi(g: &mut Aig, a: &[L], b: &[L], signed: bool) -> Bits {
let w = a.len();
let ext = |x: &[L]| -> Bits {
let fill = if signed {
*x.last().unwrap_or(&FALSE)
} else {
FALSE
};
let mut v = x.to_vec();
v.resize(2 * w, fill);
v
};
let (a2, b2) = (ext(a), ext(b));
let p = mul(g, &a2, &b2);
p[w..].to_vec()
}
pub fn pdep(g: &mut Aig, x: &[L], m: &[L]) -> Bits {
let w = x.len();
let cw = (usize::BITS - w.leading_zeros()) as usize + 1;
let mut out = Vec::with_capacity(w);
let mut c: Bits = vec![FALSE; cw];
for &mi in m.iter().take(w) {
let mut pick = FALSE;
for (j, &xj) in x.iter().enumerate() {
let at = eq(g, &c, &small(cw, j as u64));
let t = g.and(at, xj);
pick = g.or(pick, t);
}
out.push(g.and(mi, pick));
let mut one = small(cw, 0);
one[0] = mi;
c = add(g, &c, &one);
}
out
}
pub fn pext(g: &mut Aig, x: &[L], m: &[L]) -> Bits {
let w = x.len();
let cw = (usize::BITS - w.leading_zeros()) as usize + 1;
let mut out = vec![FALSE; w];
let mut c: Bits = vec![FALSE; cw];
for i in 0..w {
let src = g.and(x[i], m[i]);
for (j, o) in out.iter_mut().enumerate() {
let at = eq(g, &c, &small(cw, j as u64));
let t = g.and(at, src);
*o = g.or(*o, t);
}
let mut one = small(cw, 0);
one[0] = m[i];
c = add(g, &c, &one);
}
out
}