Skip to main content

rucc_opt/
scev.rs

1//! Scalar evolution: how a value changes across the iterations of a loop, and how many
2//! iterations there are.
3//!
4//! Design: `spec/optimizer/07-loops-and-scev.md` sections 7.4 through 7.7. This is the second
5//! half of document 07 and it answers the last two of the four questions section 7.6 says loop
6//! analysis exists for. The first two are in [`crate::loops`].
7//!
8//! # Chains of recurrences, and how much of one
9//!
10//! GCC writes how a value changes as a chain of recurrences, `{base, +, step}`, meaning a value
11//! that is `base` on the first iteration and `step` more on each one after. The representation is
12//! good because it is closed under the operations anyone wants: adding two chrecs of the same
13//! loop adds componentwise, multiplying by something invariant scales both parts, and evaluating
14//! one at a given iteration is arithmetic rather than a special case. That closure is why
15//! `j = 2 * i + 3` is as easy as `i = i + 1`, and pattern matching the second would run out of
16//! road on the first.
17//!
18//! Section 7.4 says what rucc builds and it is a subset: affine chrecs only. A value is
19//! invariant, or `{base, +, step}` with both parts invariant, or unknown. Addition, subtraction,
20//! multiplication by an invariant, shifting by a constant, and extension where the extension
21//! provably does not wrap. Nothing polynomial and nothing mutually recursive. That covers every
22//! induction variable a C programmer writes and every array subscript document 31 could use, and
23//! what it leaves out of GCC's four thousand lines is the part serving Fortran and the polyhedral
24//! framework.
25//!
26//! The one extension past affine is pointer chrecs, because C loops walk pointers and `p = p + 1`
27//! is `i = i + 1` with a scale. A `ptr_add` is addition with the byte offset as the step, which
28//! is the difference between analysing half of real C loops and analysing nearly all of them.
29//!
30//! # Trip counts, and the part that is uncomfortable
31//!
32//! Given an exit that compares an affine chrec against something invariant, solving for the
33//! iteration at which the comparison first fails is arithmetic. What makes it hard is that the
34//! answer is almost always conditional: on the loop being entered at all, and on the induction
35//! variable not wrapping before it gets there. Section 7.5 says a trip count returned without its
36//! assumptions is a miscompilation generator, and that the temptation to return one is strong
37//! because the assumptions are usually true.
38//!
39//! So [`Bound`] carries them and there is no way to read the count without seeing them.
40//! [`Bound::parts`] hands back both, and [`Bound::proven`] hands back the count only when there
41//! is nothing left to prove. A caller that means to emit a runtime check reads the assumptions
42//! and emits it, and a caller that forgets cannot get at the number.
43//!
44//! [`Bound`] and [`Estimate`] are different types on purpose. A bound is used for correctness, an
45//! estimate is used to decide whether a transformation is worth doing, and section 7.5 calls
46//! conflating them a category error that costs correctness. GCC keeps them apart as
47//! `max_loop_iterations` and `estimate_numbers_of_iterations` and the names do not stop anyone.
48//! Different structs do.
49
50use rucc_base::Symbol;
51use rucc_base::hash::Map;
52use rucc_ir::{Block, Def, Extra, Flags, Func, Imm, Inst, IntPred, Opcode, Type, Value};
53
54use crate::cfg::Cfg;
55use crate::loops::{LoopId, Loops};
56
57/// How deep the search for a step walks back through arithmetic.
58///
59/// The chain from a header parameter to the value fed back to it is two or three instructions in
60/// anything a person writes, and the walk terminates on its own because SSA has no cycles except
61/// through block parameters. The limit is here so a generated function with a thousand additions
62/// in the increment costs a bounded amount rather than a stack.
63const STEP_LIMIT: u32 = 16;
64
65/// How many blocks that do nothing but pass a value on the walk reads through.
66///
67/// One is what a canonicalized loop has. The limit is here for the same reason the one above is,
68/// which is that a generated function can have a chain of them and the cost of following it should
69/// not depend on how long somebody made it.
70const FORWARD_LIMIT: u32 = 8;
71
72/// How many times a loop is assumed to run when nothing better is known.
73///
74/// GCC's `--param avg-loop-niter`, whose default is the same number. It is a guess, so nothing may
75/// rest on it. It reaches [`Estimate`], which is only ever used to decide whether something is
76/// worth doing, and [`crate::split`], which spends it on how far to ask the runtime to look and is
77/// answered with a true count of bytes whatever it asked for.
78pub(crate) const ASSUMED_ITERATIONS: u64 = 10;
79
80/// A value that does not change inside the loop, read as `on + scale * value + offset`.
81///
82/// The `value` is a value defined outside the loop, or `None` when the linear part is a plain
83/// number. Keeping the shape rather than a bare [`Value`] is what lets `j = 2 * i + 3` come out
84/// as `{3, +, 2}` instead of unknown: the base and the step of that chrec are expressions nothing
85/// in the function computes, so a representation that could only name existing values would have
86/// to give up.
87///
88/// The `on` is a second symbol, and it is there for one shape: a pointer plus an index the loop
89/// did not start at zero. `a[i]` with `i` starting at a parameter has a first address of
90/// `a + start * 4`, which is two symbols, and a representation with room for one has to answer
91/// unknown to it. Nothing scales `on` and nothing negates it, because the thing it was added for
92/// is a pointer and a pointer is not something a loop multiplies. It is an [`Anchor`] rather than
93/// a value so that the address of a global can be one of them.
94///
95/// The `read` is the other half of the same shape, since in C that index is an `int` and what
96/// reaches the address is `sext(start)`. It is described rather than named, for the reason on
97/// [`Widening`]. The two together are what let `a[start + i]` be followed, and on the SQLite
98/// amalgamation they take 158 checks and 12 sites off the largest row of loop splitting's census.
99/// See tamnd/rucc#810.
100///
101/// Arithmetic on two of these is refused once the sum would need a third symbol, because
102/// `x + y + z` is not of this shape. That is the boundary of the subset and it is where the answer
103/// becomes unknown rather than wrong.
104///
105/// The fields are private on purpose. Every reader has to go through [`Invariant::plain`], which
106/// hands back the one symbol reading and refuses when there is a pointer in it, or through
107/// [`Invariant::on`], which hands back both halves. A reader that helped itself to `value` and
108/// `scale` would quietly drop the `on` and build an address off the wrong object.
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub struct Invariant {
111    /// A second symbol the whole expression is measured from, or `None`. Always one of it.
112    on: Option<Anchor>,
113    /// What the linear part is built on, or `None` for a plain number.
114    value: Option<Value>,
115    /// How that value is read, when it is read at a width that is not its own.
116    read: Option<Widening>,
117    /// How many of it.
118    scale: i128,
119    /// What is added.
120    offset: i128,
121}
122
123/// What an expression is measured from.
124///
125/// Usually a value the function computed somewhere outside the loop, which whoever reads the
126/// invariant can name. Sometimes the address of a global, which nothing has to compute because it
127/// is settled at link time and is the same number everywhere in the program.
128///
129/// The second one is here because of where a `global_addr` sits. [`crate::licm`] gives it a cost of
130/// zero and so never moves it out of a loop, which is the right call: working the address out again
131/// is one instruction and holding it in a register across a loop is a register. But that leaves the
132/// instruction inside the loop, and [`Loops::is_invariant`] answers by where a value is defined, so
133/// `a[i]` on a file scope `a` came out unknown. Describing the address rather than naming a value
134/// is the same move [`Widening`] makes, and it means a reader that wants the address in front of
135/// the loop writes another `global_addr` there for the one instruction it costs. On the SQLite
136/// amalgamation that is 178 checks at 47 sites of loop splitting's largest census row.
137/// See tamnd/rucc#810.
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
139pub enum Anchor {
140    /// A value, which is defined outside the loop and so can be named where it is wanted.
141    Value(Value),
142    /// The address of a global, which is written again wherever it is wanted.
143    Address(Symbol),
144}
145
146impl Anchor {
147    /// The value, when it is one. `None` for an address, which no value names.
148    #[must_use]
149    pub fn value(self) -> Option<Value> {
150        match self {
151            Self::Value(value) => Some(value),
152            Self::Address(_) => None,
153        }
154    }
155}
156
157/// A value read at a type wider than its own.
158///
159/// Widening `{start, +, 1}` in `int` gives `{sext(start), +, 1}` in `long`, and `sext(start)` is an
160/// expression nothing in the function computes. A representation that could only name values had
161/// to refuse the whole widening on that account, which is what shut the door on a walk from an
162/// index the caller handed in, because in C that index is an `int`. So the extension is described
163/// rather than named and whoever builds code from the invariant emits it.
164///
165/// The value stays the narrow one. Reading it at a third width later is an extension of an
166/// extension, and the two collapse into one wherever they mean the same thing, which is everywhere
167/// except a zero extension read as signed afterwards.
168#[derive(Clone, Copy, Debug, PartialEq, Eq)]
169pub struct Widening {
170    /// Sign extended or zero extended.
171    pub reading: Reading,
172    /// The type it is read at, which is wider than the value's own.
173    pub to: Type,
174}
175
176/// An invariant with no second symbol in it, read as `scale * value + offset`.
177///
178/// What every reader but [`crate::split`] wants, and what every reader wanted before there was an
179/// `on` at all. [`Invariant::plain`] is the only way to one, so a reader that does not know about
180/// the second symbol cannot get an expression that has one.
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
182pub struct Plain {
183    /// What it is built on, or `None` for a plain number.
184    pub value: Option<Value>,
185    /// How that value is read, when it is read at a width that is not its own.
186    pub read: Option<Widening>,
187    /// How many of it.
188    pub scale: i128,
189    /// What is added to it.
190    pub offset: i128,
191}
192
193impl Invariant {
194    /// A plain number.
195    #[must_use]
196    pub fn number(offset: i128) -> Self {
197        Self { on: None, value: None, read: None, scale: 0, offset }
198    }
199
200    /// One of a value.
201    #[must_use]
202    pub fn of(value: Value) -> Self {
203        Self { on: None, value: Some(value), read: None, scale: 1, offset: 0 }
204    }
205
206    /// So many of a value, plus a number.
207    #[must_use]
208    pub fn scaled(value: Value, scale: i128, offset: i128) -> Self {
209        Self { on: None, value: Some(value), read: None, scale, offset }
210    }
211
212    /// The address of a global.
213    ///
214    /// It goes straight into the `on` slot rather than into `value`, because that slot is the one
215    /// for the thing an address is measured from and an address is the only thing this ever is.
216    /// Nothing scales it and nothing negates it, which the rest of the arithmetic here already
217    /// refuses for whatever is in that slot.
218    #[must_use]
219    pub fn address(symbol: Symbol) -> Self {
220        Self { on: Some(Anchor::Address(symbol)), value: None, read: None, scale: 0, offset: 0 }
221    }
222
223    /// The one symbol reading, and `None` when there is a second symbol in it.
224    #[must_use]
225    pub fn plain(self) -> Option<Plain> {
226        self.on.is_none().then_some(Plain {
227            value: self.value,
228            read: self.read,
229            scale: self.scale,
230            offset: self.offset,
231        })
232    }
233
234    /// What it is measured from and how far past that, when there is a second symbol in it.
235    ///
236    /// Exactly one of this and [`Invariant::plain`] answers, so a reader that handles both has
237    /// handled every invariant there is.
238    #[must_use]
239    pub fn on(self) -> Option<(Anchor, Plain)> {
240        let on = self.on?;
241        Some((
242            on,
243            Plain { value: self.value, read: self.read, scale: self.scale, offset: self.offset },
244        ))
245    }
246
247    /// What it is measured from, when anything, and the rest of it with that taken off.
248    ///
249    /// For a reader that has to cancel the thing two expressions are measured from before it can
250    /// do arithmetic on what is left, which [`Invariant::minus`] will not do on its own because
251    /// it has no way to know the two are the same object.
252    #[must_use]
253    pub fn loose(self) -> (Option<Anchor>, Self) {
254        (self.on, Self { on: None, ..self })
255    }
256
257    /// Whether the two are the same expression apart from the number added to them.
258    #[must_use]
259    pub fn alike(self, other: Self) -> bool {
260        self.on == other.on
261            && self.value == other.value
262            && self.read == other.read
263            && self.scale == other.scale
264    }
265
266    /// The number added to it, whatever else it has in it.
267    #[must_use]
268    pub fn offset(self) -> i128 {
269        self.offset
270    }
271
272    /// The number this is, when it is one.
273    #[must_use]
274    pub fn as_number(self) -> Option<i128> {
275        (self.on.is_none() && self.symbol().is_none()).then_some(self.offset)
276    }
277
278    /// Whether this is the number zero.
279    #[must_use]
280    pub fn is_zero(self) -> bool {
281        self.as_number() == Some(0)
282    }
283
284    /// The value the linear part is built on, when the linear part has one.
285    fn symbol(self) -> Option<Value> {
286        if self.scale == 0 { None } else { self.value }
287    }
288
289    /// This as something to measure from, when it is one of a value and a number.
290    ///
291    /// Never a widened one. What an expression is measured from is a pointer, and a pointer is not
292    /// something anything here extends.
293    fn measure(self) -> Option<Anchor> {
294        (self.on.is_none() && self.read.is_none() && self.scale == 1)
295            .then_some(self.value)
296            .flatten()
297            .map(Anchor::Value)
298    }
299
300    /// The symbol both linear parts are built on and how it is read, when they agree on one or one
301    /// of them has none.
302    ///
303    /// The same value read two ways is two different numbers, so agreeing on the value is not
304    /// enough. `sext(x)` and `zext(x)` are the same bits and not the same quantity.
305    fn shared(self, other: Self) -> Option<(Option<Value>, Option<Widening>)> {
306        match (self.symbol(), other.symbol()) {
307            (None, _) => Some((other.value, other.read)),
308            (_, None) => Some((self.value, self.read)),
309            (left, right) => {
310                (left == right && self.read == other.read).then_some((left, self.read))
311            }
312        }
313    }
314
315    /// This same value read at a wider type, when the widening has a form here.
316    ///
317    /// A number means the same thing at both widths under a sign extension, and under a zero
318    /// extension once it is not negative. One of a value becomes that value read through the
319    /// extension. Anything else is refused, because the narrow arithmetic may already have wrapped
320    /// and `sext(2 * x + 3)` is not `2 * sext(x) + 3`.
321    fn widened(self, reading: Reading, to: Type) -> Option<Self> {
322        if let Some(number) = self.as_number() {
323            return (reading == Reading::Signed || number >= 0).then_some(Self::number(number));
324        }
325        if self.on.is_some() || self.scale != 1 || self.offset != 0 {
326            return None;
327        }
328        let value = self.value?;
329        // An extension of an extension. A zero extension is never negative, so reading its result
330        // as signed afterwards is the same numbers and the pair collapses into the zero extension
331        // at the outer width. The other way round it does not: a sign extension of a negative
332        // number read as unsigned afterwards is a different number entirely.
333        let reading = match (self.read.map(|read| read.reading), reading) {
334            (None, outer) => outer,
335            (Some(Reading::Unsigned), _) => Reading::Unsigned,
336            (Some(Reading::Signed), Reading::Signed) => Reading::Signed,
337            (Some(Reading::Signed), Reading::Unsigned) => return None,
338        };
339        Some(Self {
340            on: None,
341            value: Some(value),
342            read: Some(Widening { reading, to }),
343            scale: 1,
344            offset: 0,
345        })
346    }
347
348    /// The two added, when the sum is of this shape.
349    #[must_use]
350    pub fn plus(self, other: Self) -> Option<Self> {
351        let offset = self.offset.checked_add(other.offset)?;
352        // At most one of the two brought something to measure from, since a sum measured from two
353        // pointers is not an address.
354        let on = match (self.on, other.on) {
355            (None, on) | (on, None) => on,
356            (Some(_), Some(_)) => return None,
357        };
358        // The linear parts are about the same symbol, or one of them is a number, so they add.
359        if let Some((value, read)) = self.shared(other) {
360            let scale = self.scale.checked_add(other.scale)?;
361            return Some(Self { on, value, read, scale, offset });
362        }
363        // Two different symbols, which is what a pointer plus an index the loop did not start at
364        // zero is. Nothing may already be measured from anything, and one of the two has to be one
365        // of a value and a number, and that one becomes what the sum is measured from.
366        if on.is_some() {
367            return None;
368        }
369        let (on, rest) = match (self.measure(), other.measure()) {
370            (Some(on), _) => (on, other),
371            (_, Some(on)) => (on, self),
372            _ => return None,
373        };
374        Some(Self { on: Some(on), value: rest.value, read: rest.read, scale: rest.scale, offset })
375    }
376
377    /// The second subtracted from the first, when the difference is of this shape.
378    #[must_use]
379    pub fn minus(self, other: Self) -> Option<Self> {
380        self.plus(other.negated()?)
381    }
382
383    /// This with its sign flipped, which needs nothing to measure from.
384    ///
385    /// A pointer is not a thing to negate, and the second symbol is only ever there because a
386    /// pointer put it there.
387    #[must_use]
388    pub fn negated(self) -> Option<Self> {
389        if self.on.is_some() {
390            return None;
391        }
392        Some(Self {
393            on: None,
394            value: self.value,
395            read: self.read,
396            scale: self.scale.checked_neg()?,
397            offset: self.offset.checked_neg()?,
398        })
399    }
400
401    /// The two multiplied, which needs one of them to be a plain number and neither to be measured
402    /// from anything.
403    #[must_use]
404    pub fn times(self, other: Self) -> Option<Self> {
405        if self.on.is_some() || other.on.is_some() {
406            return None;
407        }
408        let (symbol, by) = match (self.as_number(), other.as_number()) {
409            (Some(by), _) => (other, by),
410            (_, Some(by)) => (self, by),
411            _ => return None,
412        };
413        Some(Self {
414            on: None,
415            value: symbol.value,
416            read: symbol.read,
417            scale: symbol.scale.checked_mul(by)?,
418            offset: symbol.offset.checked_mul(by)?,
419        })
420    }
421}
422
423/// How a value changes from one iteration of a loop to the next.
424#[derive(Clone, Copy, Debug, PartialEq, Eq)]
425pub enum Evolution {
426    /// The same on every iteration.
427    Invariant(Invariant),
428    /// `{base, +, step}`: `base` the first time round and `step` more each time after.
429    Affine(Chrec),
430    /// Not something this analysis describes. Never a claim that the value does not evolve.
431    Unknown,
432}
433
434impl Evolution {
435    /// The chrec, when this is one.
436    #[must_use]
437    pub fn chrec(self) -> Option<Chrec> {
438        match self {
439            Self::Affine(chrec) => Some(chrec),
440            _ => None,
441        }
442    }
443
444    /// The invariant expression, when this is one.
445    #[must_use]
446    pub fn invariant(self) -> Option<Invariant> {
447        match self {
448            Self::Invariant(inv) => Some(inv),
449            _ => None,
450        }
451    }
452}
453
454/// An affine chain of recurrences, `{base, +, step}`, evolving in a named type.
455///
456/// The type is not decoration. `{0, +, 1}` in `unsigned char` is not the sequence `0, 1, 2, ...`,
457/// it is that sequence modulo two hundred and fifty six, and section 7.7 says this is where a
458/// naive implementation is wrong constantly and in ways that pass every test written by someone
459/// thinking in `int`. Every operation here checks the type and every one that cannot stay right
460/// in it answers unknown.
461#[derive(Clone, Copy, Debug, PartialEq, Eq)]
462pub struct Chrec {
463    /// What the value is on the first iteration.
464    pub base: Invariant,
465    /// What is added each time round.
466    pub step: Invariant,
467    /// The type it evolves in, which is what says when it wraps.
468    pub ty: Type,
469    /// What the instruction that increments it promised. `nsw` means the sequence does not wrap
470    /// when read as signed and `nuw` means it does not when read as unsigned, and both come from
471    /// the increment rather than from anything this analysis proved.
472    pub flags: Flags,
473}
474
475impl Chrec {
476    /// Whether the sequence is known not to wrap under the reading this predicate takes.
477    #[must_use]
478    pub fn does_not_wrap(self, signed: bool) -> bool {
479        self.flags.contains(if signed { Flags::NSW } else { Flags::NUW })
480    }
481}
482
483/// Something that has to be true for a trip count to be the right answer.
484///
485/// Section 7.5 asks for exactly this: not a trip count but a trip count plus a predicate under
486/// which it holds, so the consumer either proves the predicate, emits a runtime check for it, or
487/// gives up. These are the predicates.
488#[derive(Clone, Copy, Debug, PartialEq, Eq)]
489pub enum Assumption {
490    /// The loop is entered at all, so the distance from the counter to its limit is a number that
491    /// is not negative.
492    ///
493    /// `for (i = 0; i < n; i++)` with `n` of zero runs no times and the distance is zero, but `n`
494    /// of minus one also runs no times and the distance is minus one, so a count taken from the
495    /// distance has to be told which case it is in.
496    ///
497    /// What it does not say anything about is whether the loop comes back. A counter stepping
498    /// toward a limit under an ordering test either reaches it or is already past it, and either
499    /// way that is a finite number of steps, so a caller whose question is whether the loop ends
500    /// may have this one for nothing. [`crate::hoist`] discharges it by clamping the count at zero
501    /// and [`crate::loop_delete`] by never reading the count. That is the whole of why this is a
502    /// separate assumption from [`Assumption::Approaching`] rather than the same one worded to
503    /// cover both.
504    ///
505    /// Only ever present on a symbolic count. When the distance is a number the sign of it is
506    /// there to be read, so this is settled rather than assumed.
507    Entered,
508    /// The limit is somewhere the counter is heading, which for a loop ending on `!=` is what
509    /// makes it end at all.
510    ///
511    /// A counter stepping away from its limit never arrives, and one stepping past it keeps going
512    /// until it wraps, so what is unproven here is termination rather than which number the count
513    /// is. Nothing discharges it by clamping, because there is no number to clamp when the loop
514    /// does not come back. Document 17.2 says rucc does not take out a loop that might not end,
515    /// so a pass that deletes loops refuses this one outright.
516    ///
517    /// Only ever present on a symbolic count, for the same reason [`Assumption::Entered`] is.
518    Approaching,
519    /// The induction variable does not wrap in its own type before the exit is taken.
520    ///
521    /// Present whenever the increment did not carry the matching `nsw` or `nuw` flag. With the
522    /// flag there is nothing to assume, because the flag is the promise.
523    NoWrap(Chrec),
524    /// Signed overflow is undefined here, which is what makes `for (int i = 0; i <= n; i++)`
525    /// finite.
526    ///
527    /// GCC infers loop bounds from this in `infer_loop_bounds_from_signedness`, and it is the
528    /// single most common source of a report that the compiler broke a working program. It is
529    /// recorded rather than assumed silently so that `-fwrapv` can withdraw the count and so that
530    /// a dump can name it.
531    StrictOverflow,
532}
533
534impl Assumption {
535    /// What it says, in a line, for a dump to print.
536    ///
537    /// Section 7.5 asks that every inference of this kind be dumpable and say what it rests on,
538    /// because a user who has been bitten by one deserves a command that tells them which line
539    /// the compiler used against them. This is the sentence that command prints.
540    #[must_use]
541    pub fn describe(&self) -> String {
542        match self {
543            Self::Entered => "the loop is entered at all".to_string(),
544            Self::Approaching => "the counter is heading towards its limit".to_string(),
545            Self::NoWrap(chrec) => {
546                format!("the induction variable does not wrap in i{}", chrec.ty.bits())
547            }
548            Self::StrictOverflow => {
549                "signed overflow is undefined, so -fwrapv withdraws this count".to_string()
550            }
551        }
552    }
553}
554
555/// How many iterations, as a number or as an expression.
556#[derive(Clone, Copy, Debug, PartialEq, Eq)]
557pub enum Count {
558    /// Exactly this many.
559    Exact(u128),
560    /// This many, worked out from something the loop does not change.
561    Symbolic(Invariant),
562}
563
564/// Which reading of its operands the test the count came from took.
565///
566/// It matters to anybody widening the value a symbolic count is built out of. The count is the
567/// distance to the limit of the exit test, the limit is a value of the counter's own type, and
568/// what that value means is the reading its test took. A limit past the middle of a thirty two bit
569/// type is a large number to an unsigned test and a negative one to a signed test, and a consumer
570/// that sign extends what an unsigned test compared has turned a loop over three billion elements
571/// into a loop that runs no times.
572#[derive(Clone, Copy, Debug, PartialEq, Eq)]
573pub enum Reading {
574    /// The test read its operands as signed, so widening the count means sign extending it.
575    Signed,
576    /// The test read them as unsigned, so widening the count means zero extending it.
577    Unsigned,
578}
579
580/// How many times a loop runs at most, and what that rests on.
581///
582/// For correctness. A pass that deletes an iteration, peels one off, or decides a memory access
583/// is in bounds needs one of these. The count cannot be read without the assumptions, which is
584/// section 7.7's defence against a caller proving two of three and forgetting the third.
585#[derive(Clone, Debug, PartialEq, Eq)]
586pub struct Bound {
587    count: Count,
588    assumptions: Vec<Assumption>,
589    reading: Reading,
590}
591
592impl Bound {
593    /// The count and everything it rests on, together, because they cannot be asked for apart.
594    #[must_use]
595    pub fn parts(&self) -> (Count, &[Assumption]) {
596        (self.count, &self.assumptions)
597    }
598
599    /// How the value a symbolic count is built out of has to be read.
600    ///
601    /// Meaningless on a count that is a number, since a number has already been read.
602    #[must_use]
603    pub fn reading(&self) -> Reading {
604        self.reading
605    }
606
607    /// What has to be proved before the count means anything.
608    #[must_use]
609    pub fn assumptions(&self) -> &[Assumption] {
610        &self.assumptions
611    }
612
613    /// The count, for a caller with nothing left to prove.
614    ///
615    /// `None` does not mean the count is unknown. It means there are assumptions and this is not
616    /// the accessor for reading a count that has them.
617    #[must_use]
618    pub fn proven(&self) -> Option<Count> {
619        self.assumptions.is_empty().then_some(self.count)
620    }
621
622    /// The count, for a caller compiling a language where signed overflow is undefined.
623    ///
624    /// [`Bound::proven`] answers nothing for any `for (int i = 0; i < n; i++)` in any C program,
625    /// because `solve` puts [`Assumption::StrictOverflow`] on every count taken from a signed
626    /// test, and a pass built on `proven` alone is a pass that never fires. What that assumption
627    /// says is that the count rests on signed overflow being undefined, and `-fwrapv` is
628    /// implemented in `rucc-lower` by not setting `nsw` rather than by a flag anything down here
629    /// reads. So an increment that still carries `nsw` under `-fwrapv` does not exist, and a bound
630    /// with `StrictOverflow` and nothing else on it is a bound whose counter the front end
631    /// promised does not wrap. That promise is exactly what the assumption wanted.
632    ///
633    /// [`Assumption::NoWrap`] is the case where there is no such promise, and it is refused here.
634    /// So are [`Assumption::Entered`] and [`Assumption::Approaching`], though only in passing,
635    /// because neither ever appears on a count that is a number.
636    #[must_use]
637    pub fn under_undefined_overflow(&self) -> Option<Count> {
638        self.assumptions
639            .iter()
640            .all(|rests_on| matches!(rests_on, Assumption::StrictOverflow))
641            .then_some(self.count)
642    }
643
644    /// The count, for a caller that needs the loop to come back and not how many times.
645    ///
646    /// One assumption wider than [`Bound::under_undefined_overflow`], and the one it adds is
647    /// [`Assumption::Entered`]. What that says is whether the count is the distance to the limit
648    /// or zero, and both of those are numbers of iterations the loop has, so a pass asking whether
649    /// the loop ends has already been answered whichever way it goes. A pass multiplying by the
650    /// count has not, which is why this is a second accessor and not a loosening of the first.
651    ///
652    /// [`Assumption::Approaching`] is refused, and telling those two apart is the reason they are
653    /// two assumptions. A loop ending on `!=` whose counter steps past its limit runs until it
654    /// wraps, document 17.2 is explicit that rucc does not take out a loop that might not end, and
655    /// a count that comes back from here is one no caller has to check that against.
656    #[must_use]
657    pub fn comes_back(&self) -> Option<Count> {
658        self.assumptions
659            .iter()
660            .all(|rests_on| matches!(rests_on, Assumption::StrictOverflow | Assumption::Entered))
661            .then_some(self.count)
662    }
663}
664
665/// How many times a loop probably runs.
666///
667/// For cost decisions and never for correctness. A pass asking whether unrolling pays for itself
668/// wants one of these, and it is fine for the answer to be a guess, because being wrong makes the
669/// code slower rather than wrong. Nothing here can be turned into a [`Bound`].
670#[derive(Clone, Copy, Debug, PartialEq, Eq)]
671pub struct Estimate {
672    iterations: u64,
673    guessed: bool,
674}
675
676impl Estimate {
677    /// The number to do arithmetic with.
678    #[must_use]
679    pub fn iterations(self) -> u64 {
680        self.iterations
681    }
682
683    /// Whether nothing was known and this is the default.
684    #[must_use]
685    pub fn is_guess(self) -> bool {
686        self.guessed
687    }
688}
689
690/// An exit test, read so that the loop keeps going while it holds.
691///
692/// Not public. It is the shape [`Scev::bound_at`] and [`Scev::holds`] both want out of the same
693/// branch, and what either of them says about it is what the outside sees.
694#[derive(Clone, Copy, Debug)]
695struct Test {
696    /// The side that moves, with the predicate already turned round to put it on the left.
697    chrec: Chrec,
698    /// The side that does not.
699    limit: Invariant,
700    /// The comparison that has to hold for the loop to go round again.
701    pred: IntPred,
702    /// Whether every iteration that goes round asks it.
703    each: bool,
704}
705
706/// The analysis, which works out an answer when asked and remembers it.
707///
708/// Demand driven and memoized, per section 7.8, because the cost of scalar evolution is a
709/// function of how many distinct values get asked about rather than of the size of the function.
710/// The cache holds one loop's worth of answers per loop and the whole thing is thrown away when
711/// anything about the loops changes, which per document 04.4 is any pass that touches one. It is
712/// kept as one table per loop rather than one table keyed by both, because `Scev::holds` empties a
713/// loop's answers once for every loop, and picking them out of a single table was a walk over the
714/// answers for every loop each time. In a function of two thousand loops that walk was most of
715/// what the analysis cost.
716#[derive(Debug)]
717pub struct Scev<'a> {
718    func: &'a Func,
719    cfg: &'a Cfg,
720    loops: &'a Loops,
721    known: Map<LoopId, Map<Value, Evolution>>,
722    held: Map<LoopId, Option<Chrec>>,
723}
724
725impl<'a> Scev<'a> {
726    /// A fresh analysis over these loops, knowing nothing yet.
727    #[must_use]
728    pub fn new(func: &'a Func, cfg: &'a Cfg, loops: &'a Loops) -> Self {
729        Self { func, cfg, loops, known: Map::default(), held: Map::default() }
730    }
731
732    /// How this value changes across the iterations of this loop.
733    ///
734    /// The way in, and what it does before answering is settle `Scev::holds` for the loop. That has
735    /// to happen out here rather than at the point `Scev::extend` wants it, because settling it
736    /// means asking about other values and `Scev::at` parks a marker on the value it is working on.
737    /// Asked from in there, the answer would depend on what was already in flight.
738    pub fn evolution(&mut self, id: LoopId, value: Value) -> Evolution {
739        self.holds(id);
740        self.at(id, value)
741    }
742
743    /// How this value changes, with the loop's own facts already settled.
744    fn at(&mut self, id: LoopId, value: Value) -> Evolution {
745        if let Some(&known) = self.known.get(&id).and_then(|answers| answers.get(&value)) {
746            return known;
747        }
748        // Unknown while the answer is being worked out, so the cycle from a header parameter back
749        // to itself terminates instead of asking the same question forever. Anything that reaches
750        // the parameter again gets unknown and the shape it was matching fails, which is the
751        // right answer for a value defined in terms of itself through arithmetic this does not
752        // describe.
753        self.known.entry(id).or_default().insert(value, Evolution::Unknown);
754        let found = self.compute(id, value);
755        self.known.entry(id).or_default().insert(value, found);
756        found
757    }
758
759    /// How many times this loop runs at most, and what that rests on.
760    ///
761    /// Any one exit gives a valid upper bound, because a loop cannot run more times than the
762    /// first exit that fires, so this takes the first exit it can solve rather than the smallest.
763    /// That is `max_loop_iterations` and not `estimate_numbers_of_iterations`, which is why the
764    /// answer is a [`Bound`].
765    pub fn bound(&mut self, id: LoopId) -> Option<Bound> {
766        self.holds(id);
767        let exits: Vec<Block> = self.loops.exits(id).iter().map(|exit| exit.from).collect();
768        exits.into_iter().find_map(|from| self.bound_at(id, from))
769    }
770
771    /// The counter an exit test of this loop keeps inside its own type, when there is one.
772    ///
773    /// [`bounded_by_its_test`] is the argument and this is where its answer is written down as a
774    /// fact about the loop rather than spent on one trip count. What it buys is [`Scev::extend`]:
775    /// an unsigned counter carries no `nuw`, so widening anything built out of one used to be
776    /// refused, and the test that holds the counter holds everything walking beside it.
777    ///
778    /// Settled once per loop and then read. It is settled from [`Scev::evolution`] and
779    /// [`Scev::bound`], which are the two ways in, so that it is worked out with nothing in flight.
780    /// The cache for the loop is emptied afterwards, because the answers already in it were worked
781    /// out while this was still unknown and a conservative answer that stayed would make what the
782    /// analysis says depend on which question was asked first.
783    fn holds(&mut self, id: LoopId) -> Option<Chrec> {
784        if let Some(&known) = self.held.get(&id) {
785            return known;
786        }
787        // Unknown while it is being worked out, which is what stops the recursion below from
788        // asking the same question forever, and which is why the cache is emptied after.
789        self.held.insert(id, None);
790        let exits: Vec<Block> = self.loops.exits(id).iter().map(|exit| exit.from).collect();
791        let found = exits.into_iter().find_map(|from| {
792            let test = self.test_at(id, from)?;
793            let step = test.chrec.step.as_number()?;
794            (test.each && bounded_by_its_test(test.pred, step)).then_some(test.chrec)
795        });
796        self.held.insert(id, found);
797        self.known.remove(&id);
798        found
799    }
800
801    /// How many times this loop probably runs.
802    pub fn estimate(&mut self, id: LoopId) -> Estimate {
803        match self.bound(id).map(|bound| bound.count) {
804            Some(Count::Exact(exact)) => {
805                Estimate { iterations: u64::try_from(exact).unwrap_or(u64::MAX), guessed: false }
806            }
807            _ => Estimate { iterations: ASSUMED_ITERATIONS, guessed: true },
808        }
809    }
810
811    /// The evolution of a value nothing is known about yet.
812    fn compute(&mut self, id: LoopId, value: Value) -> Evolution {
813        if let Some(invariant) = self.invariant(id, value) {
814            return Evolution::Invariant(invariant);
815        }
816        match self.func[value].def {
817            Def::Param { block, index } if block == self.loops.header(id) => {
818                self.at_header(id, value, index as usize)
819            }
820            // A parameter of a block inside the loop that is not the header takes a different
821            // value depending on which way control came, and describing that is a job for the
822            // value range work of document 10 rather than for a chrec. Unless there is only one
823            // way in, in which case it does not.
824            Def::Param { .. } => match self.forwarded(value) {
825                same if same == value => Evolution::Unknown,
826                through => self.at(id, through),
827            },
828            Def::Result { inst, .. } => self.at_inst(id, inst, value),
829        }
830    }
831
832    /// The value as an expression that does not change inside the loop, if it is one.
833    fn invariant(&self, id: LoopId, value: Value) -> Option<Invariant> {
834        if let Some((imm, ty)) = constant(self.func, value) {
835            return Some(Invariant::number(imm.signed(ty)));
836        }
837        // A constant is invariant wherever it sits, which is why it is asked about first. Anything
838        // else has to be defined outside the loop.
839        if self.loops.is_invariant(self.func, id, value) {
840            return Some(Invariant::of(value));
841        }
842        // Except the address of a global, which is a link time constant and so does not change
843        // inside a loop wherever it is written. Asked after the question above and not instead of
844        // it, so that a `global_addr` already sitting outside the loop stays a value every reader
845        // can name, and this arm is only the case that used to come out unknown. See [`Anchor`].
846        symbol(self.func, value).map(Invariant::address)
847    }
848
849    /// The evolution of a parameter of the loop header, which is where an induction variable is.
850    ///
851    /// The parameter takes one value on the way in and another on the way round, which is what
852    /// other IRs spell as a phi node. If the way round is the parameter plus something invariant,
853    /// the parameter is an affine chrec and that something is its step.
854    fn at_header(&mut self, id: LoopId, value: Value, index: usize) -> Evolution {
855        let (func, cfg, loops) = (self.func, self.cfg, self.loops);
856        let header = loops.header(id);
857        // Section 7.3 wants exactly one latch and the canonicalizer makes one. Two of them means
858        // two ways round with two different increments, and picking one would be a guess.
859        let [latch] = loops.latches(id) else { return Evolution::Unknown };
860        let mut entering = None;
861        let mut around = None;
862        for &pred in cfg.predecessors(header) {
863            let Some(arg) = argument(func, pred, header, index) else { return Evolution::Unknown };
864            let arg = self.forwarded(arg);
865            let slot = if pred == *latch { &mut around } else { &mut entering };
866            if slot.replace(arg).is_some_and(|old| old != arg) {
867                return Evolution::Unknown;
868            }
869        }
870        let (Some(entering), Some(around)) = (entering, around) else { return Evolution::Unknown };
871        let Some(base) = self.invariant(id, entering) else { return Evolution::Unknown };
872        let Some((step, flags)) = self.step(id, around, value, 0) else {
873            return Evolution::Unknown;
874        };
875        affine(base, step, func[value].ty, flags)
876    }
877
878    /// The value a block parameter stands for, when there is only one way into its block.
879    ///
880    /// This is not an analysis, it is undoing a rename. A block with one predecessor has one value
881    /// for each of its parameters and it is the argument that predecessor passes, so reading
882    /// through it loses nothing and assumes nothing.
883    ///
884    /// It is here because of what canonicalization does. `crate::canon` splits the back edge of a
885    /// loop to give it a latch of its own, and after that the value going round the loop is not the
886    /// increment the loop computed, it is a parameter of a block that does nothing but pass the
887    /// increment on. Without this, every counted loop the pipeline actually produces looks like a
888    /// loop whose counter comes from somewhere unknown, and the trip count of a `for` loop in a
889    /// real function comes back as nothing.
890    fn forwarded(&self, value: Value) -> Value {
891        let mut value = value;
892        for _ in 0..FORWARD_LIMIT {
893            let Def::Param { block, index } = self.func[value].def else { return value };
894            let [pred] = self.cfg.predecessors(block) else { return value };
895            let Some(arg) = argument(self.func, *pred, block, index as usize) else { return value };
896            if arg == value {
897                return value;
898            }
899            value = arg;
900        }
901        value
902    }
903
904    /// What is added to `of` to get `value`, and what the additions promised.
905    ///
906    /// Written as its own walk rather than as the general combination below, because at the point
907    /// this runs the parameter's own evolution is not known yet and the general walk would ask
908    /// for it and get unknown.
909    fn step(&self, id: LoopId, value: Value, of: Value, depth: u32) -> Option<(Invariant, Flags)> {
910        let value = self.forwarded(value);
911        if value == of {
912            // Nothing added yet, and nothing has had a chance to overflow either.
913            return Some((Invariant::number(0), Flags::NSW.union(Flags::NUW)));
914        }
915        if depth >= STEP_LIMIT {
916            return None;
917        }
918        let Def::Result { inst, .. } = self.func[value].def else { return None };
919        let data = &self.func[inst];
920        let args = &self.func[data.args];
921        let (&lhs, &rhs) = (args.first()?, args.get(1)?);
922        let combine = |carried: (Invariant, Flags), other: Invariant, subtract: bool| {
923            let (delta, flags) = carried;
924            let moved = if subtract { delta.minus(other)? } else { delta.plus(other)? };
925            Some((moved, flags.intersection(data.flags)))
926        };
927        match data.opcode {
928            Opcode::Add => {
929                if let Some(carried) = self.step(id, lhs, of, depth + 1) {
930                    return combine(carried, self.invariant(id, rhs)?, false);
931                }
932                combine(self.step(id, rhs, of, depth + 1)?, self.invariant(id, lhs)?, false)
933            }
934            Opcode::Sub => {
935                combine(self.step(id, lhs, of, depth + 1)?, self.invariant(id, rhs)?, true)
936            }
937            // A pointer walks by bytes, and only the pointer side can be the one carrying the
938            // induction variable. The offset is the step, which is the element size the front end
939            // already multiplied in.
940            Opcode::PtrAdd => {
941                combine(self.step(id, lhs, of, depth + 1)?, self.invariant(id, rhs)?, false)
942            }
943            _ => None,
944        }
945    }
946
947    /// The evolution of an instruction's result, from the evolutions of its operands.
948    fn at_inst(&mut self, id: LoopId, inst: Inst, value: Value) -> Evolution {
949        let func = self.func;
950        let data = &func[inst];
951        let (opcode, flags) = (data.opcode, data.flags);
952        let args = &func[data.args];
953        let ty = func[value].ty;
954        let Some(&lhs) = args.first() else { return Evolution::Unknown };
955        match opcode {
956            Opcode::Add | Opcode::PtrAdd => {
957                let Some(&rhs) = args.get(1) else { return Evolution::Unknown };
958                let (left, right) = (self.at(id, lhs), self.at(id, rhs));
959                combine(left, right, ty, flags, false)
960            }
961            Opcode::Sub => {
962                let Some(&rhs) = args.get(1) else { return Evolution::Unknown };
963                let (left, right) = (self.at(id, lhs), self.at(id, rhs));
964                combine(left, right, ty, flags, true)
965            }
966            Opcode::Mul => {
967                let Some(&rhs) = args.get(1) else { return Evolution::Unknown };
968                let (left, right) = (self.at(id, lhs), self.at(id, rhs));
969                scale(left, right, ty, flags)
970            }
971            // A shift by a constant is a multiplication by a power of two, and only by a constant:
972            // a variable count is invariant in the loop and still not a number this can multiply
973            // by. A count at or above the width is poison rather than a shift to zero, so the
974            // range is checked here rather than assumed.
975            Opcode::Shl => {
976                let Some(&rhs) = args.get(1) else { return Evolution::Unknown };
977                let Some((count, count_ty)) = constant(func, rhs) else {
978                    return Evolution::Unknown;
979                };
980                let count = count.unsigned();
981                if count >= u128::from(ty.bits()) || !count_ty.is_int() {
982                    return Evolution::Unknown;
983                }
984                let by = Evolution::Invariant(Invariant::number(1i128 << count));
985                scale(self.at(id, lhs), by, ty, flags)
986            }
987            Opcode::SExt | Opcode::ZExt => self.extend(id, opcode, lhs, ty),
988            // A truncation is a wrap by construction, so a chrec through one describes a sequence
989            // that restarts, and this does not have a representation for that.
990            _ => Evolution::Unknown,
991        }
992    }
993
994    /// A chrec widened, which needs the sequence not to wrap at the narrow width.
995    ///
996    /// Section 7.4 allows extension only where the extension provably does not wrap, and the first
997    /// proof here is the flag the increment carries. `nsw` on the increment is the promise that the
998    /// signed sequence does not wrap, which is exactly what makes the wide sequence the same
999    /// numbers as the narrow one.
1000    ///
1001    /// The second proof is the loop's own exit test, through [`Scev::holds`] and [`trails`], and it
1002    /// is here because of what an unsigned counter looks like. `for (unsigned i = 0; i < n; i++)`
1003    /// carries no `nuw`, because C says unsigned arithmetic wraps, so `a[i]` on that counter used
1004    /// to come back unwidened and every bounds check in the loop stayed where it was. The test that
1005    /// keeps the counter inside its type keeps everything walking beside it inside too.
1006    ///
1007    /// Each part is either a plain number or one of a value, and nothing else. A number means the
1008    /// same thing at both widths, and one of a value becomes that value read through the extension,
1009    /// which is what [`Widening`] is for. Anything with arithmetic in it is refused, because the
1010    /// narrow arithmetic may already have wrapped and `sext(2 * x + 3)` is not `2 * sext(x) + 3`.
1011    /// What that leaves out is a base like `start + 1`, and what it lets in is `start`, which is
1012    /// the shape a walk from an index the caller handed in is in. See #810.
1013    ///
1014    /// A value the loop does not change is widened by the same rule. It used to be widened only
1015    /// when it was a number, and everything else came back unknown, which is a sequence that does
1016    /// not move being harder to widen than one that does. What it cost is the row of a two
1017    /// dimensional array: `a[row * N + k]` round `k` has `(long)row * N` in it, that is invariant
1018    /// and is not a number, so the address of the whole subscript came back unknown and every pass
1019    /// reading it had nothing to work with. There is no wrapping question to answer here, because
1020    /// there is no sequence and so nothing to wrap, and the shapes that get through are the same
1021    /// ones [`Invariant::widened`] lets through for a chrec's base.
1022    fn extend(&mut self, id: LoopId, opcode: Opcode, from: Value, to: Type) -> Evolution {
1023        let narrow = self.func[from].ty;
1024        let signed = opcode == Opcode::SExt;
1025        let held = self.held.get(&id).copied().flatten();
1026        let settled = |chrec: Chrec| {
1027            chrec.does_not_wrap(signed) || (!signed && held.is_some_and(|held| trails(chrec, held)))
1028        };
1029        let reading = if signed { Reading::Signed } else { Reading::Unsigned };
1030        match self.at(id, from) {
1031            Evolution::Invariant(inv) => match inv.as_number() {
1032                // A number read at the narrow width means the same thing at the wide one under
1033                // sign extension, and under zero extension once it is not negative.
1034                Some(number) if signed || number >= 0 => Evolution::Invariant(inv),
1035                Some(_) => Evolution::Unknown,
1036                // Not a number, and still the same value read wider. This is the widening a chrec
1037                // gets, asked about something that does not move: `(long)row * 64` inside a loop
1038                // over `k` is an expression the loop does not change, and it used to come back
1039                // unknown, which made the whole of `a[row * N + k]` unknown. [`Invariant::widened`]
1040                // is the one that decides, and it refuses anything with arithmetic in it for the
1041                // reason written on it, so what gets through is one of a value and nothing else.
1042                None => match inv.widened(reading, to) {
1043                    Some(wide) => Evolution::Invariant(wide),
1044                    None => Evolution::Unknown,
1045                },
1046            },
1047            Evolution::Affine(chrec) if chrec.ty == narrow && settled(chrec) => {
1048                let (Some(base), Some(step)) =
1049                    (chrec.base.widened(reading, to), chrec.step.widened(reading, to))
1050                else {
1051                    return Evolution::Unknown;
1052                };
1053                Evolution::Affine(Chrec { base, step, ty: to, flags: chrec.flags })
1054            }
1055            _ => Evolution::Unknown,
1056        }
1057    }
1058
1059    /// Whether every way round the loop goes through this block.
1060    ///
1061    /// Walks back from the one latch while each block has one predecessor. A block reached that way
1062    /// is one the latch cannot be got to without, and the walk stops at the first join, so it never
1063    /// goes round the loop, since the header is a join by having a way in and a way round.
1064    fn asked_each_time(&self, id: LoopId, from: Block) -> bool {
1065        let [latch] = self.loops.latches(id) else { return false };
1066        let mut at = *latch;
1067        for _ in 0..self.loops.blocks(id).len() {
1068            if at == from {
1069                return true;
1070            }
1071            let &[before] = self.cfg.predecessors(at) else { return false };
1072            at = before;
1073        }
1074        false
1075    }
1076
1077    /// The trip count from the exit leaving this block, if this exit can be solved.
1078    ///
1079    /// Only a test every iteration asks gives one. A test under a condition first fails at some
1080    /// iteration and the loop leaves at the first iteration after that on which the condition lets
1081    /// the test be asked, which may be much later or never. `while (i != 1024 || j <= 0)` asks
1082    /// `j <= 0` only once `i` is 1024, so the count its test gives is 1 and the loop runs ten times.
1083    /// Every caller multiplies by the count or takes it to mean the loop ends, and a count from such
1084    /// a test is right for neither.
1085    fn bound_at(&mut self, id: LoopId, from: Block) -> Option<Bound> {
1086        let test = self.test_at(id, from)?;
1087        if !test.each {
1088            return None;
1089        }
1090        solve(test.chrec, test.limit, test.pred)
1091    }
1092
1093    /// The exit test leaving this block, read into the pieces its two readers want.
1094    ///
1095    /// [`Scev::bound_at`] spends it on a trip count and [`Scev::holds`] spends it on whether the
1096    /// counter can wrap, and both want the same reading of the same branch, so the reading is
1097    /// written once.
1098    fn test_at(&mut self, id: LoopId, from: Block) -> Option<Test> {
1099        let func = self.func;
1100        let term = func.terminator(from)?;
1101        if func[term].opcode != Opcode::BrIf {
1102            return None;
1103        }
1104        let args = &func[func[term].args];
1105        let &cond = args.first()?;
1106        let calls = &func[func.target_list(term)];
1107        let (&taken, &not_taken) = (calls.first()?, calls.get(1)?);
1108        // Which arm keeps going. If both stay in or both leave, the branch is not the test that
1109        // ends the loop and there is nothing here to solve.
1110        let stays = match (
1111            self.loops.contains(id, taken.block),
1112            self.loops.contains(id, not_taken.block),
1113        ) {
1114            (true, false) => true,
1115            (false, true) => false,
1116            _ => return None,
1117        };
1118
1119        let Def::Result { inst, .. } = func[cond].def else { return None };
1120        if func[inst].opcode != Opcode::ICmp {
1121            return None;
1122        }
1123        let Extra::IntPred(pred) = func[inst].extra else { return None };
1124        // The loop keeps going while the test says so, so an exit taken when the test is true is
1125        // an exit whose continuing condition is the opposite one.
1126        let pred = if stays { pred } else { invert(pred) };
1127        let operands = &func[func[inst].args];
1128        let (&lhs, &rhs) = (operands.first()?, operands.get(1)?);
1129
1130        // One side evolves and the other does not. Swapping puts the one that evolves on the left
1131        // and turns the predicate round with it, so only one direction has to be solved.
1132        let (chrec, limit, pred) = match (self.at(id, lhs), self.at(id, rhs)) {
1133            (Evolution::Affine(chrec), other) => (chrec, other.invariant()?, pred),
1134            (other, Evolution::Affine(chrec)) => (chrec, other.invariant()?, swap(pred)),
1135            _ => return None,
1136        };
1137
1138        // Whether every iteration that goes round asks this test. The header runs on all of them by
1139        // being the header. Any other block runs on all of them when the loop has one latch and the
1140        // only way to that latch is through this block, which is read by walking back from the
1141        // latch while each block has one way in. That takes in the latch itself, and the block in
1142        // front of the jump `crate::canon` splits a back edge into, which is where the test of
1143        // nearly every loop by the time this runs is. With two latches an iteration can go round
1144        // the other one and never reach the test. Anywhere else is a test under a condition, which
1145        // gives no count and which [`bounded_by_its_test`] must not be given.
1146        let each = from == self.loops.header(id) || self.asked_each_time(id, from);
1147        Some(Test { chrec, limit, pred, each })
1148    }
1149}
1150
1151/// Two evolutions added, or subtracted when asked.
1152fn combine(left: Evolution, right: Evolution, ty: Type, flags: Flags, subtract: bool) -> Evolution {
1153    let apply = |a: Invariant, b: Invariant| if subtract { a.minus(b) } else { a.plus(b) };
1154    match (left, right) {
1155        (Evolution::Invariant(a), Evolution::Invariant(b)) => {
1156            apply(a, b).map_or(Evolution::Unknown, Evolution::Invariant)
1157        }
1158        (Evolution::Affine(chrec), Evolution::Invariant(b)) => {
1159            // Adding something that does not move only moves the base.
1160            let Some(base) = apply(chrec.base, b) else { return Evolution::Unknown };
1161            affine(base, chrec.step, ty, flags.intersection(chrec.flags))
1162        }
1163        (Evolution::Invariant(a), Evolution::Affine(chrec)) => {
1164            let (Some(base), Some(step)) = (
1165                apply(a, chrec.base),
1166                if subtract { chrec.step.negated() } else { Some(chrec.step) },
1167            ) else {
1168                return Evolution::Unknown;
1169            };
1170            affine(base, step, ty, flags.intersection(chrec.flags))
1171        }
1172        (Evolution::Affine(a), Evolution::Affine(b)) => {
1173            // Two chrecs of the same loop add componentwise, which is the closure property that
1174            // makes the representation worth having. Of different types they do not, because the
1175            // two sequences wrap at different widths.
1176            if a.ty != b.ty {
1177                return Evolution::Unknown;
1178            }
1179            let (Some(base), Some(step)) = (apply(a.base, b.base), apply(a.step, b.step)) else {
1180                return Evolution::Unknown;
1181            };
1182            affine(base, step, ty, flags.intersection(a.flags).intersection(b.flags))
1183        }
1184        _ => Evolution::Unknown,
1185    }
1186}
1187
1188/// One evolution multiplied by another, which needs one of them to stand still.
1189fn scale(left: Evolution, right: Evolution, ty: Type, flags: Flags) -> Evolution {
1190    let (chrec, by) = match (left, right) {
1191        (Evolution::Invariant(a), Evolution::Invariant(b)) => {
1192            return a.times(b).map_or(Evolution::Unknown, Evolution::Invariant);
1193        }
1194        (Evolution::Affine(chrec), Evolution::Invariant(by))
1195        | (Evolution::Invariant(by), Evolution::Affine(chrec)) => (chrec, by),
1196        // Two chrecs multiplied give a quadratic, which is a chain of recurrences with a second
1197        // step and is outside the subset section 7.4 chose.
1198        _ => return Evolution::Unknown,
1199    };
1200    let (Some(base), Some(step)) = (chrec.base.times(by), chrec.step.times(by)) else {
1201        return Evolution::Unknown;
1202    };
1203    affine(base, step, ty, flags.intersection(chrec.flags))
1204}
1205
1206/// A chrec, or invariant when the step turns out to be nothing.
1207///
1208/// A step of zero is a valid affine chrec describing a value that does not move, and section 7.7
1209/// warns that code dividing by the step to get a trip count divides by zero. Reporting it as
1210/// invariant here means the shape is right for every reader rather than only for the careful
1211/// ones, and the trip count solver still checks, because a step can also come out zero from a
1212/// header parameter incremented by an invariant that happens to be zero.
1213fn affine(base: Invariant, step: Invariant, ty: Type, flags: Flags) -> Evolution {
1214    if step.is_zero() {
1215        return Evolution::Invariant(base);
1216    }
1217    Evolution::Affine(Chrec { base, step, ty, flags })
1218}
1219
1220/// The iteration at which `chrec pred limit` first fails, with what that rests on.
1221///
1222/// The test runs on every iteration that goes round, which [`Scev::bound_at`] checks before asking,
1223/// and that is what lets the test itself stand in for a promise the counter does not carry. See
1224/// [`bounded_by_its_test`].
1225fn solve(chrec: Chrec, limit: Invariant, pred: IntPred) -> Option<Bound> {
1226    // Section 7.7's first way of being wrong. A step of zero is a loop that never leaves through
1227    // this exit, and dividing the distance by it is a crash rather than an answer.
1228    let step = chrec.step.as_number()?;
1229    if step == 0 {
1230        return None;
1231    }
1232    let signed = matches!(pred, IntPred::Slt | IntPred::Sle | IntPred::Sgt | IntPred::Sge);
1233
1234    let mut assumptions = Vec::new();
1235    if !chrec.does_not_wrap(signed) && !bounded_by_its_test(pred, step) {
1236        assumptions.push(Assumption::NoWrap(chrec));
1237    }
1238    if signed {
1239        assumptions.push(Assumption::StrictOverflow);
1240    }
1241
1242    // A test that does not read its operands as signed does not read the constants in them that
1243    // way either, and every constant reaching here was read as signed on the way in.
1244    let (base, limit) = if signed {
1245        (chrec.base, limit)
1246    } else {
1247        (unsigned_base(chrec)?, as_unsigned(limit, chrec.ty)?)
1248    };
1249
1250    // The distance the counter has to travel, always counting up. A loop going down is the same
1251    // problem with the ends swapped, which is why the step is used by size below and its sign is
1252    // spent here.
1253    let apart = step.unsigned_abs();
1254    let found = match (pred, step > 0) {
1255        (IntPred::Slt | IntPred::Ult, true) => {
1256            ordered(limit.minus(base)?, apart, false, assumptions)
1257        }
1258        (IntPred::Sle | IntPred::Ule, true) => {
1259            ordered(limit.minus(base)?, apart, true, assumptions)
1260        }
1261        (IntPred::Sgt | IntPred::Ugt, false) => {
1262            ordered(base.minus(limit)?, apart, false, assumptions)
1263        }
1264        (IntPred::Sge | IntPred::Uge, false) => {
1265            ordered(base.minus(limit)?, apart, true, assumptions)
1266        }
1267        (IntPred::Ne, _) => {
1268            let distance = if step > 0 { limit.minus(base)? } else { base.minus(limit)? };
1269            landing(distance, apart, step < 0 && limit.is_zero(), assumptions)
1270        }
1271        // Either the counter steps away from the limit, in which case the loop is endless rather
1272        // than long, or the test is one this does not solve. Silence is the answer to both.
1273        _ => None,
1274    };
1275    // Written once here rather than threaded through the two solvers, because it is a fact about
1276    // the test and neither of them looks at the test. A count taken from a test with no sign to it,
1277    // which is `!=`, is read unsigned, because that is the reading `as_unsigned` above already put
1278    // its operands through.
1279    let reading = if signed { Reading::Signed } else { Reading::Unsigned };
1280    found.map(|(count, assumptions)| Bound { count, assumptions, reading })
1281}
1282
1283/// Whether the exit test by itself rules out the counter wrapping before the loop ends.
1284///
1285/// An unsigned counter carries no `nuw`, because C says unsigned arithmetic wraps, so without this
1286/// every `for (unsigned i = 0; i < n; i++)` comes back resting on an assumption nothing downstream
1287/// can discharge. What discharges it is the test. A counter stepping up by exactly one is at the
1288/// limit before it is anywhere past it, and the test ends the loop there, so it never reaches the
1289/// top of its type. GCC works the same thing out in `scev_probably_wraps_p`.
1290///
1291/// Every part of that is load bearing. The step has to be one: `i += 2` can go from one below the
1292/// limit to one above the top of the type and come back round at the bottom, which is a loop that
1293/// runs forever rather than one that runs twice as fast. The test has to be the strict one: `<=`
1294/// lets the counter reach the limit and step once more, and a limit that is the largest number of
1295/// its type makes that last step the one that wraps. And the test has to run on every iteration
1296/// that goes round, or the counter can be stepped by a path that never asks it anything.
1297///
1298/// Nothing is claimed here about a signed counter, which needs no help: a signed counter that would
1299/// wrap is a program with undefined behaviour in it and [`Assumption::StrictOverflow`] is where
1300/// that is recorded.
1301fn bounded_by_its_test(pred: IntPred, step: i128) -> bool {
1302    matches!((pred, step), (IntPred::Ult, 1) | (IntPred::Ugt, -1))
1303}
1304
1305/// Whether this sequence stays behind one the exit test already keeps inside its type.
1306///
1307/// [`bounded_by_its_test`] says the counter the test compares never reaches the top of its type.
1308/// Everything else the loop counts with is that counter plus a fixed distance, because two affine
1309/// chrecs of the same loop with the same step differ by a constant, so a sequence starting no
1310/// further along than the counter is a sequence that gets to the top no sooner than the counter
1311/// does, which is never.
1312///
1313/// Same base is the case that matters most and the easiest to see: the test compares `i + 1` and
1314/// the subscript reads `i`, which is one loop written two ways, and the two chrecs differ only in
1315/// where they start.
1316///
1317/// Going up only. A counter going down wraps at the bottom rather than the top, so the sequence
1318/// that is safe is the one that starts further along rather than the one that starts behind, and
1319/// nothing measured so far walks an array downwards. Doing it would be turning the comparison
1320/// round, and it should come with the program that wants it.
1321fn trails(chrec: Chrec, held: Chrec) -> bool {
1322    if chrec.ty != held.ty || chrec.step != held.step {
1323        return false;
1324    }
1325    if chrec.base == held.base {
1326        return true;
1327    }
1328    let (Some(step), Some(mine), Some(theirs)) =
1329        (chrec.step.as_number(), chrec.base.as_number(), held.base.as_number())
1330    else {
1331        return false;
1332    };
1333    // Read as unsigned, which is the reading the test took, so a base that came in negative is a
1334    // large number rather than a small one and starting behind is not what it is doing.
1335    step > 0 && mine >= 0 && theirs >= 0 && mine <= theirs
1336}
1337
1338/// The same expression, read the way a test without a sign reads it.
1339///
1340/// Constants arrive here as the number their bits are when the sign bit is taken seriously,
1341/// because that is the only reading available before anybody knows what will be done with them.
1342/// An unsigned test disagrees about half of them. `for (unsigned char i = 0; i < 200; i++)` holds
1343/// its limit as minus fifty six, and a distance worked out from that is negative, which reads as
1344/// a loop that runs no times rather than one that runs two hundred.
1345///
1346/// The step is not put through this, because a step is a difference rather than a value and its
1347/// signed reading is the one that says which way the counter goes.
1348/// Where a counter starts, read unsigned.
1349///
1350/// What [`as_unsigned`] says, and one more case it has to refuse without the counter to ask. A base
1351/// with a number folded in beside its symbol is safe to read unsigned when the counter promises not
1352/// to wrap that way, because the base is the first value the counter took and it took it without
1353/// wrapping, so the sum is the number it looks like. The countdown ivopts writes tests its variable
1354/// after taking one off, and this is what its base looks like.
1355fn unsigned_base(chrec: Chrec) -> Option<Invariant> {
1356    let base = chrec.base;
1357    let plain = base.on.is_none() && base.read.is_none() && base.scale == 1;
1358    as_unsigned(base, chrec.ty).or_else(|| (plain && chrec.does_not_wrap(false)).then_some(base))
1359}
1360
1361fn as_unsigned(inv: Invariant, ty: Type) -> Option<Invariant> {
1362    match inv.as_number() {
1363        Some(number) if number >= 0 => Some(inv),
1364        Some(number) => {
1365            // Only an integer constant was read as signed in the first place. A pointer never
1366            // was, so a negative number sitting in one is an expression this cannot reinterpret.
1367            let bits = ty.is_int().then(|| ty.bits()).filter(|&bits| bits < 127)?;
1368            Some(Invariant::number(number & ((1i128 << bits) - 1)))
1369        }
1370        // A symbolic operand is whatever it is at run time, and the subtraction below cancels it
1371        // rather than reading it, so long as nothing signed has been folded in beside it. Two
1372        // symbols is two things to cancel and the subtraction only ever cancels one.
1373        None => (inv.on.is_none() && inv.scale == 1 && inv.offset == 0).then_some(inv),
1374    }
1375}
1376
1377/// The count for an exit tested with an ordering, where overshooting the limit still ends it.
1378fn ordered(
1379    distance: Invariant,
1380    step: u128,
1381    inclusive: bool,
1382    mut assumptions: Vec<Assumption>,
1383) -> Option<(Count, Vec<Assumption>)> {
1384    match distance.as_number() {
1385        Some(exact) => {
1386            if exact < 0 {
1387                // The counter starts past the limit, so the test fails the first time it runs.
1388                // That is a count of zero and it rests on nothing at all, not even on the counter
1389                // behaving, because the counter never moves.
1390                return Some((Count::Exact(0), Vec::new()));
1391            }
1392            // Rounding up, because a step that overshoots still took the iteration that overshot.
1393            let count = (exact.unsigned_abs() + u128::from(inclusive)).div_ceil(step);
1394            Some((Count::Exact(count), assumptions))
1395        }
1396        // Symbolic, and only for a step of one, because dividing an expression by anything else
1397        // needs a representation for a division and there is not one here.
1398        None if step == 1 => {
1399            assumptions.push(Assumption::Entered);
1400            let count = distance.plus(Invariant::number(i128::from(inclusive)))?;
1401            Some((Count::Symbolic(count), assumptions))
1402        }
1403        None => None,
1404    }
1405}
1406
1407/// The count for an exit tested with `!=`, where the counter has to land on the limit exactly.
1408///
1409/// This is a different problem from the one above and not a special case of it. An ordering test
1410/// ends the loop the moment the counter is past the limit, so a step that overshoots still stops.
1411/// `!=` only ends the loop on the one iteration where the counter is the limit, so a counter that
1412/// steps over the limit, or that starts on the far side of it, keeps going until it wraps. Both
1413/// of those are endless loops rather than short ones, and answering zero for either was the bug
1414/// this function exists to not have.
1415fn landing(
1416    distance: Invariant,
1417    step: u128,
1418    bottom: bool,
1419    mut assumptions: Vec<Assumption>,
1420) -> Option<(Count, Vec<Assumption>)> {
1421    match distance.as_number() {
1422        Some(exact) => {
1423            let travel = u128::try_from(exact).ok()?;
1424            // Checked outright rather than assumed, which is why nothing here needs an assumption
1425            // about the step dividing anything.
1426            (travel % step == 0).then(|| (Count::Exact(travel / step), assumptions))
1427        }
1428        // A step of one lands on everything ahead of it, so the only thing left to establish is
1429        // that the limit is ahead. `while (p != end)` is this case, and a step of anything else
1430        // would need the division a symbolic distance has no room for.
1431        //
1432        // A counter going down to zero has it established already, because `!=` reads it unsigned
1433        // and nothing unsigned is below zero, so zero is ahead of wherever it starts. The `!=`
1434        // that ivopts writes for a countdown is this case. A promise not to wrap would not do
1435        // instead, since a loop with a limit behind its counter can stop on something else, a
1436        // bounds check for one, long before the counter comes round to break the promise.
1437        None if step == 1 => {
1438            if !bottom {
1439                assumptions.push(Assumption::Approaching);
1440            }
1441            Some((Count::Symbolic(distance), assumptions))
1442        }
1443        None => None,
1444    }
1445}
1446
1447/// The predicate that is true exactly when this one is not.
1448fn invert(pred: IntPred) -> IntPred {
1449    match pred {
1450        IntPred::Eq => IntPred::Ne,
1451        IntPred::Ne => IntPred::Eq,
1452        IntPred::Slt => IntPred::Sge,
1453        IntPred::Sle => IntPred::Sgt,
1454        IntPred::Sgt => IntPred::Sle,
1455        IntPred::Sge => IntPred::Slt,
1456        IntPred::Ult => IntPred::Uge,
1457        IntPred::Ule => IntPred::Ugt,
1458        IntPred::Ugt => IntPred::Ule,
1459        IntPred::Uge => IntPred::Ult,
1460    }
1461}
1462
1463/// The predicate that says the same thing with the operands the other way round.
1464fn swap(pred: IntPred) -> IntPred {
1465    match pred {
1466        IntPred::Eq => IntPred::Eq,
1467        IntPred::Ne => IntPred::Ne,
1468        IntPred::Slt => IntPred::Sgt,
1469        IntPred::Sle => IntPred::Sge,
1470        IntPred::Sgt => IntPred::Slt,
1471        IntPred::Sge => IntPred::Sle,
1472        IntPred::Ult => IntPred::Ugt,
1473        IntPred::Ule => IntPred::Uge,
1474        IntPred::Ugt => IntPred::Ult,
1475        IntPred::Uge => IntPred::Ule,
1476    }
1477}
1478
1479/// The constant a value is, if it is one.
1480fn constant(func: &Func, value: Value) -> Option<(Imm, Type)> {
1481    let Def::Result { inst, .. } = func[value].def else { return None };
1482    if func[inst].opcode != Opcode::IConst {
1483        return None;
1484    }
1485    let Extra::Imm(at) = func[inst].extra else { return None };
1486    let ty = func[value].ty;
1487    ty.is_int().then(|| (func[at], ty))
1488}
1489
1490/// The global whose address a value is, if it is one.
1491fn symbol(func: &Func, value: Value) -> Option<Symbol> {
1492    let Def::Result { inst, .. } = func[value].def else { return None };
1493    if func[inst].opcode != Opcode::GlobalAddr {
1494        return None;
1495    }
1496    let Extra::Symbol(symbol) = func[inst].extra else { return None };
1497    Some(symbol)
1498}
1499
1500/// What this predecessor passes to the block's parameter at this position.
1501///
1502/// `None` when the predecessor branches to the block more than once with different arguments,
1503/// which a `br_if` with both arms on the same block can do and which means the parameter takes a
1504/// value that depends on the test rather than on the edge.
1505fn argument(func: &Func, pred: Block, block: Block, index: usize) -> Option<Value> {
1506    let term = func.terminator(pred)?;
1507    let mut found = None;
1508    for call in func.successors(term) {
1509        if call.block != block {
1510            continue;
1511        }
1512        let arg = *func[call.args].get(index)?;
1513        if found.replace(arg).is_some_and(|old| old != arg) {
1514            return None;
1515        }
1516    }
1517    found
1518}
1519
1520#[cfg(test)]
1521mod tests {
1522    use rucc_base::Interner;
1523    use rucc_ir::{Builder, Extra, Flags, Func, InstData, IntPred, Opcode, Signature, Type, Value};
1524
1525    use crate::cfg::Cfg;
1526    use crate::dom::Dominators;
1527    use crate::loops::{LoopId, Loops};
1528    use crate::scev::{
1529        Anchor, Assumption, Bound, Count, Evolution, Invariant, Reading, Scev, Widening,
1530    };
1531
1532    /// A loop counting in `ty` from `from` by `step` while the counter is below `to`.
1533    ///
1534    /// ```text
1535    /// entry:  jump header(from)
1536    /// header(i): test = icmp pred i, to ; br_if test, body, exit
1537    /// body:   next = add i, step ; jump header(next)
1538    /// exit:   ret
1539    /// ```
1540    ///
1541    /// The counter is the header's only parameter, which is what the tests ask about.
1542    struct Counted {
1543        func: Func,
1544        counter: Value,
1545        next: Value,
1546    }
1547
1548    fn counted(ty: Type, from: i128, to: i128, step: i128, pred: IntPred, flags: Flags) -> Counted {
1549        let (it, ()) = counted_with(ty, from, to, step, pred, flags, |_, _| ());
1550        it
1551    }
1552
1553    /// The same loop, with `extra` run in the body on the counter before the counter steps.
1554    ///
1555    /// The builder appends, and the body's `jump` back to the header has to stay the last
1556    /// instruction in it or the block has no terminator and the loop stops being one. So anything
1557    /// a test wants derived from the counter goes in here rather than being tacked on afterwards.
1558    fn counted_with<T>(
1559        ty: Type,
1560        from: i128,
1561        to: i128,
1562        step: i128,
1563        pred: IntPred,
1564        flags: Flags,
1565        extra: impl FnOnce(&mut Builder<'_>, Value) -> T,
1566    ) -> (Counted, T) {
1567        let mut names = Interner::new();
1568        let mut func = Func::new(names.intern("f"), Signature::new());
1569        let entry = func.create_block();
1570        let header = func.create_block();
1571        let body = func.create_block();
1572        let exit = func.create_block();
1573        let counter = func.append_param(header, ty);
1574
1575        let mut build = Builder::new(&mut func, entry);
1576        let start = build.iconst(ty, from);
1577        build.jump(header, &[start]);
1578
1579        let mut build = Builder::new(&mut func, header);
1580        let limit = build.iconst(ty, to);
1581        let test = build.icmp(pred, counter, limit);
1582        build.br_if(test, body, &[], exit, &[]);
1583
1584        let mut build = Builder::new(&mut func, body);
1585        let derived = extra(&mut build, counter);
1586        let by = build.iconst(ty, step);
1587        let next = build.binary(Opcode::Add, counter, by, flags);
1588        build.jump(header, &[next]);
1589
1590        let mut build = Builder::new(&mut func, exit);
1591        build.ret(&[]);
1592
1593        (Counted { func, counter, next }, derived)
1594    }
1595
1596    /// The analysis over a function, along with the one loop it has.
1597    fn analyse(func: &Func) -> (Cfg, Loops) {
1598        let cfg = Cfg::new(func);
1599        let doms = Dominators::new(&cfg);
1600        let loops = Loops::new(&cfg, &doms);
1601        (cfg, loops)
1602    }
1603
1604    /// The chrec of a value in the one loop of a function.
1605    fn evolution(func: &Func, value: Value) -> Evolution {
1606        let (cfg, loops) = analyse(func);
1607        let id = loops.roots()[0];
1608        Scev::new(func, &cfg, &loops).evolution(id, value)
1609    }
1610
1611    /// The trip count of the one loop of a function.
1612    fn bound(func: &Func) -> Option<Bound> {
1613        let (cfg, loops) = analyse(func);
1614        let id: LoopId = loops.roots()[0];
1615        Scev::new(func, &cfg, &loops).bound(id)
1616    }
1617
1618    #[test]
1619    fn a_counter_from_zero_by_one_is_the_chrec_everyone_expects() {
1620        let it = counted(Type::int(32), 0, 100, 1, IntPred::Slt, Flags::NSW);
1621        let chrec = evolution(&it.func, it.counter).chrec().expect("the counter evolves");
1622        assert_eq!(chrec.base, Invariant::number(0));
1623        assert_eq!(chrec.step, Invariant::number(1));
1624        assert_eq!(chrec.ty, Type::int(32));
1625        assert!(chrec.does_not_wrap(true));
1626    }
1627
1628    #[test]
1629    fn a_walk_over_a_file_scope_array_is_a_chrec_measured_from_the_symbol() {
1630        // The `global_addr` is inside the loop, which is where the compiler leaves one: working
1631        // the address out again is a single instruction and `crate::licm` would rather do that
1632        // than hold it in a register the whole way round. Answering by where a value is defined
1633        // meant `a[i]` on a file scope `a` was an address with nothing to say about it.
1634        let mut names = Interner::new();
1635        let tab = names.intern("tab");
1636        let (it, address) =
1637            counted_with(Type::int(64), 0, 100, 1, IntPred::Slt, Flags::NSW, |build, counter| {
1638                let four = build.iconst(Type::int(64), 4);
1639                let by = build.binary(Opcode::Mul, counter, four, Flags::NSW);
1640                let extra = Extra::Symbol(tab);
1641                let at =
1642                    build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
1643                let args = build.func().push_values(&[at, by]);
1644                build.value(InstData { args, ..InstData::new(Opcode::PtrAdd) }, Type::PTR)
1645            });
1646
1647        let chrec = evolution(&it.func, address).chrec().expect("the address evolves");
1648        assert_eq!(chrec.step, Invariant::number(4));
1649        // Described rather than named, so there is nothing for `plain` to hand back and a reader
1650        // of the base has to go through `on` and see what it is measured from.
1651        assert!(chrec.base.plain().is_none());
1652        let (base, rest) = chrec.base.on().expect("the base is measured from the symbol");
1653        assert_eq!(base, Anchor::Address(tab));
1654        assert_eq!(base.value(), None);
1655        assert_eq!(rest.value, None);
1656        assert_eq!(rest.offset, 0);
1657    }
1658
1659    #[test]
1660    fn the_value_fed_back_is_the_chrec_one_step_along() {
1661        let it = counted(Type::int(32), 5, 100, 3, IntPred::Slt, Flags::NSW);
1662        let chrec = evolution(&it.func, it.next).chrec().expect("the increment evolves");
1663        assert_eq!(chrec.base, Invariant::number(8));
1664        assert_eq!(chrec.step, Invariant::number(3));
1665    }
1666
1667    #[test]
1668    fn a_multiple_of_the_counter_plus_a_number_is_a_chrec_of_its_own() {
1669        // `j = 2 * i + 3` where `i = {0, +, 1}`, which is the shape section 7.4 says pattern
1670        // matching runs out of road on and chains of recurrences do not.
1671        let (it, shifted) =
1672            counted_with(Type::int(32), 0, 100, 1, IntPred::Slt, Flags::NSW, |build, counter| {
1673                let two = build.iconst(Type::int(32), 2);
1674                let three = build.iconst(Type::int(32), 3);
1675                let doubled = build.binary(Opcode::Mul, counter, two, Flags::NSW);
1676                build.binary(Opcode::Add, doubled, three, Flags::NSW)
1677            });
1678
1679        let chrec = evolution(&it.func, shifted).chrec().expect("it evolves");
1680        assert_eq!(chrec.base, Invariant::number(3));
1681        assert_eq!(chrec.step, Invariant::number(2));
1682    }
1683
1684    #[test]
1685    fn a_shift_by_a_constant_scales_the_chrec_and_a_shift_past_the_width_does_not() {
1686        let (it, (scaled, poison)) =
1687            counted_with(Type::int(32), 1, 100, 1, IntPred::Slt, Flags::NSW, |build, counter| {
1688                let three = build.iconst(Type::int(32), 3);
1689                let wide = build.iconst(Type::int(32), 32);
1690                (
1691                    build.binary(Opcode::Shl, counter, three, Flags::NSW),
1692                    build.binary(Opcode::Shl, counter, wide, Flags::NSW),
1693                )
1694            });
1695
1696        let chrec = evolution(&it.func, scaled).chrec().expect("it evolves");
1697        assert_eq!(chrec.base, Invariant::number(8));
1698        assert_eq!(chrec.step, Invariant::number(8));
1699        // A count at the width is poison rather than a shift to zero, so there is no sequence to
1700        // describe.
1701        assert_eq!(evolution(&it.func, poison), Evolution::Unknown);
1702    }
1703
1704    #[test]
1705    fn a_pointer_walked_by_the_element_size_is_a_chrec_in_bytes() {
1706        // What `for (p = a; p != end; p++)` lowers to on an array of four byte elements. Section
1707        // 7.4 calls this the one deliberate extension past affine and the difference between
1708        // analysing half of real C loops and nearly all of them.
1709        let mut names = Interner::new();
1710        let mut func = Func::new(names.intern("f"), Signature::new());
1711        let entry = func.create_block();
1712        let header = func.create_block();
1713        let body = func.create_block();
1714        let exit = func.create_block();
1715        let start = func.append_param(entry, Type::PTR);
1716        let cursor = func.append_param(header, Type::PTR);
1717
1718        let mut build = Builder::new(&mut func, entry);
1719        build.jump(header, &[start]);
1720        let mut build = Builder::new(&mut func, header);
1721        let done = build.icmp(IntPred::Eq, cursor, start);
1722        build.br_if(done, exit, &[], body, &[]);
1723        let mut build = Builder::new(&mut func, body);
1724        let four = build.iconst(Type::int(64), 4);
1725        let next = build.binary(Opcode::PtrAdd, cursor, four, Flags::NONE);
1726        build.jump(header, &[next]);
1727        let mut build = Builder::new(&mut func, exit);
1728        build.ret(&[]);
1729
1730        let chrec = evolution(&func, cursor).chrec().expect("the cursor evolves");
1731        assert_eq!(chrec.base, Invariant::of(start));
1732        assert_eq!(chrec.step, Invariant::number(4));
1733        assert_eq!(chrec.ty, Type::PTR);
1734    }
1735
1736    #[test]
1737    fn a_value_the_loop_does_not_change_widens_the_way_a_sequence_does() {
1738        // `(long)row` inside a loop over something else. There is no sequence here and so nothing
1739        // that could wrap, and the answer was unknown all the same, which made a sequence that does
1740        // not move harder to widen than one that does. What it cost is `a[row * N + k]` round `k`,
1741        // whose address came back unknown on account of the widening in the middle of it.
1742        let mut names = Interner::new();
1743        let mut func = Func::new(names.intern("f"), Signature::new());
1744        let entry = func.create_block();
1745        let header = func.create_block();
1746        let body = func.create_block();
1747        let exit = func.create_block();
1748        let row = func.append_param(entry, Type::int(32));
1749        let counter = func.append_param(header, Type::int(64));
1750
1751        let mut build = Builder::new(&mut func, entry);
1752        let zero = build.iconst(Type::int(64), 0);
1753        build.jump(header, &[zero]);
1754
1755        let mut build = Builder::new(&mut func, header);
1756        let limit = build.iconst(Type::int(64), 100);
1757        let test = build.icmp(IntPred::Slt, counter, limit);
1758        build.br_if(test, body, &[], exit, &[]);
1759
1760        let mut build = Builder::new(&mut func, body);
1761        let wide = build.unary(Opcode::SExt, row, Type::int(64));
1762        let one = build.iconst(Type::int(64), 1);
1763        let next = build.binary(Opcode::Add, counter, one, Flags::NSW);
1764        build.jump(header, &[next]);
1765        Builder::new(&mut func, exit).ret(&[]);
1766
1767        let word = Type::int(64);
1768        let widened =
1769            Invariant::of(row).widened(Reading::Signed, word).expect("one of a value widens");
1770        assert_eq!(evolution(&func, wide), Evolution::Invariant(widened));
1771    }
1772
1773    /// A value to hang an invariant on, which these never look inside.
1774    fn some_value() -> Value {
1775        let mut names = Interner::new();
1776        let mut func = Func::new(names.intern("f"), Signature::new());
1777        let entry = func.create_block();
1778        func.append_param(entry, Type::int(8))
1779    }
1780
1781    #[test]
1782    fn one_of_a_value_widens_and_arithmetic_on_it_does_not() {
1783        // What `Scev::extend` may take. A value is widened by describing the extension rather than
1784        // by naming a value nothing computes, which is what lets `for (i = start; i < n; i++)`
1785        // have a chrec at pointer width. `2 * x + 3` is refused, because the narrow arithmetic may
1786        // already have wrapped and `sext(2 * x + 3)` is not `2 * sext(x) + 3`.
1787        let value = some_value();
1788        let word = Type::int(64);
1789        assert_eq!(
1790            Invariant::of(value).widened(Reading::Signed, word),
1791            Some(Invariant {
1792                on: None,
1793                value: Some(value),
1794                read: Some(Widening { reading: Reading::Signed, to: word }),
1795                scale: 1,
1796                offset: 0,
1797            }),
1798        );
1799        assert_eq!(Invariant::scaled(value, 2, 3).widened(Reading::Signed, word), None);
1800        assert_eq!(Invariant::scaled(value, 1, 3).widened(Reading::Signed, word), None);
1801        // A number is the same number at both widths under a sign extension, and under a zero
1802        // extension once it is not negative.
1803        assert_eq!(
1804            Invariant::number(-1).widened(Reading::Signed, word),
1805            Some(Invariant::number(-1)),
1806        );
1807        assert_eq!(Invariant::number(-1).widened(Reading::Unsigned, word), None);
1808    }
1809
1810    #[test]
1811    fn an_extension_of_an_extension_collapses_only_where_it_means_the_same_thing() {
1812        // A zero extension is never negative, so reading its result as signed afterwards is the
1813        // same numbers and the pair is one zero extension at the outer width. The other way round
1814        // it is not: a sign extended negative number read as unsigned is a different quantity, and
1815        // there is nothing to collapse to.
1816        let value = some_value();
1817        let (half, word) = (Type::int(32), Type::int(64));
1818        let read = |inv: Invariant| inv.read.expect("a widened value carries how it is read");
1819
1820        let zeroed = Invariant::of(value).widened(Reading::Unsigned, half).expect("it widens");
1821        let again = zeroed.widened(Reading::Signed, word).expect("and it widens again");
1822        assert_eq!(read(again), Widening { reading: Reading::Unsigned, to: word });
1823
1824        let signed = Invariant::of(value).widened(Reading::Signed, half).expect("it widens");
1825        assert_eq!(signed.widened(Reading::Unsigned, word), None);
1826        let again = signed.widened(Reading::Signed, word).expect("and it widens again");
1827        assert_eq!(read(again), Widening { reading: Reading::Signed, to: word });
1828    }
1829
1830    #[test]
1831    fn two_invariants_on_the_same_value_read_two_ways_do_not_add() {
1832        // `sext(x)` and `zext(x)` are the same bits and not the same quantity, so a sum of them is
1833        // not two of anything and there is no shape here for it.
1834        let value = some_value();
1835        let word = Type::int(64);
1836        let signed = Invariant::of(value).widened(Reading::Signed, word).expect("it widens");
1837        let zeroed = Invariant::of(value).widened(Reading::Unsigned, word).expect("it widens");
1838        assert_eq!(signed.plus(zeroed), None);
1839        assert_eq!(
1840            signed.plus(signed),
1841            Some(Invariant {
1842                on: None,
1843                value: Some(value),
1844                read: Some(Widening { reading: Reading::Signed, to: word }),
1845                scale: 2,
1846                offset: 0,
1847            }),
1848            "the same value read the same way adds to two of it",
1849        );
1850    }
1851
1852    #[test]
1853    fn a_counter_in_unsigned_char_wraps_and_does_not_widen_without_a_promise() {
1854        // Section 7.7's second way of being wrong. `{0, +, 1}` in `unsigned char` is not
1855        // `0, 1, 2, ...`, it is that modulo two hundred and fifty six, and widening it is only
1856        // the same sequence if it does not get that far.
1857        //
1858        // An inclusive test, because a strict one is a proof of its own and the case below is
1859        // about what happens when there is no proof at all. This loop does not in fact wrap, and
1860        // the point is that nothing here can say so.
1861        let (it, wide) =
1862            counted_with(Type::int(8), 0, 100, 1, IntPred::Ule, Flags::NONE, |build, counter| {
1863                build.unary(Opcode::ZExt, counter, Type::int(32))
1864            });
1865        let chrec = evolution(&it.func, it.counter).chrec().expect("the counter evolves");
1866        assert_eq!(chrec.ty, Type::int(8));
1867        assert!(!chrec.does_not_wrap(false));
1868        assert_eq!(evolution(&it.func, wide), Evolution::Unknown);
1869    }
1870
1871    #[test]
1872    fn a_counter_its_own_test_holds_widens_without_a_promise() {
1873        // The same counter under the strict test, which is the shape `for (unsigned i = 0; i < n;
1874        // i++)` has. Nothing promised anything, and the test is the proof: the counter is at the
1875        // limit before it is anywhere past it, and the loop ends there.
1876        let (it, wide) =
1877            counted_with(Type::int(8), 0, 100, 1, IntPred::Ult, Flags::NONE, |build, counter| {
1878                build.unary(Opcode::ZExt, counter, Type::int(32))
1879            });
1880        let narrow = evolution(&it.func, it.counter).chrec().expect("the counter evolves");
1881        assert!(!narrow.does_not_wrap(false), "nothing was promised, so nothing carries a flag");
1882        let chrec = evolution(&it.func, wide).chrec().expect("its own test holds it");
1883        assert_eq!(chrec.ty, Type::int(32));
1884        assert_eq!(chrec.base, Invariant::number(0));
1885        assert_eq!(chrec.step, Invariant::number(1));
1886    }
1887
1888    #[test]
1889    fn a_sequence_that_starts_further_along_than_the_counter_does_not_widen() {
1890        // `trails` in the direction it refuses. The test holds `i`, which starts at zero, and this
1891        // asks about `i + 1`, which starts one further along. One further along is where the
1892        // counter would be if it had gone round once more, and going round once more is the step
1893        // nothing here rules out.
1894        let (it, wide) =
1895            counted_with(Type::int(8), 0, 100, 1, IntPred::Ult, Flags::NONE, |build, counter| {
1896                let one = build.iconst(Type::int(8), 1);
1897                let ahead = build.binary(Opcode::Add, counter, one, Flags::NONE);
1898                build.unary(Opcode::ZExt, ahead, Type::int(32))
1899            });
1900        assert_eq!(evolution(&it.func, wide), Evolution::Unknown);
1901    }
1902
1903    #[test]
1904    fn a_counter_in_short_widens_when_the_increment_promised_it_would_not_wrap() {
1905        let (it, (wide, zero_extended)) =
1906            counted_with(Type::int(16), 0, 100, 1, IntPred::Slt, Flags::NSW, |build, counter| {
1907                (
1908                    build.unary(Opcode::SExt, counter, Type::int(32)),
1909                    build.unary(Opcode::ZExt, counter, Type::int(32)),
1910                )
1911            });
1912
1913        let chrec = evolution(&it.func, wide).chrec().expect("it widens");
1914        assert_eq!(chrec.ty, Type::int(32));
1915        assert_eq!(chrec.base, Invariant::number(0));
1916        assert_eq!(chrec.step, Invariant::number(1));
1917        // `nsw` is a promise about the signed reading and says nothing about the unsigned one.
1918        assert_eq!(evolution(&it.func, zero_extended), Evolution::Unknown);
1919    }
1920
1921    #[test]
1922    fn a_step_of_zero_is_invariant_and_has_no_trip_count() {
1923        // Section 7.7's first way of being wrong. `i += k` with `k` of zero is a valid affine
1924        // chrec of a loop that never leaves through this exit, and code dividing the distance by
1925        // the step divides by zero.
1926        let it = counted(Type::int(32), 0, 100, 0, IntPred::Slt, Flags::NSW);
1927        assert!(matches!(evolution(&it.func, it.counter), Evolution::Invariant(_)));
1928        assert_eq!(bound(&it.func), None);
1929    }
1930
1931    #[test]
1932    fn a_counted_loop_has_the_count_anyone_would_work_out_by_hand() {
1933        let it = counted(Type::int(32), 0, 100, 1, IntPred::Slt, Flags::NSW);
1934        let found = bound(&it.func).expect("it is counted");
1935        let (count, assumptions) = found.parts();
1936        assert_eq!(count, Count::Exact(100));
1937        // The distance is a number and it is not negative, so being entered is not in question.
1938        // Signed overflow being undefined still is, which is what `-fwrapv` would withdraw.
1939        assert_eq!(assumptions, [Assumption::StrictOverflow]);
1940        assert_eq!(found.proven(), None);
1941    }
1942
1943    #[test]
1944    fn a_step_that_overshoots_still_takes_the_iteration_that_overshot() {
1945        // Zero, three, six, nine, and the test fails at twelve, so four iterations rather than
1946        // three and a third. Rounding the other way is an off by one in every unroller.
1947        let it = counted(Type::int(32), 0, 10, 3, IntPred::Slt, Flags::NSW);
1948        let (count, _) = bound(&it.func).expect("it is counted").parts();
1949        assert_eq!(count, Count::Exact(4));
1950    }
1951
1952    #[test]
1953    fn an_inclusive_test_runs_one_more_time() {
1954        let it = counted(Type::int(32), 0, 10, 1, IntPred::Sle, Flags::NSW);
1955        let (count, _) = bound(&it.func).expect("it is counted").parts();
1956        assert_eq!(count, Count::Exact(11));
1957    }
1958
1959    #[test]
1960    fn a_loop_whose_test_fails_first_time_runs_no_times_and_rests_on_nothing() {
1961        let it = counted(Type::int(32), 10, 0, 1, IntPred::Slt, Flags::NSW);
1962        let found = bound(&it.func).expect("it is counted");
1963        assert_eq!(found.proven(), Some(Count::Exact(0)));
1964        assert!(found.assumptions().is_empty());
1965    }
1966
1967    #[test]
1968    fn counting_down_is_the_same_problem_with_the_ends_swapped() {
1969        let it = counted(Type::int(32), 10, 0, -1, IntPred::Sgt, Flags::NSW);
1970        let (count, _) = bound(&it.func).expect("it is counted").parts();
1971        assert_eq!(count, Count::Exact(10));
1972    }
1973
1974    #[test]
1975    fn an_unsigned_test_does_not_drag_in_the_signed_overflow_assumption() {
1976        let it = counted(Type::int(32), 0, 100, 1, IntPred::Ult, Flags::NUW);
1977        let found = bound(&it.func).expect("it is counted");
1978        assert_eq!(found.proven(), Some(Count::Exact(100)));
1979    }
1980
1981    #[test]
1982    fn a_test_against_something_the_loop_does_not_change_gives_a_symbolic_count() {
1983        // `for (i = 0; i < n; i++)`, where the answer is `n` and is only `n` if the loop is
1984        // entered, because `n` of minus one runs no times and the distance is minus one.
1985        let mut names = Interner::new();
1986        let mut func = Func::new(names.intern("f"), Signature::new());
1987        let entry = func.create_block();
1988        let header = func.create_block();
1989        let body = func.create_block();
1990        let exit = func.create_block();
1991        let limit = func.append_param(entry, Type::int(32));
1992        let counter = func.append_param(header, Type::int(32));
1993
1994        let mut build = Builder::new(&mut func, entry);
1995        let zero = build.iconst(Type::int(32), 0);
1996        build.jump(header, &[zero]);
1997        let mut build = Builder::new(&mut func, header);
1998        let test = build.icmp(IntPred::Slt, counter, limit);
1999        build.br_if(test, body, &[], exit, &[]);
2000        let mut build = Builder::new(&mut func, body);
2001        let one = build.iconst(Type::int(32), 1);
2002        let next = build.binary(Opcode::Add, counter, one, Flags::NSW);
2003        build.jump(header, &[next]);
2004        let mut build = Builder::new(&mut func, exit);
2005        build.ret(&[]);
2006
2007        let found = bound(&func).expect("it is counted");
2008        let (count, assumptions) = found.parts();
2009        assert_eq!(count, Count::Symbolic(Invariant::of(limit)));
2010        assert!(assumptions.contains(&Assumption::Entered), "{assumptions:?}");
2011        assert!(assumptions.contains(&Assumption::StrictOverflow), "{assumptions:?}");
2012        assert_eq!(found.proven(), None);
2013    }
2014
2015    /// `for (c = n; c != limit; c--)`, with the counter in sixty four bits and no flags on it.
2016    fn down_to(limit: i128) -> (Func, Value) {
2017        let mut names = Interner::new();
2018        let mut func = Func::new(names.intern("f"), Signature::new());
2019        let entry = func.create_block();
2020        let header = func.create_block();
2021        let body = func.create_block();
2022        let exit = func.create_block();
2023        let start = func.append_param(entry, Type::int(64));
2024        let counter = func.append_param(header, Type::int(64));
2025
2026        let mut build = Builder::new(&mut func, entry);
2027        build.jump(header, &[start]);
2028        let mut build = Builder::new(&mut func, header);
2029        let limit = build.iconst(Type::int(64), limit);
2030        let test = build.icmp(IntPred::Ne, counter, limit);
2031        build.br_if(test, body, &[], exit, &[]);
2032        let mut build = Builder::new(&mut func, body);
2033        let one = build.iconst(Type::int(64), 1);
2034        let next = build.binary(Opcode::Sub, counter, one, Flags::NONE);
2035        build.jump(header, &[next]);
2036        let mut build = Builder::new(&mut func, exit);
2037        build.ret(&[]);
2038        (func, start)
2039    }
2040
2041    #[test]
2042    fn a_countdown_to_zero_is_always_heading_for_it() {
2043        let (func, start) = down_to(0);
2044        let found = bound(&func).expect("it is counted");
2045        let (count, assumptions) = found.parts();
2046        assert_eq!(count, Count::Symbolic(Invariant::of(start)));
2047        assert!(!assumptions.contains(&Assumption::Approaching), "{assumptions:?}");
2048    }
2049
2050    #[test]
2051    fn a_countdown_tested_after_its_step_is_counted_when_it_cannot_wrap() {
2052        // The shape ivopts writes: the variable starts one above the count and the header takes
2053        // one off before the test, so what the test sees starts at the start less one.
2054        for (flags, counted) in [(Flags::NSW | Flags::NUW, true), (Flags::NSW, false)] {
2055            let mut names = Interner::new();
2056            let mut func = Func::new(names.intern("f"), Signature::new());
2057            let entry = func.create_block();
2058            let header = func.create_block();
2059            let body = func.create_block();
2060            let exit = func.create_block();
2061            let start = func.append_param(entry, Type::int(64));
2062            let counter = func.append_param(header, Type::int(64));
2063
2064            Builder::new(&mut func, entry).jump(header, &[start]);
2065            let mut build = Builder::new(&mut func, header);
2066            let one = build.iconst(Type::int(64), 1);
2067            let next = build.binary(Opcode::Sub, counter, one, flags);
2068            let zero = build.iconst(Type::int(64), 0);
2069            let test = build.icmp(IntPred::Ne, next, zero);
2070            build.br_if(test, body, &[], exit, &[]);
2071            Builder::new(&mut func, body).jump(header, &[next]);
2072            Builder::new(&mut func, exit).ret(&[]);
2073
2074            let found = bound(&func);
2075            assert_eq!(found.is_some(), counted, "{flags:?}");
2076            if let Some(found) = found {
2077                let at = Invariant::of(start).plus(Invariant::number(-1)).expect("it adds");
2078                assert_eq!(found.comes_back(), Some(Count::Symbolic(at)));
2079            }
2080        }
2081    }
2082
2083    #[test]
2084    fn a_countdown_to_anything_else_may_have_started_below_it() {
2085        // Started at zero, this one goes all the way round before it gets to one.
2086        let (func, _) = down_to(1);
2087        let found = bound(&func).expect("it is counted");
2088        let (_, assumptions) = found.parts();
2089        assert!(assumptions.contains(&Assumption::Approaching), "{assumptions:?}");
2090    }
2091
2092    #[test]
2093    fn the_count_records_which_reading_its_test_took() {
2094        // What a consumer widening a symbolic count has to know. The limit is a value of the
2095        // counter's type and which number that value is depends on how its test read it.
2096        let signed = counted(Type::int(32), 0, 100, 1, IntPred::Slt, Flags::NSW);
2097        assert_eq!(bound(&signed.func).expect("it is counted").reading(), Reading::Signed);
2098        let unsigned = counted(Type::int(32), 0, 100, 1, IntPred::Ult, Flags::NUW);
2099        assert_eq!(bound(&unsigned.func).expect("it is counted").reading(), Reading::Unsigned);
2100    }
2101
2102    #[test]
2103    fn a_counter_without_a_no_wrap_promise_carries_the_assumption_instead() {
2104        // An inclusive test, because the strict one is the case the test itself answers. Under
2105        // `<=` the counter reaches the limit and is stepped once more, so a limit at the top of
2106        // the type makes that last step the one that wraps and nothing here rules it out.
2107        let it = counted(Type::int(32), 0, 100, 1, IntPred::Ule, Flags::NONE);
2108        let found = bound(&it.func).expect("it is counted");
2109        let (_, assumptions) = found.parts();
2110        assert!(assumptions.iter().any(|a| matches!(a, Assumption::NoWrap(_))), "{assumptions:?}");
2111    }
2112
2113    #[test]
2114    fn an_unsigned_counter_stepping_by_one_is_held_by_its_own_test() {
2115        // `for (unsigned i = 0; i < n; i++)` written out. Unsigned arithmetic wraps in C so the
2116        // increment carries no `nuw`, and without reading the test this would rest on an
2117        // assumption nothing downstream can discharge.
2118        let it = counted(Type::int(32), 0, 100, 1, IntPred::Ult, Flags::NONE);
2119        let found = bound(&it.func).expect("it is counted");
2120        assert_eq!(found.assumptions(), &[]);
2121        assert_eq!(found.proven(), Some(Count::Exact(100)));
2122    }
2123
2124    #[test]
2125    fn counting_down_by_one_is_held_the_same_way() {
2126        let it = counted(Type::int(32), 100, 0, -1, IntPred::Ugt, Flags::NONE);
2127        let found = bound(&it.func).expect("it is counted");
2128        assert_eq!(found.assumptions(), &[]);
2129        assert_eq!(found.proven(), Some(Count::Exact(100)));
2130    }
2131
2132    #[test]
2133    fn a_step_of_two_can_jump_the_limit_so_the_test_holds_nothing() {
2134        // The counter is never at the limit, so the loop can be left by a step that goes from one
2135        // below the limit to one past the top of the type and comes back round at the bottom.
2136        let it = counted(Type::int(32), 0, 100, 2, IntPred::Ult, Flags::NONE);
2137        let found = bound(&it.func).expect("it is counted");
2138        let (_, assumptions) = found.parts();
2139        assert!(assumptions.iter().any(|a| matches!(a, Assumption::NoWrap(_))), "{assumptions:?}");
2140    }
2141
2142    #[test]
2143    fn a_test_the_counter_can_be_stepped_without_being_asked_gives_no_count() {
2144        // ```text
2145        // header(i): br_if flag, check, latch
2146        // check:     br_if i <u 100, latch, exit
2147        // latch:     jump header(i + 1)
2148        // ```
2149        // The counter goes round by a path that never reaches the test, so the test says nothing
2150        // about how far the counter got, and with `flag` false the loop never ends at all.
2151        let mut names = Interner::new();
2152        let mut func = Func::new(names.intern("f"), Signature::new());
2153        let entry = func.create_block();
2154        let header = func.create_block();
2155        let check = func.create_block();
2156        let latch = func.create_block();
2157        let exit = func.create_block();
2158        let flag = func.append_param(entry, Type::int(1));
2159        let counter = func.append_param(header, Type::int(32));
2160
2161        let mut build = Builder::new(&mut func, entry);
2162        let zero = build.iconst(Type::int(32), 0);
2163        build.jump(header, &[zero]);
2164        let mut build = Builder::new(&mut func, header);
2165        build.br_if(flag, check, &[], latch, &[]);
2166        let mut build = Builder::new(&mut func, check);
2167        let limit = build.iconst(Type::int(32), 100);
2168        let test = build.icmp(IntPred::Ult, counter, limit);
2169        build.br_if(test, latch, &[], exit, &[]);
2170        let mut build = Builder::new(&mut func, latch);
2171        let one = build.iconst(Type::int(32), 1);
2172        let next = build.binary(Opcode::Add, counter, one, Flags::NONE);
2173        build.jump(header, &[next]);
2174        let mut build = Builder::new(&mut func, exit);
2175        build.ret(&[]);
2176
2177        assert!(bound(&func).is_none());
2178    }
2179
2180    #[test]
2181    fn a_test_asked_only_once_another_one_passes_gives_no_count() {
2182        // `while (i != 1024 || j <= 0) { i *= 2; ++j; }`, which is gcc.c-torture 20000731-2.
2183        //
2184        // ```text
2185        // header(i, j): br_if i != 1024, latch, check
2186        // check:        br_if j <= 0, latch, exit
2187        // latch:        jump header(i + i, j + 1)
2188        // ```
2189        // `j <= 0` first fails on the second iteration and the loop runs ten, because the test is
2190        // only asked once `i` is 1024. Reading a count off it said `j` ends at one.
2191        let mut names = Interner::new();
2192        let mut func = Func::new(names.intern("f"), Signature::new());
2193        let entry = func.create_block();
2194        let header = func.create_block();
2195        let check = func.create_block();
2196        let latch = func.create_block();
2197        let exit = func.create_block();
2198        let (i, j) =
2199            (func.append_param(header, Type::int(32)), func.append_param(header, Type::int(32)));
2200
2201        let mut build = Builder::new(&mut func, entry);
2202        let one = build.iconst(Type::int(32), 1);
2203        let zero = build.iconst(Type::int(32), 0);
2204        build.jump(header, &[one, zero]);
2205        let mut build = Builder::new(&mut func, header);
2206        let top = build.iconst(Type::int(32), 1024);
2207        let short = build.icmp(IntPred::Ne, i, top);
2208        build.br_if(short, latch, &[], check, &[]);
2209        let mut build = Builder::new(&mut func, check);
2210        let none = build.iconst(Type::int(32), 0);
2211        let again = build.icmp(IntPred::Sle, j, none);
2212        build.br_if(again, latch, &[], exit, &[]);
2213        let mut build = Builder::new(&mut func, latch);
2214        let twice = build.binary(Opcode::Add, i, i, Flags::NONE);
2215        let step = build.iconst(Type::int(32), 1);
2216        let next = build.binary(Opcode::Add, j, step, Flags::NSW);
2217        build.jump(header, &[twice, next]);
2218        let mut build = Builder::new(&mut func, exit);
2219        build.ret(&[]);
2220
2221        assert!(bound(&func).is_none());
2222    }
2223
2224    #[test]
2225    fn a_test_that_ends_the_loop_when_it_succeeds_is_read_the_other_way_round() {
2226        // `for (i = 0; ; i++) if (i >= 100) break;`, which is the same loop with the arms of the
2227        // branch swapped. The test that keeps the loop going is the opposite of the one written.
2228        let mut names = Interner::new();
2229        let mut func = Func::new(names.intern("f"), Signature::new());
2230        let entry = func.create_block();
2231        let header = func.create_block();
2232        let body = func.create_block();
2233        let exit = func.create_block();
2234        let counter = func.append_param(header, Type::int(32));
2235
2236        let mut build = Builder::new(&mut func, entry);
2237        let zero = build.iconst(Type::int(32), 0);
2238        build.jump(header, &[zero]);
2239        let mut build = Builder::new(&mut func, header);
2240        let limit = build.iconst(Type::int(32), 100);
2241        let done = build.icmp(IntPred::Sge, counter, limit);
2242        build.br_if(done, exit, &[], body, &[]);
2243        let mut build = Builder::new(&mut func, body);
2244        let one = build.iconst(Type::int(32), 1);
2245        let next = build.binary(Opcode::Add, counter, one, Flags::NSW);
2246        build.jump(header, &[next]);
2247        let mut build = Builder::new(&mut func, exit);
2248        build.ret(&[]);
2249
2250        let (count, _) = bound(&func).expect("it is counted").parts();
2251        assert_eq!(count, Count::Exact(100));
2252    }
2253
2254    #[test]
2255    fn an_unsigned_limit_past_the_middle_of_its_type_is_not_a_negative_one() {
2256        // `for (unsigned char i = 0; i < 200; i++)`. Two hundred does not fit in a signed byte
2257        // and the constant is held as minus fifty six, so a distance taken at face value is
2258        // negative and reads as a loop that runs no times.
2259        let it = counted(Type::int(8), 0, 200, 1, IntPred::Ult, Flags::NUW);
2260        let found = bound(&it.func).expect("it is counted");
2261        assert_eq!(found.proven(), Some(Count::Exact(200)));
2262    }
2263
2264    #[test]
2265    fn a_walk_that_lands_on_a_not_equal_limit_exactly_is_counted() {
2266        // `while (i != 10)` counting by one, which is `while (p != end)` over an array once the
2267        // element size has been divided out. `!=` says nothing about how its operands are read,
2268        // so the promise it wants is the unsigned one and an `nsw` on its own is not enough.
2269        let it = counted(Type::int(32), 0, 10, 1, IntPred::Ne, Flags::NSW.union(Flags::NUW));
2270        let found = bound(&it.func).expect("it lands on its limit");
2271        // The step divides the distance and both are numbers, so it was checked rather than
2272        // assumed and there is nothing left over.
2273        assert_eq!(found.proven(), Some(Count::Exact(10)));
2274    }
2275
2276    #[test]
2277    fn a_counter_stepping_away_from_a_not_equal_limit_is_not_a_loop_that_runs_no_times() {
2278        // The distance is negative and an ordering test would read that as the loop never being
2279        // entered. `!=` reads it as the counter never arriving, which is an endless loop, and
2280        // answering zero for it was a real bug that the property test in `tests/scev.rs` found.
2281        let it = counted(Type::int(32), 48, 15, 1, IntPred::Ne, Flags::NSW);
2282        assert_eq!(bound(&it.func), None);
2283    }
2284
2285    #[test]
2286    fn a_counter_stepping_over_a_not_equal_limit_never_arrives_either() {
2287        // Zero, three, six, nine, twelve, and ten is never one of them. An ordering test would
2288        // have stopped at twelve.
2289        let it = counted(Type::int(32), 0, 10, 3, IntPred::Ne, Flags::NSW);
2290        assert_eq!(bound(&it.func), None);
2291    }
2292
2293    #[test]
2294    fn an_estimate_is_the_count_when_there_is_one_and_a_guess_when_there_is_not() {
2295        let counted_loop = counted(Type::int(32), 0, 7, 1, IntPred::Slt, Flags::NSW);
2296        let (cfg, loops) = analyse(&counted_loop.func);
2297        let id = loops.roots()[0];
2298        let estimate = Scev::new(&counted_loop.func, &cfg, &loops).estimate(id);
2299        assert_eq!(estimate.iterations(), 7);
2300        assert!(!estimate.is_guess());
2301
2302        // A loop this cannot count still has to answer, because the caller is deciding whether
2303        // something is worth doing rather than whether it is legal.
2304        let uncounted = counted(Type::int(32), 0, 100, 0, IntPred::Slt, Flags::NSW);
2305        let (cfg, loops) = analyse(&uncounted.func);
2306        let id = loops.roots()[0];
2307        let estimate = Scev::new(&uncounted.func, &cfg, &loops).estimate(id);
2308        assert!(estimate.is_guess());
2309        assert_eq!(estimate.iterations(), super::ASSUMED_ITERATIONS);
2310    }
2311
2312    #[test]
2313    fn a_value_the_loop_does_not_touch_is_invariant_rather_than_unknown() {
2314        let it = counted(Type::int(32), 0, 100, 1, IntPred::Slt, Flags::NSW);
2315        let (cfg, loops) = analyse(&it.func);
2316        let id = loops.roots()[0];
2317        let mut scev = Scev::new(&it.func, &cfg, &loops);
2318        // The counter's start is an `iconst` in the entry block, which is both.
2319        assert_eq!(
2320            scev.evolution(id, it.counter).chrec().expect("it evolves").base,
2321            Invariant::number(0)
2322        );
2323    }
2324
2325    #[test]
2326    fn a_back_edge_of_its_own_does_not_hide_the_counter() {
2327        // What canonicalization leaves behind. The back edge goes through a block that does nothing
2328        // but pass the increment on, so the value arriving at the header is a parameter of that
2329        // block rather than the increment itself. Reading through it is undoing a rename and not an
2330        // analysis, and without it the trip count of every loop the pipeline produces is nothing.
2331        let mut names = Interner::new();
2332        let mut func = Func::new(names.intern("f"), Signature::new());
2333        let entry = func.create_block();
2334        let header = func.create_block();
2335        let body = func.create_block();
2336        let latch = func.create_block();
2337        let exit = func.create_block();
2338        let counter = func.append_param(header, Type::int(32));
2339        let carried = func.append_param(latch, Type::int(32));
2340
2341        let start = Builder::new(&mut func, entry).iconst(Type::int(32), 0);
2342        Builder::new(&mut func, entry).jump(header, &[start]);
2343
2344        let mut build = Builder::new(&mut func, header);
2345        let limit = build.iconst(Type::int(32), 100);
2346        let test = build.icmp(IntPred::Slt, counter, limit);
2347        build.br_if(test, body, &[], exit, &[]);
2348
2349        let mut build = Builder::new(&mut func, body);
2350        let by = build.iconst(Type::int(32), 1);
2351        let next = build.binary(Opcode::Add, counter, by, Flags::NSW);
2352        build.jump(latch, &[next]);
2353
2354        Builder::new(&mut func, latch).jump(header, &[carried]);
2355        Builder::new(&mut func, exit).ret(&[]);
2356
2357        let chrec = evolution(&func, counter).chrec().expect("the counter still evolves");
2358        assert_eq!(chrec.base, Invariant::number(0));
2359        assert_eq!(chrec.step, Invariant::number(1));
2360        let (count, _) = bound(&func).expect("it is still counted").parts();
2361        assert_eq!(count, Count::Exact(100));
2362    }
2363
2364    #[test]
2365    fn every_assumption_says_what_it_is_in_a_line() {
2366        let it = counted(Type::int(8), 0, 100, 1, IntPred::Ult, Flags::NONE);
2367        let found = bound(&it.func).expect("it is counted");
2368        for assumption in found.assumptions() {
2369            let line = assumption.describe();
2370            assert!(!line.is_empty());
2371            assert!(!line.contains('\n'), "an assumption is one line: {line}");
2372        }
2373    }
2374}