use super::CombinedBitvector;
use crate::{
abstr::{combined::DomainCombination, BitvectorDomain},
forward::*,
misc::{BitvectorBound, CBound},
};
macro_rules! generate_uni_op {
($op_name:ident) => {
fn $op_name(self) -> Self {
Self::combine(self.left.$op_name(), self.right.$op_name())
}
};
}
macro_rules! generate_bi_op {
($op_name:ident, $output:ty) => {
fn $op_name(self, rhs: Self) -> $output {
<$output>::combine(self.left.$op_name(rhs.left), self.right.$op_name(rhs.right))
}
};
}
macro_rules! generate_divrem_op {
($op_name:ident, $output:ty) => {
fn $op_name(self, rhs: Self) -> $output {
Self::combine_panic_result(self.left.$op_name(rhs.left), self.right.$op_name(rhs.right))
}
};
}
macro_rules! generate_cmp_op {
($op_name:ident, $output:ty) => {
fn $op_name(self, rhs: Self) -> $output {
Self::combine_boolean(self.left.$op_name(rhs.left), self.right.$op_name(rhs.right))
}
};
}
impl<B: BitvectorBound, D: DomainCombination<B>> Bitwise for CombinedBitvector<B, D>
where
D::Left: Bitwise,
D::Right: Bitwise,
{
generate_uni_op!(bit_not);
generate_bi_op!(bit_and, Self);
generate_bi_op!(bit_or, Self);
generate_bi_op!(bit_xor, Self);
}
impl<B: BitvectorBound, D: DomainCombination<B>> HwArith for CombinedBitvector<B, D>
where
D::Left: HwArith<DivRemResult = PanicResult<D::Left>>,
D::Right: HwArith<DivRemResult = PanicResult<D::Right>>,
{
type DivRemResult = PanicResult<Self>;
generate_uni_op!(arith_neg);
generate_bi_op!(add, Self);
generate_bi_op!(sub, Self);
generate_bi_op!(mul, Self);
generate_divrem_op!(udiv, PanicResult<Self>);
generate_divrem_op!(urem, PanicResult<Self>);
generate_divrem_op!(sdiv, PanicResult<Self>);
generate_divrem_op!(srem, PanicResult<Self>);
}
impl<B: BitvectorBound, D: DomainCombination<B>> TypedCmp for CombinedBitvector<B, D>
where
D::Left: TypedCmp<Output = Boolean>,
D::Right: TypedCmp<Output = Boolean>,
{
type Output = Boolean;
generate_cmp_op!(ult, Self::Output);
generate_cmp_op!(ule, Self::Output);
generate_cmp_op!(slt, Self::Output);
generate_cmp_op!(sle, Self::Output);
}
impl<B: BitvectorBound, D: DomainCombination<B>> TypedEq for CombinedBitvector<B, D>
where
D::Left: TypedEq<Output = Boolean>,
D::Right: TypedEq<Output = Boolean>,
{
type Output = Boolean;
generate_cmp_op!(eq, Self::Output);
generate_cmp_op!(ne, Self::Output);
}
impl<B: BitvectorBound, D: DomainCombination<B>> HwShift for CombinedBitvector<B, D>
where
D::Left: HwShift<Output = D::Left>,
D::Right: HwShift<Output = D::Right>,
{
type Output = Self;
generate_bi_op!(logic_shl, Self::Output);
generate_bi_op!(logic_shr, Self::Output);
generate_bi_op!(arith_shr, Self::Output);
}
impl<B: BitvectorBound, D: DomainCombination<B>, X: BitvectorBound> BExt<X>
for CombinedBitvector<B, D>
where
D::Left: BExt<X, Output = <D::Left as BitvectorDomain>::General<X>>,
D::Right: BExt<X, Output = <D::Right as BitvectorDomain>::General<X>>,
{
type Output = CombinedBitvector<X, D::General<X>>;
fn uext(self, new_bound: X) -> Self::Output {
Self::Output::combine(self.left.uext(new_bound), self.right.uext(new_bound))
}
fn sext(self, new_bound: X) -> Self::Output {
Self::Output::combine(self.left.sext(new_bound), self.right.sext(new_bound))
}
}
impl<const W: u32, const X: u32, D: DomainCombination<CBound<W>>> Ext<X>
for CombinedBitvector<CBound<W>, D>
where
D::Left: BExt<CBound<X>, Output = <D::Left as BitvectorDomain>::General<CBound<X>>>,
D::Right: BExt<CBound<X>, Output = <D::Right as BitvectorDomain>::General<CBound<X>>>,
{
type Output = CombinedBitvector<CBound<X>, D::General<CBound<X>>>;
fn uext(self) -> Self::Output {
BExt::uext(self, CBound::<X>)
}
fn sext(self) -> Self::Output {
BExt::sext(self, CBound::<X>)
}
}