mod ops;
mod support;
use std::hash::Hash;
use serde::{Deserialize, Serialize};
use crate::{
abstr::{
combination::DomainCombination, BitvectorDomain, Boolean, CBitvectorDomain, PanicResult,
Test,
},
concr::{CConcreteBitvector, ConcreteBitvector, SignedBitvector, UnsignedBitvector},
misc::{BitvectorBound, CBound, Join, RBound},
};
#[derive(Clone, Copy, Hash, Serialize, Deserialize)]
pub struct CombinedBitvector<B: BitvectorBound, D: DomainCombination<B>> {
left: D::Left,
right: D::Right,
}
pub type CCombinedBitvector<const W: u32, D> = CombinedBitvector<CBound<W>, D>;
pub type RCombinedBitvector<D> = CombinedBitvector<RBound, D>;
#[allow(dead_code)]
impl<B: BitvectorBound, D: DomainCombination<B>> CombinedBitvector<B, D> {
pub fn new(value: u64, bound: B) -> Self {
Self::single_value(ConcreteBitvector::new(value, bound))
}
pub(crate) fn combine(mut left: D::Left, mut right: D::Right) -> Self {
D::combine(&mut left, &mut right);
Self { left, right }
}
fn combine_boolean(three_valued: Boolean, dual_interval: Boolean) -> Boolean {
let can_be_false = three_valued.can_be_false() && dual_interval.can_be_false();
let can_be_true = three_valued.can_be_true() && dual_interval.can_be_true();
Boolean::from_bools(can_be_false, can_be_true)
}
fn combine_panic_result(
three_valued: PanicResult<D::Left>,
dual_interval: PanicResult<D::Right>,
) -> PanicResult<CombinedBitvector<B, D>> {
let panic = three_valued
.panic
.meet(&dual_interval.panic)
.expect("Combined panic meet should not be empty");
let result = Self::combine(three_valued.result, dual_interval.result);
PanicResult { panic, result }
}
pub(crate) fn from_left(left: D::Left) -> CombinedBitvector<B, D> {
let dual_interval = D::Right::top(left.bound());
Self::combine(left, dual_interval)
}
pub(crate) fn left(&self) -> &D::Left {
&self.left
}
pub(crate) fn right(&self) -> &D::Right {
&self.right
}
pub(super) fn left_mut(&mut self) -> &mut D::Left {
&mut self.left
}
pub(super) fn right_mut(&mut self) -> &mut D::Right {
&mut self.right
}
}
impl<B: BitvectorBound, D: DomainCombination<B>> Join for CombinedBitvector<B, D> {
fn join(self, other: &Self) -> Self {
let three_valued = self.left.join(&other.left);
let dual_interval = self.right.join(&other.right);
Self::combine(three_valued, dual_interval)
}
}
impl<B: BitvectorBound, D: DomainCombination<B>> BitvectorDomain for CombinedBitvector<B, D> {
type Bound = B;
type General<X: BitvectorBound> = CombinedBitvector<X, D::General<X>>;
fn single_value(value: ConcreteBitvector<Self::Bound>) -> Self {
let left = D::Left::single_value(value);
let right = D::Right::single_value(value);
Self { left, right }
}
fn top(bound: Self::Bound) -> Self {
Self {
left: D::Left::top(bound),
right: D::Right::top(bound),
}
}
fn bound(&self) -> Self::Bound {
self.left.bound()
}
fn meet(self, other: &Self) -> Option<Self> {
let left = self.left.meet(&other.left);
let right = self.right.meet(&other.right);
if let (Some(left), Some(right)) = (left, right) {
Some(Self::combine(left, right))
} else {
None
}
}
fn umin(&self) -> crate::concr::UnsignedBitvector<Self::Bound> {
UnsignedBitvector::max(self.left.umin(), self.right.umin())
}
fn umax(&self) -> crate::concr::UnsignedBitvector<Self::Bound> {
UnsignedBitvector::min(self.left.umax(), self.right.umax())
}
fn smin(&self) -> crate::concr::SignedBitvector<Self::Bound> {
SignedBitvector::max(self.left.smin(), self.right.smin())
}
fn smax(&self) -> crate::concr::SignedBitvector<Self::Bound> {
SignedBitvector::min(self.left.smax(), self.right.smax())
}
fn concrete_value(&self) -> Option<ConcreteBitvector<Self::Bound>> {
match (self.left.concrete_value(), self.right.concrete_value()) {
(None, None) => None,
(None, Some(value)) => Some(value),
(Some(value), None) => Some(value),
(Some(left), Some(right)) => {
assert_eq!(left, right);
Some(left)
}
}
}
fn get_tracker(&self) -> Option<u32> {
let left_tracker = self.left.get_tracker();
let right_tracker = self.right.get_tracker();
match (left_tracker, right_tracker) {
(None, None) => None,
(None, Some(tracker)) | (Some(tracker), None) => Some(tracker),
(Some(left), Some(right)) => {
assert_eq!(left, right);
Some(left)
}
}
}
fn assign_tracker(&mut self, tracker: Option<u32>) {
self.left.assign_tracker(tracker);
self.right.assign_tracker(tracker);
}
fn display(&self) -> super::BitvectorDisplay {
D::display(&self.left, &self.right)
}
}
impl<const W: u32, D: DomainCombination<CBound<W>>> CBitvectorDomain for CCombinedBitvector<W, D>
where
D::Left: CBitvectorDomain<Concrete = CConcreteBitvector<W>>,
D::Right: CBitvectorDomain<Concrete = CConcreteBitvector<W>>,
{
type Concrete = CConcreteBitvector<W>;
fn from_concrete_bitvector(value: Self::Concrete) -> Self {
let left = D::Left::from_concrete_bitvector(value);
let right = D::Right::from_concrete_bitvector(value);
Self::combine(left, right)
}
fn from_runtime_bitvector(value: Self::General<RBound>) -> Self {
Self {
left: D::Left::from_runtime_bitvector(value.left),
right: D::Right::from_runtime_bitvector(value.right),
}
}
fn as_runtime_bitvector(&self) -> Self::General<RBound> {
Self::General {
left: self.left.as_runtime_bitvector(),
right: self.right.as_runtime_bitvector(),
}
}
}