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}