use crate::ir::{BufferDecl, DataType, Expr, Node, Program};
use crate::ops::AlgebraicLaw;
use crate::ops::{OpSpec, BYTES_TO_U32_OUTPUTS};
pub const ASCII_123456789_CRC32: u32 = 0xCBF4_3926;
pub const CRC32_FINAL_XOR: u32 = 0xffff_ffff;
pub const CRC32_INITIAL: u32 = 0xffff_ffff;
pub const CRC32_POLY_REFLECTED: u32 = 0xEDB8_8320;
#[must_use]
pub fn crc32_program() -> Program {
Program::new(
vec![
BufferDecl::read("input", 0, DataType::Bytes),
BufferDecl::output("out", 1, DataType::U32),
],
[1, 1, 1],
vec![
Node::let_bind("crc", Expr::u32(CRC32_INITIAL)),
Node::loop_for(
"pos",
Expr::u32(0),
Expr::buf_len("input"),
vec![
Node::assign("crc", Expr::bitxor(Expr::var("crc"), input_byte())),
Node::loop_for(
"bit",
Expr::u32(0),
Expr::u32(8),
vec![Node::assign("crc", crc_bit_step())],
),
],
),
Node::assign(
"crc",
Expr::bitxor(Expr::var("crc"), Expr::u32(CRC32_FINAL_XOR)),
),
Node::if_then(
Expr::lt(Expr::u32(0), Expr::buf_len("out")),
vec![Node::store("out", Expr::u32(0), Expr::var("crc"))],
),
],
)
}
pub fn crc_bit_step() -> Expr {
let shifted = Expr::shr(Expr::var("crc"), Expr::u32(1));
Expr::select(
Expr::ne(Expr::bitand(Expr::var("crc"), Expr::u32(1)), Expr::u32(0)),
Expr::bitxor(shifted.clone(), Expr::u32(CRC32_POLY_REFLECTED)),
shifted,
)
}
pub const EMPTY_CRC32: u32 = 0;
pub fn input_byte() -> Expr {
Expr::bitand(Expr::load("input", Expr::var("pos")), Expr::u32(0xff))
}
pub const INPUTS: &[DataType] = &[DataType::Bytes];
pub const LAWS: &[AlgebraicLaw] = &[AlgebraicLaw::Bounded {
lo: 0,
hi: u32::MAX,
}];
pub const SPEC: OpSpec = OpSpec::composition(
"hash.crc32",
INPUTS,
BYTES_TO_U32_OUTPUTS,
LAWS,
crc32_program,
);