use crate::{
abstr::{BitvectorDomain, CBitvectorDomain, DomainDisplay},
bitvector::interval::{SignedInterval, SignlessInterval, UnsignedInterval, WrappingInterval},
concr::{CConcreteBitvector, ConcreteBitvector, SignedBitvector, UnsignedBitvector},
misc::{BitvectorBound, CBound, Join, RBound},
};
mod arith;
mod bitwise;
mod cmp;
mod eq;
mod ext;
mod shift;
mod halves;
mod support;
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct DualInterval<B: BitvectorBound> {
near_half: SignlessInterval<B>,
far_half: SignlessInterval<B>,
}
pub type CDualInterval<const W: u32> = DualInterval<CBound<W>>;
pub type RDualInterval = DualInterval<RBound>;
use serde::{Deserialize, Serialize};
impl<B: BitvectorBound> DualInterval<B> {
pub fn new(value: u64, bound: B) -> Self {
Self::from_value(ConcreteBitvector::new(value, bound))
}
pub(crate) fn from_wrapping_intervals(intervals: &[WrappingInterval<B>]) -> Self {
let mut near_half = None;
let mut far_half = None;
for interval in intervals {
let (interval_near_half, interval_far_half) = halves::wrapping_halves(*interval);
near_half = SignlessInterval::union_opt(near_half, interval_near_half);
far_half = SignlessInterval::union_opt(far_half, interval_far_half);
}
Self::from_opt_halves(near_half, far_half)
}
fn from_unsigned_intervals(intervals: impl IntoIterator<Item = UnsignedInterval<B>>) -> Self {
let mut near_half = None;
let mut far_half = None;
for interval in intervals {
let (interval_near_half, interval_far_half) = halves::unsigned_halves(interval);
near_half = SignlessInterval::union_opt(near_half, interval_near_half);
far_half = SignlessInterval::union_opt(far_half, interval_far_half);
}
Self::from_opt_halves(near_half, far_half)
}
fn from_signed_intervals(intervals: &[SignedInterval<B>]) -> Self {
let mut near_half = None;
let mut far_half = None;
for interval in intervals {
let (interval_near_half, interval_far_half) = halves::signed_halves(*interval);
near_half = SignlessInterval::union_opt(near_half, interval_near_half);
far_half = SignlessInterval::union_opt(far_half, interval_far_half);
}
Self::from_opt_halves(near_half, far_half)
}
}
impl<B: BitvectorBound> Join for DualInterval<B> {
fn join(self, other: &Self) -> Self {
let (our_near_half, our_far_half) = self.opt_halves();
let (other_near_half, other_far_half) = other.opt_halves();
let result_near_half = match (our_near_half, other_near_half) {
(None, None) => None,
(None, Some(half)) => Some(half),
(Some(half), None) => Some(half),
(Some(our_half), Some(other_half)) => Some(our_half.union(other_half)),
};
let result_far_half = match (our_far_half, other_far_half) {
(None, None) => None,
(None, Some(half)) => Some(half),
(Some(half), None) => Some(half),
(Some(our_half), Some(other_half)) => Some(our_half.union(other_half)),
};
Self::from_opt_halves(result_near_half, result_far_half)
}
}
impl<B: BitvectorBound> BitvectorDomain for DualInterval<B> {
type Bound = B;
type General<X: BitvectorBound> = DualInterval<X>;
fn single_value(value: ConcreteBitvector<B>) -> Self {
Self::from_value(value)
}
fn top(bound: Self::Bound) -> Self {
Self {
near_half: SignlessInterval::new_full_near_halfplane(bound),
far_half: SignlessInterval::new_full_far_halfplane(bound),
}
}
fn bound(&self) -> Self::Bound {
self.near_half.bound()
}
fn meet(self, rhs: &Self) -> Option<Self> {
let (our_near_half, our_far_half) = self.opt_halves();
let (other_near_half, other_far_half) = rhs.opt_halves();
let mut result_near_half = None;
let mut result_far_half = None;
if let (Some(our_near_half), Some(other_near_half)) = (our_near_half, other_near_half) {
result_near_half = our_near_half.intersection(other_near_half);
}
if let (Some(our_far_half), Some(other_far_half)) = (our_far_half, other_far_half) {
result_far_half = our_far_half.intersection(other_far_half);
}
Self::try_from_opt_halves(result_near_half, result_far_half)
}
fn umin(&self) -> UnsignedBitvector<B> {
self.near_half.min().as_unsigned()
}
fn umax(&self) -> UnsignedBitvector<B> {
self.far_half.max().as_unsigned()
}
fn smin(&self) -> SignedBitvector<B> {
self.far_half.min().as_signed()
}
fn smax(&self) -> SignedBitvector<B> {
self.near_half.max().as_signed()
}
fn concrete_value(&self) -> Option<ConcreteBitvector<Self::Bound>> {
if self.near_half == self.far_half {
return self.near_half.concrete_value();
}
None
}
fn display(&self) -> super::BitvectorDisplay {
super::BitvectorDisplay {
domains: vec![DomainDisplay::Value(format!("{}", self))],
}
}
}
impl<const W: u32> CBitvectorDomain for CDualInterval<W> {
type Concrete = CConcreteBitvector<W>;
fn from_concrete_bitvector(value: Self::Concrete) -> Self {
let interval = SignlessInterval::from_value(value);
Self {
near_half: interval,
far_half: interval,
}
}
fn from_runtime_bitvector(value: Self::General<RBound>) -> Self {
Self {
near_half: SignlessInterval::from_runtime(value.near_half),
far_half: SignlessInterval::from_runtime(value.far_half),
}
}
fn as_runtime_bitvector(&self) -> Self::General<RBound> {
Self::General {
near_half: self.near_half.to_runtime(),
far_half: self.far_half.to_runtime(),
}
}
}