pub mod ops;
pub mod query;
use std::fmt;
use rucc_ir::Type;
pub const PAIRS: usize = 3;
pub const MAX_BITS: u32 = 128;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Bits {
value: u128,
unknown: u128,
}
impl Bits {
#[must_use]
pub const fn unknown(width: u32) -> Self {
Self { value: 0, unknown: mask(width) }
}
#[must_use]
pub const fn exactly(value: u128, width: u32) -> Self {
Self { value: value & mask(width), unknown: 0 }
}
#[must_use]
pub const fn known(self, width: u32) -> u128 {
!self.unknown & mask(width)
}
#[must_use]
pub const fn value(self) -> u128 {
self.value
}
#[must_use]
pub const fn min(self) -> u128 {
self.value
}
#[must_use]
pub const fn max(self) -> u128 {
self.value | self.unknown
}
#[must_use]
pub const fn allows(self, value: u128) -> bool {
value & !self.unknown == self.value
}
#[must_use]
pub const fn from_parts(value: u128, unknown: u128, width: u32) -> Self {
let unknown = unknown & mask(width);
Self { value: value & mask(width) & !unknown, unknown }
}
#[must_use]
pub const fn unknown_bits(self) -> u128 {
self.unknown
}
#[must_use]
pub const fn low_zeros(self) -> u32 {
(self.value | self.unknown).trailing_zeros()
}
#[must_use]
pub fn meet(self, other: Self) -> Option<Self> {
let both = self.known(MAX_BITS) & other.known(MAX_BITS);
if self.value & both != other.value & both {
return None;
}
let unknown = self.unknown & other.unknown;
Some(Self { value: (self.value | other.value) & !unknown, unknown })
}
#[must_use]
pub fn join(self, other: Self) -> Self {
let differ = self.value ^ other.value;
let unknown = self.unknown | other.unknown | differ;
Self { value: self.value & !unknown, unknown }
}
fn of_interval(lo: u128, hi: u128, width: u32) -> Self {
let differ = lo ^ hi;
let below = if differ == 0 { 0 } else { u128::MAX >> differ.leading_zeros() };
let unknown = below & mask(width);
Self { value: lo & !unknown, unknown }
}
}
impl fmt::Debug for Bits {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.unknown == 0 {
return write!(f, "{:#x}", self.value);
}
write!(f, "{:#x}/{:#x}", self.value, self.unknown)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Range {
pairs: [(u128, u128); PAIRS],
count: u8,
width: u32,
bits: Bits,
}
impl Range {
#[must_use]
pub const fn empty(width: u32) -> Self {
Self {
pairs: [(0, 0); PAIRS],
count: 0,
width: clamp(width),
bits: Bits { value: 0, unknown: 0 },
}
}
#[must_use]
pub const fn full(width: u32) -> Self {
let width = clamp(width);
Self {
pairs: [(0, mask(width)), (0, 0), (0, 0)],
count: 1,
width,
bits: Bits::unknown(width),
}
}
#[must_use]
pub fn of(ty: Type) -> Self {
if ty.is_int() && ty.is_scalar() {
return Self::full(ty.bits());
}
Self::full(MAX_BITS)
}
#[must_use]
pub fn exactly(value: u128, width: u32) -> Self {
let width = clamp(width);
let value = value & mask(width);
Self {
pairs: [(value, value), (0, 0), (0, 0)],
count: 1,
width,
bits: Bits::exactly(value, width),
}
}
#[must_use]
pub fn between(lo: u128, hi: u128, width: u32) -> Self {
let width = clamp(width);
let (lo, hi) = (lo & mask(width), hi & mask(width));
if lo <= hi {
return Self::from_pairs(&[(lo, hi)], width);
}
Self::from_pairs(&[(0, hi), (lo, mask(width))], width)
}
#[must_use]
pub fn signed_between(lo: i128, hi: i128, width: u32) -> Self {
let width = clamp(width);
let (low, high) = signed_limits(width);
if lo > hi || lo > high || hi < low {
return Self::empty(width);
}
let (lo, hi) = (lo.max(low), hi.min(high));
Self::between(lo as u128, hi as u128, width)
}
#[must_use]
pub fn other_than(value: u128, width: u32) -> Self {
let width = clamp(width);
let value = value & mask(width);
let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(2);
if value > 0 {
pairs.push((0, value - 1));
}
if value < mask(width) {
pairs.push((value + 1, mask(width)));
}
Self::from_pairs(&pairs, width)
}
#[must_use]
pub fn from_pairs(pairs: &[(u128, u128)], width: u32) -> Self {
let width = clamp(width);
let mut sorted: Vec<(u128, u128)> = pairs
.iter()
.map(|&(lo, hi)| (lo & mask(width), hi & mask(width)))
.filter(|&(lo, hi)| lo <= hi)
.collect();
sorted.sort_unstable();
let mut merged: Vec<(u128, u128)> = Vec::with_capacity(sorted.len());
for (lo, hi) in sorted {
match merged.last_mut() {
Some(last) if lo <= last.1.saturating_add(1) => last.1 = last.1.max(hi),
_ => merged.push((lo, hi)),
}
}
if merged.len() > PAIRS {
let tail = merged.get(PAIRS - 1..).unwrap_or_default().to_vec();
let lo = tail.iter().map(|pair| pair.0).min().unwrap_or(0);
let hi = tail.iter().map(|pair| pair.1).max().unwrap_or(0);
merged.truncate(PAIRS - 1);
merged.push((lo, hi));
}
let mut range = Self::empty(width);
for (index, &pair) in merged.iter().enumerate() {
range.pairs[index] = pair;
}
range.count = u8::try_from(merged.len().min(PAIRS)).unwrap_or(0);
range.bits = range.bits_of_pairs();
range
}
#[must_use]
pub fn narrow(self, bits: Bits) -> Self {
let Some(bits) = self.bits.meet(bits) else {
return Self::empty(self.width);
};
if self.is_empty() {
return self;
}
let (low, high) = (bits.min(), bits.max());
let step = match bits.low_zeros() {
zeros if zeros == 0 || zeros >= self.width => 1,
zeros => 1u128 << zeros,
};
let kept: Vec<(u128, u128)> = self
.pairs()
.iter()
.map(|&(lo, hi)| (lo.max(low), hi.min(high)))
.filter(|&(lo, hi)| lo <= hi)
.filter_map(|(lo, hi)| {
Some((lo.checked_add(step - 1)? & !(step - 1), hi & !(step - 1)))
})
.filter(|&(lo, hi)| lo <= hi)
.collect();
let mut range = Self::from_pairs(&kept, self.width);
range.bits = match range.bits.meet(bits) {
Some(bits) => bits,
None => return Self::empty(self.width),
};
range
}
#[must_use]
pub const fn width(self) -> u32 {
self.width
}
#[must_use]
pub fn pairs(&self) -> &[(u128, u128)] {
&self.pairs[..self.count as usize]
}
#[must_use]
pub const fn bits(self) -> Bits {
self.bits
}
#[must_use]
pub fn list(self, limit: usize) -> Option<Vec<u128>> {
let mut values = Vec::new();
for &(lo, hi) in self.pairs() {
if hi - lo >= limit as u128 {
return None;
}
for value in lo..=hi {
if values.len() == limit {
return None;
}
values.push(value);
}
}
Some(values)
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.count == 0
}
#[must_use]
pub fn is_full(self) -> bool {
match self.pairs() {
[(0, hi)] => *hi == mask(self.width),
_ => false,
}
}
#[must_use]
pub fn singleton(self) -> Option<u128> {
match self.pairs() {
[(lo, hi)] if lo == hi => Some(*lo),
_ => None,
}
}
#[must_use]
pub fn contains(self, value: u128) -> bool {
let value = value & mask(self.width);
self.bits.allows(value) && self.pairs().iter().any(|&(lo, hi)| lo <= value && value <= hi)
}
#[must_use]
pub fn unsigned_bounds(self) -> Option<(u128, u128)> {
let pairs = self.pairs();
Some((pairs.first()?.0, pairs.last()?.1))
}
#[must_use]
pub fn signed_bounds(self) -> Option<(i128, i128)> {
let pairs = self.pairs();
let (first, _) = *pairs.first()?;
let (_, last) = *pairs.last()?;
let boundary = sign_bit(self.width);
let negative = pairs.iter().find(|&&(_, hi)| hi >= boundary);
let positive = pairs.iter().rev().find(|&&(lo, _)| lo < boundary);
let min = match negative {
Some(&(lo, _)) => signed(lo.max(boundary), self.width),
None => signed(first, self.width),
};
let max = match positive {
Some(&(_, hi)) => signed(hi.min(boundary - 1), self.width),
None => signed(last, self.width),
};
Some((min, max))
}
#[must_use]
pub fn nonzero(self) -> bool {
!self.is_empty() && !self.contains(0)
}
#[must_use]
pub fn fits_unsigned(self, bits: u32) -> bool {
match self.unsigned_bounds() {
None => true,
Some((_, high)) => bits >= self.width || high <= mask(bits),
}
}
#[must_use]
pub fn fits_signed(self, bits: u32) -> bool {
let Some((low, high)) = self.signed_bounds() else {
return true;
};
if bits >= self.width {
return true;
}
let limit = 1i128 << (bits - 1);
-limit <= low && high < limit
}
#[must_use]
pub fn union(self, other: Self) -> Self {
assert_eq!(self.width, other.width, "these are ranges of different widths");
if self.is_empty() {
return other;
}
if other.is_empty() {
return self;
}
let mut pairs = self.pairs().to_vec();
pairs.extend_from_slice(other.pairs());
let range = Self::from_pairs(&pairs, self.width);
range.narrow(self.bits.join(other.bits))
}
#[must_use]
pub fn intersect(self, other: Self) -> Self {
assert_eq!(self.width, other.width, "these are ranges of different widths");
let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(PAIRS * PAIRS);
for &(lo, hi) in self.pairs() {
for &(start, end) in other.pairs() {
let (lo, hi) = (lo.max(start), hi.min(end));
if lo <= hi {
pairs.push((lo, hi));
}
}
}
Self::from_pairs(&pairs, self.width).narrow(self.bits).narrow(other.bits)
}
#[must_use]
pub fn invert(self) -> Self {
let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(PAIRS + 1);
let mut next = 0u128;
for &(lo, hi) in self.pairs() {
if lo > next {
pairs.push((next, lo - 1));
}
let Some(after) = hi.checked_add(1) else {
return Self::from_pairs(&pairs, self.width);
};
next = after;
}
if next <= mask(self.width) {
pairs.push((next, mask(self.width)));
}
Self::from_pairs(&pairs, self.width)
}
fn bits_of_pairs(&self) -> Bits {
let mut bits: Option<Bits> = None;
for &(lo, hi) in self.pairs() {
let one = Bits::of_interval(lo, hi, self.width);
bits = Some(bits.map_or(one, |had: Bits| had.join(one)));
}
bits.unwrap_or(Bits { value: 0, unknown: 0 })
}
}
impl fmt::Debug for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "i{}", self.width)?;
if self.is_empty() {
return write!(f, " empty");
}
for (index, &(lo, hi)) in self.pairs().iter().enumerate() {
let separator = if index == 0 { " " } else { " u " };
if lo == hi {
write!(f, "{separator}[{lo:#x}]")?;
} else {
write!(f, "{separator}[{lo:#x}, {hi:#x}]")?;
}
}
if self.bits.unknown != mask(self.width) {
write!(f, " bits {:?}", self.bits)?;
}
Ok(())
}
}
const fn mask(width: u32) -> u128 {
if width >= MAX_BITS { u128::MAX } else { (1u128 << width) - 1 }
}
const fn sign_bit(width: u32) -> u128 {
1u128 << (width - 1)
}
const fn signed(value: u128, width: u32) -> i128 {
let shift = MAX_BITS - width;
((value << shift) as i128) >> shift
}
const fn signed_limits(width: u32) -> (i128, i128) {
if width >= MAX_BITS {
return (i128::MIN, i128::MAX);
}
let high = (1i128 << (width - 1)) - 1;
(!high, high)
}
const fn clamp(width: u32) -> u32 {
if width == 0 {
return 1;
}
if width > MAX_BITS { MAX_BITS } else { width }
}
#[cfg(test)]
mod tests {
use super::*;
fn every(width: u32) -> Vec<u128> {
(0..=mask(width)).collect()
}
fn held(range: Range) -> Vec<u128> {
every(range.width()).into_iter().filter(|&value| range.contains(value)).collect()
}
fn all_at(width: u32) -> Vec<Range> {
let mut ranges = Vec::new();
for subset in 0u64..1 << (1u64 << width) {
let values: Vec<u128> =
(0..=mask(width)).filter(|&value| subset & (1 << value) != 0).collect();
let pairs = runs(&values);
if pairs.len() > PAIRS {
continue;
}
let range = Range::from_pairs(&pairs, width);
if held(range) == values {
ranges.push(range);
}
}
ranges
}
fn runs(values: &[u128]) -> Vec<(u128, u128)> {
let mut pairs: Vec<(u128, u128)> = Vec::new();
for &value in values {
match pairs.last_mut() {
Some(last) if last.1 + 1 == value => last.1 = value,
_ => pairs.push((value, value)),
}
}
pairs
}
#[test]
fn nothing_and_everything_are_what_they_say() {
let empty = Range::empty(8);
assert!(empty.is_empty());
assert!(!empty.is_full());
assert!(!empty.contains(0));
assert_eq!(empty.unsigned_bounds(), None);
assert_eq!(empty.signed_bounds(), None);
let full = Range::full(8);
assert!(full.is_full());
assert!(!full.is_empty());
assert_eq!(full.unsigned_bounds(), Some((0, 255)));
assert_eq!(full.signed_bounds(), Some((-128, 127)));
assert_eq!(full.bits(), Bits::unknown(8));
}
#[test]
fn the_fact_a_null_check_produces_is_one_interval() {
let nonzero = Range::other_than(0, 32);
assert_eq!(nonzero.pairs(), [(1, 0xffff_ffff)]);
assert!(nonzero.nonzero());
assert!(!nonzero.contains(0));
assert_eq!(nonzero.pairs().len(), 1);
}
#[test]
fn a_signed_interval_around_zero_is_two_intervals_and_still_exact() {
let around = Range::between(0xfb, 0x05, 8);
assert_eq!(around.pairs(), [(0x00, 0x05), (0xfb, 0xff)]);
assert_eq!(around.signed_bounds(), Some((-5, 5)));
assert_eq!(around.unsigned_bounds(), Some((0, 255)));
}
#[test]
fn signed_bounds_are_right_wherever_the_range_sits() {
for width in [4u32, 8, 16, 32, 64] {
let cases: [(Range, (i128, i128)); 4] = [
(Range::full(width), (-(1 << (width - 1)), (1 << (width - 1)) - 1)),
(Range::exactly(mask(width), width), (-1, -1)),
(Range::between(0, 1, width), (0, 1)),
(Range::between(sign_bit(width), mask(width), width), (-(1 << (width - 1)), -1)),
];
for (range, want) in cases {
assert_eq!(range.signed_bounds(), Some(want), "{range:?} at {width}");
}
}
}
#[test]
fn an_interval_says_what_bits_it_knows() {
let range = Range::between(8, 11, 8);
assert_eq!(range.bits().known(8), 0b1111_1100);
assert_eq!(range.bits().value(), 0b0000_1000);
assert_eq!(Range::exactly(0x5a, 8).bits(), Bits::exactly(0x5a, 8));
}
#[test]
fn known_bits_pull_the_intervals_in() {
let multiples = Bits { value: 0, unknown: 0b1111_1000 };
let range = Range::full(8).narrow(multiples);
assert_eq!(range.unsigned_bounds(), Some((0, 0b1111_1000)));
assert!(range.contains(0b1111_1000));
assert!(!range.contains(0b1111_1001));
}
#[test]
fn intervals_and_bits_that_contradict_each_other_come_back_empty() {
let odd = Bits { value: 1, unknown: !1 & mask(8) };
assert!(Range::between(8, 8, 8).narrow(odd).is_empty());
let evens = Range::full(8).narrow(Bits { value: 0, unknown: !1 & mask(8) });
assert!(evens.intersect(Range::exactly(7, 8)).is_empty());
}
#[test]
fn more_intervals_than_there_is_room_for_lose_precision_and_not_soundness() {
let pairs = [(0, 0), (2, 2), (4, 4), (6, 6), (8, 8)];
let range = Range::from_pairs(&pairs, 4);
assert_eq!(range.pairs().len(), PAIRS);
for (value, _) in pairs {
assert!(range.contains(value), "{range:?} lost {value}");
}
}
#[test]
fn a_range_holds_exactly_what_it_was_built_from() {
for range in all_at(4) {
let listed = held(range);
assert_eq!(Range::from_pairs(&runs(&listed), 4), range, "{range:?}");
}
}
#[test]
fn union_and_intersection_are_the_set_operations_they_are_named_after() {
let all = all_at(3);
for &a in &all {
for &b in &all {
let (left, right) = (held(a), held(b));
let either: Vec<u128> = every(3)
.into_iter()
.filter(|value| left.contains(value) || right.contains(value))
.collect();
check(a.union(b), &either, &format!("{a:?} u {b:?}"));
let both: Vec<u128> =
left.iter().copied().filter(|value| right.contains(value)).collect();
check(a.intersect(b), &both, &format!("{a:?} n {b:?}"));
}
}
}
#[test]
fn inverting_gives_back_everything_that_was_not_in_it() {
for range in all_at(4) {
let want: Vec<u128> =
every(4).into_iter().filter(|value| !range.contains(*value)).collect();
let flipped = range.invert();
check(flipped, &want, &format!("not({range:?})"));
if runs(&want).len() <= PAIRS {
assert_eq!(held(flipped.invert()), held(range), "not(not({range:?}))");
}
}
}
fn check(got: Range, want: &[u128], what: &str) {
let listed = held(got);
for value in want {
assert!(listed.contains(value), "{what} lost {value:#x}");
}
if runs(want).len() <= PAIRS {
assert_eq!(listed, want, "{what} gave up with room to spare");
}
}
#[test]
fn the_bits_of_a_range_are_true_of_every_value_in_it() {
for range in all_at(4) {
let bits = range.bits();
for value in held(range) {
assert!(bits.allows(value), "{range:?} says {value:#x} but its bits do not");
}
}
}
#[test]
fn the_bounds_of_a_range_are_the_bounds_of_what_is_in_it() {
for range in all_at(4) {
let values = held(range);
let Some(&first) = values.first() else {
assert_eq!(range.unsigned_bounds(), None);
continue;
};
let last = *values.last().expect("not empty");
assert_eq!(range.unsigned_bounds(), Some((first, last)), "{range:?}");
let as_signed: Vec<i128> = values.iter().map(|&v| signed(v, 4)).collect();
let low = *as_signed.iter().min().expect("not empty");
let high = *as_signed.iter().max().expect("not empty");
assert_eq!(range.signed_bounds(), Some((low, high)), "{range:?}");
}
}
#[test]
fn fitting_in_a_narrower_type_means_every_value_in_it_does() {
for range in all_at(4) {
for bits in 1..=4u32 {
let values = held(range);
let unsigned = values.iter().all(|&value| value <= mask(bits));
assert_eq!(range.fits_unsigned(bits), unsigned, "{range:?} in u{bits}");
let limit = 1i128 << (bits - 1);
let signed_fits =
values.iter().all(|&value| (-limit..limit).contains(&signed(value, 4)));
assert_eq!(range.fits_signed(bits), signed_fits, "{range:?} in i{bits}");
}
}
}
#[test]
fn a_type_that_is_not_a_scalar_integer_gets_a_range_that_says_nothing() {
assert!(Range::of(Type::PTR).is_full());
assert!(Range::of(Type::int(32)).is_full());
assert_eq!(Range::of(Type::int(32)).width(), 32);
assert_eq!(Range::of(Type::PTR).width(), MAX_BITS);
}
#[test]
fn a_width_wider_than_this_reasons_about_is_clamped_rather_than_wrong() {
let wide = Range::full(256);
assert_eq!(wide.width(), MAX_BITS);
assert!(wide.is_full());
}
#[test]
fn bits_that_contradict_each_other_have_no_meet() {
let zero = Bits::exactly(0, 8);
let one = Bits::exactly(1, 8);
assert_eq!(zero.meet(one), None);
assert_eq!(zero.meet(Bits::unknown(8)), Some(zero));
assert_eq!(zero.join(one), Bits { value: 0, unknown: 1 });
}
}