Skip to main content

rucc_opt/
range.rs

1//! What values an integer can hold: a few intervals, and the bits that are known.
2//!
3//! Design: `spec/optimizer/10-value-ranges.md`, sections 10.2, 10.4 and 10.7. This module is the
4//! representation and [`ops`] is the arithmetic over it. The on-demand query that walks back
5//! through branch conditions to answer what a value is at a point is the piece that comes after.
6//!
7//! Knowing a value is in `[0, 63]` is what removes a bounds check, narrows a sixty four bit
8//! multiply to thirty two, proves a shift count is in range, folds a comparison, and tells the
9//! switch lowering which of eleven cases are unreachable. Section 10.5 counts six consumers and
10//! says the first two are most of the value, which is the argument for building this well rather
11//! than building it large.
12//!
13//! # Three parts and not one
14//!
15//! **Intervals, plural.** A range is a union of disjoint intervals rather than one `[min, max]`,
16//! because the single most useful fact in a C compiler is that a value is not zero, and that is
17//! not one interval in every reading. It is what a null check produces and what a division needs.
18//! Section 10.2 asks for a small fixed number of them, and this carries [`PAIRS`] with anything
19//! beyond that collapsing to the hull, because an unbounded pair count is how a range
20//! implementation becomes a memory problem.
21//!
22//! **Known bits, on the same object.** A mask says which bits are unknown and a value says what
23//! the rest are. Section 10.2 says keeping this beside the interval rather than in a lattice of
24//! its own is the thing a from-scratch implementation gets wrong, because the two refine each
25//! other: the low three bits being zero says the value is a multiple of eight, which narrows an
26//! interval, and an interval of `[0, 15]` says the top bits are zero. [`Range::narrow`] is where
27//! that happens and every operation that builds a range ends by calling it.
28//!
29//! **Pointers are separate.** Not here. A pointer range is about null and about provenance and
30//! forcing it through integer interval arithmetic produces a pointer in `[0x1000, 0x2000]` that
31//! no target promised. Section 10.2 says GCC split `prange` out of `irange` in GCC 14 for this
32//! reason, and rucc's split is that this module is about integers and the pointer facts live with
33//! the provenance in `alias.rs`, which already has them.
34//!
35//! Floats have no range here at all. Section 10.2 says to skip them in M4: the interesting facts
36//! about a float are whether it is a NaN and what its sign is, the consumers are few, and the
37//! traps around signed zero and NaN comparison are many.
38//!
39//! # Bit patterns, not signed numbers
40//!
41//! GCC's `irange` holds bounds in the domain of its tree type, which carries a signedness. An IR
42//! type here does not: `i32` is thirty two bits and the instruction says how to read them, which
43//! is why there is an `icmp slt` and an `icmp ult`. So the intervals in this module are over the
44//! **unsigned reading of the bit pattern**, from zero to `2^width - 1`, and the signed facts are
45//! recovered from them by [`Range::signed_bounds`], which splits at the sign boundary.
46//!
47//! This is a departure from the document and it is worth saying why. The property section 10.2
48//! cares about is that a range can say a value is not zero, and in this domain that is the one
49//! interval `[1, max]` rather than the two the document's example has. What it costs is that a
50//! small signed range around zero, `[-5, 5]`, is two intervals rather than one. Both fit in
51//! [`PAIRS`], both are exact, and the domain that matches the IR is the one where the arithmetic
52//! is exact, because every operation in the IR is defined on bit patterns modulo `2^width`.
53//!
54//! # How this is wrong
55//!
56//! Section 10.7 names three ways and [`ops`] answers two of them. Wrapping: `[100, 200] + [100,
57//! 200]` in eight bits is not `[200, 400]`, and every operation there is defined modulo the
58//! width. Signed overflow: in a signed type without `-fwrapv` it may be assumed not to have
59//! happened, so the flags the instruction carries are an argument to every operation that can
60//! overflow rather than a check somewhere upstream, because a range computed under one assumption
61//! and used under the other is a miscompilation.
62//!
63//! The third is the one still open: precision loss is invisible. A range that fell back to
64//! everything because of a missing case produces correct code that is slower, forever, with no
65//! signal. There is no counter here yet because a count is only meaningful per query, and the
66//! query is what comes next.
67
68pub mod ops;
69pub mod query;
70
71use std::fmt;
72
73use rucc_ir::Type;
74
75/// How many disjoint intervals a range holds before it collapses to their hull.
76///
77/// Three, which section 10.2 says covers `x != 0`, `x != 0 && x != 1`, and the exclusions a
78/// switch produces. A fourth interval is not free: every operation over ranges is quadratic in
79/// this number, so the arithmetic that comes next pays for it nine times over.
80pub const PAIRS: usize = 3;
81
82/// The widest integer this reasons about.
83///
84/// A wider one gets [`Range::full`] and that is correct rather than a gap, because a range that
85/// says nothing is always true. The consumers in section 10.5 all ask about values that fit in a
86/// machine register, and carrying arbitrary precision through the arithmetic to serve a
87/// `_BitInt(256)` nobody has asked about would be paid for on every query.
88pub const MAX_BITS: u32 = 128;
89
90/// Which bits of a value are known, and what they are.
91///
92/// A set bit in `unknown` means that bit could be either. A clear one means `value` has it. The
93/// two are kept canonical, so a bit that is unknown is zero in `value`, which makes equality mean
94/// what it looks like.
95#[derive(Clone, Copy, PartialEq, Eq)]
96pub struct Bits {
97    value: u128,
98    unknown: u128,
99}
100
101impl Bits {
102    /// Nothing known at this width.
103    #[must_use]
104    pub const fn unknown(width: u32) -> Self {
105        Self { value: 0, unknown: mask(width) }
106    }
107
108    /// Every bit known, and these are they.
109    #[must_use]
110    pub const fn exactly(value: u128, width: u32) -> Self {
111        Self { value: value & mask(width), unknown: 0 }
112    }
113
114    /// The bits that are known, as a mask.
115    #[must_use]
116    pub const fn known(self, width: u32) -> u128 {
117        !self.unknown & mask(width)
118    }
119
120    /// What the known bits are, with the unknown ones zero.
121    #[must_use]
122    pub const fn value(self) -> u128 {
123        self.value
124    }
125
126    /// The smallest value these bits allow, which is the unknown ones all zero.
127    #[must_use]
128    pub const fn min(self) -> u128 {
129        self.value
130    }
131
132    /// The largest, which is the unknown ones all one.
133    #[must_use]
134    pub const fn max(self) -> u128 {
135        self.value | self.unknown
136    }
137
138    /// Whether this value is one these bits allow.
139    #[must_use]
140    pub const fn allows(self, value: u128) -> bool {
141        value & !self.unknown == self.value
142    }
143
144    /// Bits from a value and a mask of which of them mean nothing.
145    ///
146    /// This is the way in for an operation that worked out its answer a bit at a time, which is
147    /// every bitwise operation. The value is canonicalized, so a bit that is unknown comes back
148    /// zero however it went in.
149    #[must_use]
150    pub const fn from_parts(value: u128, unknown: u128, width: u32) -> Self {
151        let unknown = unknown & mask(width);
152        Self { value: value & mask(width) & !unknown, unknown }
153    }
154
155    /// The bits that mean nothing, as a mask.
156    #[must_use]
157    pub const fn unknown_bits(self) -> u128 {
158        self.unknown
159    }
160
161    /// How many low bits are known to be zero, which is what says a value is a multiple of a
162    /// power of two and so what an alignment fact is made of.
163    #[must_use]
164    pub const fn low_zeros(self) -> u32 {
165        (self.value | self.unknown).trailing_zeros()
166    }
167
168    /// Everything both of these know, or `None` when they contradict each other.
169    ///
170    /// A contradiction is not a failure. It is the proof that whatever produced the two facts is
171    /// on a path that is never taken, and the caller turns it into the empty range.
172    #[must_use]
173    pub fn meet(self, other: Self) -> Option<Self> {
174        let both = self.known(MAX_BITS) & other.known(MAX_BITS);
175        if self.value & both != other.value & both {
176            return None;
177        }
178        let unknown = self.unknown & other.unknown;
179        Some(Self { value: (self.value | other.value) & !unknown, unknown })
180    }
181
182    /// Only what both of these agree on, which is what a value from either place is known to be.
183    #[must_use]
184    pub fn join(self, other: Self) -> Self {
185        let differ = self.value ^ other.value;
186        let unknown = self.unknown | other.unknown | differ;
187        Self { value: self.value & !unknown, unknown }
188    }
189
190    /// The bits every value in this interval agrees on, which is the prefix the two ends share.
191    fn of_interval(lo: u128, hi: u128, width: u32) -> Self {
192        // Above the highest bit where the two ends differ, every value between them agrees with
193        // both. At and below it, some value in between has each way, since the interval is the
194        // whole run of numbers from one end to the other.
195        let differ = lo ^ hi;
196        let below = if differ == 0 { 0 } else { u128::MAX >> differ.leading_zeros() };
197        let unknown = below & mask(width);
198        Self { value: lo & !unknown, unknown }
199    }
200}
201
202impl fmt::Debug for Bits {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        if self.unknown == 0 {
205            return write!(f, "{:#x}", self.value);
206        }
207        write!(f, "{:#x}/{:#x}", self.value, self.unknown)
208    }
209}
210
211/// What an integer value can be.
212///
213/// A few disjoint intervals over the unsigned reading of the bit pattern, and the bits that are
214/// known, at a width. The two halves are kept consistent with each other by [`Range::narrow`], so
215/// a range that came out of any constructor here has intervals no wider than its bits allow and
216/// bits no vaguer than its intervals prove.
217#[derive(Clone, Copy, PartialEq, Eq)]
218pub struct Range {
219    /// The intervals, ascending, disjoint and not touching. Empty when the range is.
220    pairs: [(u128, u128); PAIRS],
221    count: u8,
222    width: u32,
223    bits: Bits,
224}
225
226impl Range {
227    /// Nothing at all, which is the range of a value on a path that is never taken.
228    #[must_use]
229    pub const fn empty(width: u32) -> Self {
230        Self {
231            pairs: [(0, 0); PAIRS],
232            count: 0,
233            width: clamp(width),
234            bits: Bits { value: 0, unknown: 0 },
235        }
236    }
237
238    /// Every value of this width, which is what is known about a value nothing has said anything
239    /// about.
240    #[must_use]
241    pub const fn full(width: u32) -> Self {
242        let width = clamp(width);
243        Self {
244            pairs: [(0, mask(width)), (0, 0), (0, 0)],
245            count: 1,
246            width,
247            bits: Bits::unknown(width),
248        }
249    }
250
251    /// Everything a value of this type can be.
252    ///
253    /// A type that is not a scalar integer gets the widest full range, because saying nothing
254    /// about a vector or a pointer is always true and this module is about integers.
255    #[must_use]
256    pub fn of(ty: Type) -> Self {
257        if ty.is_int() && ty.is_scalar() {
258            return Self::full(ty.bits());
259        }
260        Self::full(MAX_BITS)
261    }
262
263    /// One value.
264    #[must_use]
265    pub fn exactly(value: u128, width: u32) -> Self {
266        let width = clamp(width);
267        let value = value & mask(width);
268        Self {
269            pairs: [(value, value), (0, 0), (0, 0)],
270            count: 1,
271            width,
272            bits: Bits::exactly(value, width),
273        }
274    }
275
276    /// Every bit pattern from one bound to the other, inclusive, wrapping if the low bound is
277    /// above the high one.
278    ///
279    /// The wrapping case is what a signed interval becomes here: `[-5, 5]` in eight bits is
280    /// `[0xfb, 0x05]`, which is the two intervals `[0, 5]` and `[0xfb, 0xff]`, and taking the
281    /// bounds in that order is how a caller says so without having to split it itself.
282    #[must_use]
283    pub fn between(lo: u128, hi: u128, width: u32) -> Self {
284        let width = clamp(width);
285        let (lo, hi) = (lo & mask(width), hi & mask(width));
286        if lo <= hi {
287            return Self::from_pairs(&[(lo, hi)], width);
288        }
289        Self::from_pairs(&[(0, hi), (lo, mask(width))], width)
290    }
291
292    /// Every value from one signed bound to the other, inclusive.
293    ///
294    /// The bounds are read as signed numbers of that width and the intervals come out over bit
295    /// patterns, so `[-5, 5]` in eight bits becomes `[0, 5]` and `[0xfb, 0xff]` on its own. A
296    /// signed interval is always one wrapping interval in the unsigned domain, so nothing is lost
297    /// on the way through.
298    #[must_use]
299    pub fn signed_between(lo: i128, hi: i128, width: u32) -> Self {
300        let width = clamp(width);
301        let (low, high) = signed_limits(width);
302        if lo > hi || lo > high || hi < low {
303            return Self::empty(width);
304        }
305        let (lo, hi) = (lo.max(low), hi.min(high));
306        Self::between(lo as u128, hi as u128, width)
307    }
308
309    /// Every value except this one.
310    ///
311    /// `Range::other_than(0, width)` is the non-zero range, which section 10.2 calls the single
312    /// most useful range fact in a C compiler.
313    #[must_use]
314    pub fn other_than(value: u128, width: u32) -> Self {
315        let width = clamp(width);
316        let value = value & mask(width);
317        let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(2);
318        if value > 0 {
319            pairs.push((0, value - 1));
320        }
321        if value < mask(width) {
322            pairs.push((value + 1, mask(width)));
323        }
324        Self::from_pairs(&pairs, width)
325    }
326
327    /// A range from intervals that need not be sorted, disjoint or in bounds.
328    ///
329    /// This is the way in from an operation that produced a handful of intervals and does not
330    /// want to think about their order. Anything beyond [`PAIRS`] of them after merging collapses
331    /// to the hull of the ones that did not fit, which loses precision and never soundness.
332    #[must_use]
333    pub fn from_pairs(pairs: &[(u128, u128)], width: u32) -> Self {
334        let width = clamp(width);
335        let mut sorted: Vec<(u128, u128)> = pairs
336            .iter()
337            .map(|&(lo, hi)| (lo & mask(width), hi & mask(width)))
338            .filter(|&(lo, hi)| lo <= hi)
339            .collect();
340        sorted.sort_unstable();
341
342        // Merge what overlaps or touches. Two intervals that touch are one interval, and leaving
343        // them apart would spend a pair on a boundary that says nothing.
344        let mut merged: Vec<(u128, u128)> = Vec::with_capacity(sorted.len());
345        for (lo, hi) in sorted {
346            match merged.last_mut() {
347                Some(last) if lo <= last.1.saturating_add(1) => last.1 = last.1.max(hi),
348                _ => merged.push((lo, hi)),
349            }
350        }
351
352        // Too many, so the tail becomes its hull. The tail rather than the head because the
353        // intervals are sorted, so this keeps the low bound exact and gives up the shape in the
354        // middle, which is the half a consumer asks about less often.
355        if merged.len() > PAIRS {
356            let tail = merged.get(PAIRS - 1..).unwrap_or_default().to_vec();
357            let lo = tail.iter().map(|pair| pair.0).min().unwrap_or(0);
358            let hi = tail.iter().map(|pair| pair.1).max().unwrap_or(0);
359            merged.truncate(PAIRS - 1);
360            merged.push((lo, hi));
361        }
362
363        let mut range = Self::empty(width);
364        for (index, &pair) in merged.iter().enumerate() {
365            range.pairs[index] = pair;
366        }
367        range.count = u8::try_from(merged.len().min(PAIRS)).unwrap_or(0);
368        range.bits = range.bits_of_pairs();
369        range
370    }
371
372    /// The same intervals with these bits also known.
373    ///
374    /// The two refine each other here and nowhere else, which is what section 10.2 asks for. An
375    /// interval whose ends the bits rule out is pulled in to the nearest value the bits allow,
376    /// the bits are then recomputed from what survived, and a range whose halves contradict each
377    /// other comes back empty.
378    #[must_use]
379    pub fn narrow(self, bits: Bits) -> Self {
380        let Some(bits) = self.bits.meet(bits) else {
381            return Self::empty(self.width);
382        };
383        if self.is_empty() {
384            return self;
385        }
386
387        // Everything the bits allow is between their least and their greatest, so an interval
388        // outside that is empty and one that straddles the edge shrinks to fit. Then the ends
389        // move again to the nearest value with the right low zeroes, which is what turns "this is
390        // a multiple of four" and "this is somewhere in `[1, 3]`" into the one value it can be.
391        let (low, high) = (bits.min(), bits.max());
392        let step = match bits.low_zeros() {
393            zeros if zeros == 0 || zeros >= self.width => 1,
394            zeros => 1u128 << zeros,
395        };
396        let kept: Vec<(u128, u128)> = self
397            .pairs()
398            .iter()
399            .map(|&(lo, hi)| (lo.max(low), hi.min(high)))
400            .filter(|&(lo, hi)| lo <= hi)
401            .filter_map(|(lo, hi)| {
402                Some((lo.checked_add(step - 1)? & !(step - 1), hi & !(step - 1)))
403            })
404            .filter(|&(lo, hi)| lo <= hi)
405            .collect();
406
407        let mut range = Self::from_pairs(&kept, self.width);
408        range.bits = match range.bits.meet(bits) {
409            Some(bits) => bits,
410            None => return Self::empty(self.width),
411        };
412        range
413    }
414
415    /// The width the values are, in bits.
416    #[must_use]
417    pub const fn width(self) -> u32 {
418        self.width
419    }
420
421    /// The intervals, ascending and disjoint.
422    #[must_use]
423    pub fn pairs(&self) -> &[(u128, u128)] {
424        &self.pairs[..self.count as usize]
425    }
426
427    /// The bits that are known about every value in it.
428    #[must_use]
429    pub const fn bits(self) -> Bits {
430        self.bits
431    }
432
433    /// Every value in it, or `None` when there are more than that many.
434    ///
435    /// For walking a shift count or a switch selector, where the range is usually a handful of
436    /// values and enumerating them gives an exact answer that reasoning about the bounds would
437    /// round off. The limit is what stops that turning into a walk over four billion of them.
438    #[must_use]
439    pub fn list(self, limit: usize) -> Option<Vec<u128>> {
440        let mut values = Vec::new();
441        for &(lo, hi) in self.pairs() {
442            if hi - lo >= limit as u128 {
443                return None;
444            }
445            for value in lo..=hi {
446                if values.len() == limit {
447                    return None;
448                }
449                values.push(value);
450            }
451        }
452        Some(values)
453    }
454
455    /// Whether nothing is in it, which means the value is on a path that is never taken.
456    #[must_use]
457    pub const fn is_empty(self) -> bool {
458        self.count == 0
459    }
460
461    /// Whether everything is in it, which means nothing is known.
462    #[must_use]
463    pub fn is_full(self) -> bool {
464        match self.pairs() {
465            [(0, hi)] => *hi == mask(self.width),
466            _ => false,
467        }
468    }
469
470    /// The one value in it, if there is exactly one.
471    #[must_use]
472    pub fn singleton(self) -> Option<u128> {
473        match self.pairs() {
474            [(lo, hi)] if lo == hi => Some(*lo),
475            _ => None,
476        }
477    }
478
479    /// Whether this value is in it.
480    ///
481    /// A range is its intervals and its bits together, so this asks both. A value inside one of
482    /// the intervals whose bits are wrong is not in the range, which is what makes "somewhere in
483    /// `[0, 1023]` and a multiple of eight" mean the hundred and twenty eight values it says
484    /// rather than the thousand and twenty four the interval alone would.
485    #[must_use]
486    pub fn contains(self, value: u128) -> bool {
487        let value = value & mask(self.width);
488        self.bits.allows(value) && self.pairs().iter().any(|&(lo, hi)| lo <= value && value <= hi)
489    }
490
491    /// The least and greatest, read as unsigned, or `None` when the range is empty.
492    #[must_use]
493    pub fn unsigned_bounds(self) -> Option<(u128, u128)> {
494        let pairs = self.pairs();
495        Some((pairs.first()?.0, pairs.last()?.1))
496    }
497
498    /// The least and greatest, read as signed at this width, or `None` when the range is empty.
499    ///
500    /// The intervals are over bit patterns, so the signed answer is not the first and last of
501    /// them. Everything at or above the sign boundary is negative and sorts below everything
502    /// under it, so the least signed value is the first pattern at or above the boundary when
503    /// there is one and the first pattern otherwise. That reordering is the whole of what the
504    /// unsigned domain costs, and it is eleven lines.
505    #[must_use]
506    pub fn signed_bounds(self) -> Option<(i128, i128)> {
507        let pairs = self.pairs();
508        let (first, _) = *pairs.first()?;
509        let (_, last) = *pairs.last()?;
510        let boundary = sign_bit(self.width);
511        let negative = pairs.iter().find(|&&(_, hi)| hi >= boundary);
512        let positive = pairs.iter().rev().find(|&&(lo, _)| lo < boundary);
513        let min = match negative {
514            Some(&(lo, _)) => signed(lo.max(boundary), self.width),
515            None => signed(first, self.width),
516        };
517        let max = match positive {
518            Some(&(_, hi)) => signed(hi.min(boundary - 1), self.width),
519            None => signed(last, self.width),
520        };
521        Some((min, max))
522    }
523
524    /// Whether nothing in it is zero.
525    ///
526    /// The fact a null check produces and the fact a division needs, which is why it has a name
527    /// of its own rather than being spelled out at every call.
528    #[must_use]
529    pub fn nonzero(self) -> bool {
530        !self.is_empty() && !self.contains(0)
531    }
532
533    /// Whether every value in it fits in that many bits, read as unsigned.
534    #[must_use]
535    pub fn fits_unsigned(self, bits: u32) -> bool {
536        match self.unsigned_bounds() {
537            None => true,
538            Some((_, high)) => bits >= self.width || high <= mask(bits),
539        }
540    }
541
542    /// Whether every value in it fits in that many bits, read as signed.
543    #[must_use]
544    pub fn fits_signed(self, bits: u32) -> bool {
545        let Some((low, high)) = self.signed_bounds() else {
546            return true;
547        };
548        if bits >= self.width {
549            return true;
550        }
551        let limit = 1i128 << (bits - 1);
552        -limit <= low && high < limit
553    }
554
555    /// Everything in either of them.
556    ///
557    /// # Panics
558    ///
559    /// Panics if the two are of different widths, since a value is one width and combining the
560    /// ranges of two that are not is a question with no answer.
561    #[must_use]
562    pub fn union(self, other: Self) -> Self {
563        assert_eq!(self.width, other.width, "these are ranges of different widths");
564        if self.is_empty() {
565            return other;
566        }
567        if other.is_empty() {
568            return self;
569        }
570        let mut pairs = self.pairs().to_vec();
571        pairs.extend_from_slice(other.pairs());
572        let range = Self::from_pairs(&pairs, self.width);
573        // The bits of a union are only what both sides agree on, and that can be sharper than
574        // what the merged intervals show, since three ones and a hull have lost the shape the
575        // bits still remember.
576        range.narrow(self.bits.join(other.bits))
577    }
578
579    /// Everything in both of them.
580    ///
581    /// # Panics
582    ///
583    /// Panics if the two are of different widths.
584    #[must_use]
585    pub fn intersect(self, other: Self) -> Self {
586        assert_eq!(self.width, other.width, "these are ranges of different widths");
587        let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(PAIRS * PAIRS);
588        for &(lo, hi) in self.pairs() {
589            for &(start, end) in other.pairs() {
590                let (lo, hi) = (lo.max(start), hi.min(end));
591                if lo <= hi {
592                    pairs.push((lo, hi));
593                }
594            }
595        }
596        // Both sets of bits and not just the intervals, because a fact like "this is even" lives
597        // only in the bits and intersecting the intervals alone would drop it.
598        Self::from_pairs(&pairs, self.width).narrow(self.bits).narrow(other.bits)
599    }
600
601    /// Everything of this width that is not in it.
602    #[must_use]
603    pub fn invert(self) -> Self {
604        let mut pairs: Vec<(u128, u128)> = Vec::with_capacity(PAIRS + 1);
605        let mut next = 0u128;
606        for &(lo, hi) in self.pairs() {
607            if lo > next {
608                pairs.push((next, lo - 1));
609            }
610            // The top interval can end at the largest value there is, and there is nothing above
611            // it to start the next gap at.
612            let Some(after) = hi.checked_add(1) else {
613                return Self::from_pairs(&pairs, self.width);
614            };
615            next = after;
616        }
617        if next <= mask(self.width) {
618            pairs.push((next, mask(self.width)));
619        }
620        Self::from_pairs(&pairs, self.width)
621    }
622
623    /// The bits every interval agrees on.
624    fn bits_of_pairs(&self) -> Bits {
625        let mut bits: Option<Bits> = None;
626        for &(lo, hi) in self.pairs() {
627            let one = Bits::of_interval(lo, hi, self.width);
628            bits = Some(bits.map_or(one, |had: Bits| had.join(one)));
629        }
630        bits.unwrap_or(Bits { value: 0, unknown: 0 })
631    }
632}
633
634impl fmt::Debug for Range {
635    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
636        write!(f, "i{}", self.width)?;
637        if self.is_empty() {
638            return write!(f, " empty");
639        }
640        for (index, &(lo, hi)) in self.pairs().iter().enumerate() {
641            let separator = if index == 0 { " " } else { " u " };
642            if lo == hi {
643                write!(f, "{separator}[{lo:#x}]")?;
644            } else {
645                write!(f, "{separator}[{lo:#x}, {hi:#x}]")?;
646            }
647        }
648        if self.bits.unknown != mask(self.width) {
649            write!(f, " bits {:?}", self.bits)?;
650        }
651        Ok(())
652    }
653}
654
655/// Every bit of that width set.
656const fn mask(width: u32) -> u128 {
657    if width >= MAX_BITS { u128::MAX } else { (1u128 << width) - 1 }
658}
659
660/// The lowest bit pattern that reads as negative at that width.
661const fn sign_bit(width: u32) -> u128 {
662    1u128 << (width - 1)
663}
664
665/// That bit pattern read as a signed number of that width.
666const fn signed(value: u128, width: u32) -> i128 {
667    // Up to the top and back down again, which is sign extension without a branch on the width.
668    let shift = MAX_BITS - width;
669    ((value << shift) as i128) >> shift
670}
671
672/// The least and greatest signed numbers of that width.
673const fn signed_limits(width: u32) -> (i128, i128) {
674    if width >= MAX_BITS {
675        return (i128::MIN, i128::MAX);
676    }
677    let high = (1i128 << (width - 1)) - 1;
678    (!high, high)
679}
680
681/// A width this module reasons about, which is at least one bit and at most [`MAX_BITS`].
682const fn clamp(width: u32) -> u32 {
683    if width == 0 {
684        return 1;
685    }
686    if width > MAX_BITS { MAX_BITS } else { width }
687}
688
689#[cfg(test)]
690mod tests {
691    use super::*;
692
693    /// Every value of that width, as the set a range is being checked against.
694    fn every(width: u32) -> Vec<u128> {
695        (0..=mask(width)).collect()
696    }
697
698    /// The values a range says it holds, as a list.
699    fn held(range: Range) -> Vec<u128> {
700        every(range.width()).into_iter().filter(|&value| range.contains(value)).collect()
701    }
702
703    /// Every range this width can describe exactly, which is every subset of its values that
704    /// fits in [`PAIRS`] intervals.
705    ///
706    /// Section 10.4 says a claim about ranges at width four is exhaustively checkable, and this
707    /// is what makes that true of the representation as well as of the arithmetic to come. Width
708    /// four is ten thousand ranges, which is nothing to walk once and too many to walk against
709    /// each other, so the properties about one range use four and the properties about two use
710    /// three.
711    fn all_at(width: u32) -> Vec<Range> {
712        let mut ranges = Vec::new();
713        for subset in 0u64..1 << (1u64 << width) {
714            let values: Vec<u128> =
715                (0..=mask(width)).filter(|&value| subset & (1 << value) != 0).collect();
716            let pairs = runs(&values);
717            if pairs.len() > PAIRS {
718                continue;
719            }
720            let range = Range::from_pairs(&pairs, width);
721            // Only the subsets a range describes exactly, so a property that fails is a property
722            // and not a rounding.
723            if held(range) == values {
724                ranges.push(range);
725            }
726        }
727        ranges
728    }
729
730    /// The values grouped into runs of consecutive ones.
731    fn runs(values: &[u128]) -> Vec<(u128, u128)> {
732        let mut pairs: Vec<(u128, u128)> = Vec::new();
733        for &value in values {
734            match pairs.last_mut() {
735                Some(last) if last.1 + 1 == value => last.1 = value,
736                _ => pairs.push((value, value)),
737            }
738        }
739        pairs
740    }
741
742    #[test]
743    fn nothing_and_everything_are_what_they_say() {
744        let empty = Range::empty(8);
745        assert!(empty.is_empty());
746        assert!(!empty.is_full());
747        assert!(!empty.contains(0));
748        assert_eq!(empty.unsigned_bounds(), None);
749        assert_eq!(empty.signed_bounds(), None);
750
751        let full = Range::full(8);
752        assert!(full.is_full());
753        assert!(!full.is_empty());
754        assert_eq!(full.unsigned_bounds(), Some((0, 255)));
755        assert_eq!(full.signed_bounds(), Some((-128, 127)));
756        assert_eq!(full.bits(), Bits::unknown(8));
757    }
758
759    #[test]
760    fn the_fact_a_null_check_produces_is_one_interval() {
761        let nonzero = Range::other_than(0, 32);
762        assert_eq!(nonzero.pairs(), [(1, 0xffff_ffff)]);
763        assert!(nonzero.nonzero());
764        assert!(!nonzero.contains(0));
765        // And the reason the domain is bit patterns rather than signed numbers: this is the fact
766        // section 10.2 calls the most useful one in a C compiler, and here it costs one pair.
767        assert_eq!(nonzero.pairs().len(), 1);
768    }
769
770    #[test]
771    fn a_signed_interval_around_zero_is_two_intervals_and_still_exact() {
772        // What `[-5, 5]` in eight bits comes to, which is the case the unsigned domain pays for.
773        let around = Range::between(0xfb, 0x05, 8);
774        assert_eq!(around.pairs(), [(0x00, 0x05), (0xfb, 0xff)]);
775        assert_eq!(around.signed_bounds(), Some((-5, 5)));
776        assert_eq!(around.unsigned_bounds(), Some((0, 255)));
777    }
778
779    #[test]
780    fn signed_bounds_are_right_wherever_the_range_sits() {
781        for width in [4u32, 8, 16, 32, 64] {
782            let cases: [(Range, (i128, i128)); 4] = [
783                (Range::full(width), (-(1 << (width - 1)), (1 << (width - 1)) - 1)),
784                (Range::exactly(mask(width), width), (-1, -1)),
785                (Range::between(0, 1, width), (0, 1)),
786                (Range::between(sign_bit(width), mask(width), width), (-(1 << (width - 1)), -1)),
787            ];
788            for (range, want) in cases {
789                assert_eq!(range.signed_bounds(), Some(want), "{range:?} at {width}");
790            }
791        }
792    }
793
794    #[test]
795    fn an_interval_says_what_bits_it_knows() {
796        // Everything from 8 to 11 has the top five bits of a byte clear and the fourth set.
797        let range = Range::between(8, 11, 8);
798        assert_eq!(range.bits().known(8), 0b1111_1100);
799        assert_eq!(range.bits().value(), 0b0000_1000);
800
801        // And a single value knows all of them.
802        assert_eq!(Range::exactly(0x5a, 8).bits(), Bits::exactly(0x5a, 8));
803    }
804
805    #[test]
806    fn known_bits_pull_the_intervals_in() {
807        // Multiples of eight, from anywhere in a byte, is 0, 8, 16 and so on, so the range that
808        // was everything comes back with the ends it can actually reach.
809        let multiples = Bits { value: 0, unknown: 0b1111_1000 };
810        let range = Range::full(8).narrow(multiples);
811        assert_eq!(range.unsigned_bounds(), Some((0, 0b1111_1000)));
812        assert!(range.contains(0b1111_1000));
813        assert!(!range.contains(0b1111_1001));
814    }
815
816    #[test]
817    fn intervals_and_bits_that_contradict_each_other_come_back_empty() {
818        // Nothing between 8 and 11 is odd.
819        let odd = Bits { value: 1, unknown: !1 & mask(8) };
820        assert!(Range::between(8, 8, 8).narrow(odd).is_empty());
821        // And the same the other way about, through an intersection.
822        let evens = Range::full(8).narrow(Bits { value: 0, unknown: !1 & mask(8) });
823        assert!(evens.intersect(Range::exactly(7, 8)).is_empty());
824    }
825
826    #[test]
827    fn more_intervals_than_there_is_room_for_lose_precision_and_not_soundness() {
828        // Five separate values in four bits, which is two more than a range can hold.
829        let pairs = [(0, 0), (2, 2), (4, 4), (6, 6), (8, 8)];
830        let range = Range::from_pairs(&pairs, 4);
831        assert_eq!(range.pairs().len(), PAIRS);
832        for (value, _) in pairs {
833            assert!(range.contains(value), "{range:?} lost {value}");
834        }
835    }
836
837    #[test]
838    fn a_range_holds_exactly_what_it_was_built_from() {
839        for range in all_at(4) {
840            let listed = held(range);
841            assert_eq!(Range::from_pairs(&runs(&listed), 4), range, "{range:?}");
842        }
843    }
844
845    #[test]
846    fn union_and_intersection_are_the_set_operations_they_are_named_after() {
847        // Three bits rather than four because this is quadratic in the number of ranges, and the
848        // property does not get any truer with ten thousand of them on each side.
849        let all = all_at(3);
850        for &a in &all {
851            for &b in &all {
852                let (left, right) = (held(a), held(b));
853
854                let either: Vec<u128> = every(3)
855                    .into_iter()
856                    .filter(|value| left.contains(value) || right.contains(value))
857                    .collect();
858                check(a.union(b), &either, &format!("{a:?} u {b:?}"));
859
860                let both: Vec<u128> =
861                    left.iter().copied().filter(|value| right.contains(value)).collect();
862                check(a.intersect(b), &both, &format!("{a:?} n {b:?}"));
863            }
864        }
865    }
866
867    #[test]
868    fn inverting_gives_back_everything_that_was_not_in_it() {
869        for range in all_at(4) {
870            let want: Vec<u128> =
871                every(4).into_iter().filter(|value| !range.contains(*value)).collect();
872            let flipped = range.invert();
873            check(flipped, &want, &format!("not({range:?})"));
874            // The complement of a complement is what it started with, and both of them fit,
875            // since a range that fits is one whose complement collapsed to at most three runs.
876            if runs(&want).len() <= PAIRS {
877                assert_eq!(held(flipped.invert()), held(range), "not(not({range:?}))");
878            }
879        }
880    }
881
882    /// The result holds everything it should, and holds nothing more whenever there was room to
883    /// say so.
884    ///
885    /// The asymmetry is the whole contract of a fixed pair count. Losing a value would be a
886    /// miscompilation, so that is checked always. Gaining one is precision loss, so it is
887    /// allowed, but only when the exact answer needed more than [`PAIRS`] intervals: a range that
888    /// gave up with room to spare is a bug in the merging and not a limit of the representation.
889    fn check(got: Range, want: &[u128], what: &str) {
890        let listed = held(got);
891        for value in want {
892            assert!(listed.contains(value), "{what} lost {value:#x}");
893        }
894        if runs(want).len() <= PAIRS {
895            assert_eq!(listed, want, "{what} gave up with room to spare");
896        }
897    }
898
899    #[test]
900    fn the_bits_of_a_range_are_true_of_every_value_in_it() {
901        for range in all_at(4) {
902            let bits = range.bits();
903            for value in held(range) {
904                assert!(bits.allows(value), "{range:?} says {value:#x} but its bits do not");
905            }
906        }
907    }
908
909    #[test]
910    fn the_bounds_of_a_range_are_the_bounds_of_what_is_in_it() {
911        for range in all_at(4) {
912            let values = held(range);
913            let Some(&first) = values.first() else {
914                assert_eq!(range.unsigned_bounds(), None);
915                continue;
916            };
917            let last = *values.last().expect("not empty");
918            assert_eq!(range.unsigned_bounds(), Some((first, last)), "{range:?}");
919
920            let as_signed: Vec<i128> = values.iter().map(|&v| signed(v, 4)).collect();
921            let low = *as_signed.iter().min().expect("not empty");
922            let high = *as_signed.iter().max().expect("not empty");
923            assert_eq!(range.signed_bounds(), Some((low, high)), "{range:?}");
924        }
925    }
926
927    #[test]
928    fn fitting_in_a_narrower_type_means_every_value_in_it_does() {
929        for range in all_at(4) {
930            for bits in 1..=4u32 {
931                let values = held(range);
932                let unsigned = values.iter().all(|&value| value <= mask(bits));
933                assert_eq!(range.fits_unsigned(bits), unsigned, "{range:?} in u{bits}");
934
935                let limit = 1i128 << (bits - 1);
936                let signed_fits =
937                    values.iter().all(|&value| (-limit..limit).contains(&signed(value, 4)));
938                assert_eq!(range.fits_signed(bits), signed_fits, "{range:?} in i{bits}");
939            }
940        }
941    }
942
943    #[test]
944    fn a_type_that_is_not_a_scalar_integer_gets_a_range_that_says_nothing() {
945        assert!(Range::of(Type::PTR).is_full());
946        assert!(Range::of(Type::int(32)).is_full());
947        assert_eq!(Range::of(Type::int(32)).width(), 32);
948        assert_eq!(Range::of(Type::PTR).width(), MAX_BITS);
949    }
950
951    #[test]
952    fn a_width_wider_than_this_reasons_about_is_clamped_rather_than_wrong() {
953        let wide = Range::full(256);
954        assert_eq!(wide.width(), MAX_BITS);
955        assert!(wide.is_full());
956    }
957
958    #[test]
959    fn bits_that_contradict_each_other_have_no_meet() {
960        let zero = Bits::exactly(0, 8);
961        let one = Bits::exactly(1, 8);
962        assert_eq!(zero.meet(one), None);
963        assert_eq!(zero.meet(Bits::unknown(8)), Some(zero));
964        // And a join keeps only what they agree on, which for these is the seven high bits.
965        assert_eq!(zero.join(one), Bits { value: 0, unknown: 1 });
966    }
967}