use crate::ir::{BufferDecl, DataType, Expr, Node, Program};
use crate::ops::{AlgebraicLaw, OpSpec, U32_INPUTS, U32_OUTPUTS};
pub const LAWS: &[AlgebraicLaw] = &[
AlgebraicLaw::Bounded { lo: 0, hi: 32 },
AlgebraicLaw::Complement {
complement_op: "primitive.bitwise.not",
universe: 32,
},
];
#[derive(Debug, Clone, Copy, Default)]
pub struct PopcountSw;
impl PopcountSw {
pub const SPEC: OpSpec = OpSpec::composition_inlinable(
"primitive.bitwise.popcount_sw",
U32_INPUTS,
U32_OUTPUTS,
LAWS,
Self::program,
);
#[must_use]
pub fn program() -> Program {
let idx = Expr::var("idx");
let a = Expr::load("a", idx.clone());
let t1 = Expr::sub(
a.clone(),
Expr::bitand(Expr::shr(a, Expr::u32(1)), Expr::u32(0x5555_5555)),
);
let t2 = Expr::add(
Expr::bitand(t1.clone(), Expr::u32(0x3333_3333)),
Expr::bitand(Expr::shr(t1, Expr::u32(2)), Expr::u32(0x3333_3333)),
);
let t3 = Expr::bitand(
Expr::add(t2.clone(), Expr::shr(t2, Expr::u32(4))),
Expr::u32(0x0f0f_0f0f),
);
let result = Expr::shr(Expr::mul(t3, Expr::u32(0x0101_0101)), Expr::u32(24));
Program::new(
vec![
BufferDecl::read("a", 0, DataType::U32),
BufferDecl::output("out", 1, DataType::U32),
],
[64, 1, 1],
vec![
Node::let_bind("idx", Expr::gid_x()),
Node::if_then(
Expr::lt(idx.clone(), Expr::buf_len("out")),
vec![Node::store("out", idx, result)],
),
],
)
}
}