use crate::ir::{Expr, Program};
use crate::ops::primitive;
use crate::ops::{AlgebraicLaw, OpSpec, U32_OUTPUTS, U32_U32_INPUTS};
pub const LAWS: &[AlgebraicLaw] = &[AlgebraicLaw::Bounded {
lo: 0,
hi: u32::MAX,
}];
#[derive(Debug, Clone, Copy, Default)]
pub struct ExtractBits;
impl ExtractBits {
pub const SPEC: OpSpec = OpSpec::composition_inlinable(
"primitive.bitwise.extract_bits",
U32_U32_INPUTS,
U32_OUTPUTS,
LAWS,
Self::program,
);
#[must_use]
pub fn program() -> Program {
primitive::binary_u32_program(|value, packed| {
let offset = Expr::bitand(packed.clone(), Expr::u32(31));
let raw_count = Expr::bitand(Expr::shr(packed, Expr::u32(5)), Expr::u32(31));
let max_count = Expr::sub(Expr::u32(32), offset.clone());
let count = Expr::select(
Expr::le(raw_count.clone(), max_count.clone()),
raw_count,
max_count,
);
let mask = Expr::select(
Expr::eq(count.clone(), Expr::u32(32)),
Expr::u32(0xFFFF_FFFF),
Expr::sub(Expr::shl(Expr::u32(1), count.clone()), Expr::u32(1)),
);
Expr::select(
Expr::eq(count, Expr::u32(0)),
Expr::u32(0),
Expr::bitand(Expr::shr(value, offset), mask),
)
})
}
}