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