Skip to main content

rucc_regalloc/
live.rs

1//! Where every value in a machine function is live.
2//!
3//! Design: `spec/10-backend.md` section 10.4.
4//!
5//! A register can be given to two values at once exactly when the two are never both wanted, so
6//! this is the question every allocator asks first and the one both of ours will read the answer
7//! to from here. It is asked of the machine IR while it is still in SSA form, which is what makes
8//! the answer cheap: a value is written once, so its live range is one interval from where it is
9//! written to the last place it is read, and there is no need to ask which of several definitions
10//! a use is reading from.
11//!
12//! # What the answer is
13//!
14//! A list of pieces per virtual register, one for each run of blocks the value is live over, and
15//! the interval around them for anyone who only wants to know where a value starts and stops.
16//!
17//! The pieces are what it takes to say that a value live in one loop and live again in a later one
18//! is not live in between. Both loops are in the same line of points, so an interval that covered
19//! them both would cover everything laid out between them and every value in there would look like
20//! it was competing for a register with one it never meets. Twelve such values in a row are twelve
21//! registers gone on a machine that has twelve, which is how a function using half the machine
22//! ended up spilling. tamnd/rucc#982.
23//!
24//! Being dead in a piece's hole means dead for good rather than dead for a while. A value is live
25//! in a block when a use of it can still be reached from there, so a block it is not live in is
26//! one that no execution reaching it ever reads the value again. That is what makes a hole safe to
27//! hand to somebody else without splitting anything: whoever gets the register in there is not
28//! borrowing it, and nothing has to be put back afterwards.
29//!
30//! Physical registers in the operands are not in the answer. Nothing writes one before allocation
31//! except an instruction that must, and what a call destroys is a separate question that the ABI
32//! lowering asks, so a pass that reads this is reading about the values the allocator places.
33//!
34//! # How it is computed
35//!
36//! Which values arrive live in each block and which leave live is found one value at a time, by
37//! walking backwards from the blocks that read it through their predecessors until a block that
38//! writes it. Backwards because liveness flows backwards, and a walk rather than one pass over the
39//! blocks because a loop carries a value from the end of a block round to a block in front of it.
40//! The pieces then come from one walk over the instructions, a block at a time.
41//!
42//! What each block arrives holding is kept as the register numbers rather than as a bit each, and
43//! `Rows` in this module says why. The short of it is that a block is live in a handful of values
44//! whatever the function has in it, so a bit per value per block is the size of the function
45//! squared for an answer that is not.
46//!
47//! Inside one block a value's live points are one stretch and never two, because the machine IR is
48//! in SSA form and a value is written once. The stretch runs from the start of the block if the
49//! value arrives live and from where it is written otherwise, and to the end of the block if it
50//! leaves live and to its last read otherwise. Two stretches join into one piece when the blocks
51//! they are in are next to each other in the line, which is what makes a value carried round a loop
52//! one piece over the whole loop rather than one per block in it.
53
54use rucc_mir::{Block, Func, Reg, Role};
55
56use crate::order::{Order, Point};
57
58/// The stretch of the function a value is live over.
59///
60/// Both ends are included: a value written at a point and read at a later one is live at both,
61/// and one written and never read is live where it was written, because the register it was
62/// written to is not free at the instant it was written to. A value written early is written
63/// before the instruction reads its operands and is still written when the instruction is done,
64/// so even one nothing reads covers the whole of the instruction that wrote it.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct Range {
67    /// Where the value is written.
68    pub start: Point,
69    /// The last place it is read, or where it is written if nothing reads it.
70    pub end: Point,
71}
72
73impl Range {
74    /// Whether the value is live at that point.
75    #[must_use]
76    pub fn covers(self, point: Point) -> bool {
77        self.start <= point && point <= self.end
78    }
79
80    /// Whether two values are both live anywhere, which is what stops them sharing a register.
81    #[must_use]
82    pub fn overlaps(self, other: Self) -> bool {
83        self.start <= other.end && other.start <= self.end
84    }
85
86    /// The smallest range covering both, which is how a range grows as more of the function is
87    /// read.
88    fn with(self, point: Point) -> Self {
89        Self { start: self.start.min(point), end: self.end.max(point) }
90    }
91}
92
93/// Everywhere one value is live, which is one or more pieces and at most one more point in front
94/// of the piece that follows it.
95///
96/// That one extra point is the only thing about a live area anybody adjusts. A value a two address
97/// instruction writes into a register it read is really live from where that instruction reads its
98/// operands, which is one point in front of where it is written, and both the allocator and the
99/// checker add that point before asking anything. It is one point rather than a new start because
100/// a value can be live in several pieces and the one to stretch is the piece the instruction
101/// writes, which is not always the first. Reading an area this way only ever makes it bigger, so
102/// it is still an area and every answer below still holds of it.
103#[derive(Debug, Clone, Copy)]
104pub struct Area<'a> {
105    pieces: &'a [Range],
106    also: Option<Point>,
107}
108
109impl<'a> Area<'a> {
110    /// An area over pieces already in order and apart, for a test that wants one without a
111    /// function to work it out from.
112    #[cfg(test)]
113    pub(crate) fn of_pieces(pieces: &'a [Range]) -> Self {
114        Self { pieces, also: None }
115    }
116
117    /// The same area with one more point in it, joined to the piece that starts just after it.
118    ///
119    /// A point already inside a piece changes nothing, which is what a value a loop carries round
120    /// looks like: it is live on the way into the instruction that writes it anyway.
121    #[must_use]
122    pub fn with(self, point: Point) -> Self {
123        Self { also: Some(point), ..self }
124    }
125
126    /// The interval around the whole area, holes and all, which is what a sweep in the order
127    /// values start reads.
128    #[must_use]
129    pub fn hull(self) -> Range {
130        Range { start: self.piece(0).start, end: self.pieces[self.pieces.len() - 1].end }
131    }
132
133    /// Whether the value is live at that point.
134    ///
135    /// The pieces are in order and the extra point only moves a start down to just past the end
136    /// of the piece in front, so the first piece that ends at or after the point is the only one
137    /// that can hold it, and a search finds that one without looking at the rest.
138    #[must_use]
139    pub fn covers(self, point: Point) -> bool {
140        let first = self.pieces.partition_point(|piece| piece.end < point);
141        first < self.pieces.len() && self.piece(first).covers(point)
142    }
143
144    /// Whether two values are both live somewhere, which is what stops them sharing a register.
145    ///
146    /// Both lists are in order and neither is long, so this walks them together and stops at the
147    /// first pair that touches rather than comparing every piece with every other.
148    #[must_use]
149    pub fn overlaps(self, other: Self) -> bool {
150        let (mut mine, mut theirs) = (0, 0);
151        while mine < self.pieces.len() && theirs < other.pieces.len() {
152            let (one, two) = (self.piece(mine), other.piece(theirs));
153            if one.overlaps(two) {
154                return true;
155            }
156            // Whichever stops first cannot reach anything further along the other list.
157            if one.end < two.end {
158                mine += 1;
159            } else {
160                theirs += 1;
161            }
162        }
163        false
164    }
165
166    /// The pieces themselves, in order.
167    pub fn pieces(self) -> impl Iterator<Item = Range> + 'a {
168        (0..self.pieces.len()).map(move |piece| self.piece(piece))
169    }
170
171    /// How many pieces there are.
172    pub(crate) fn count(self) -> usize {
173        self.pieces.len()
174    }
175
176    /// One piece, stretched down over the extra point when that point is the one just in front of
177    /// it.
178    pub(crate) fn piece(self, index: usize) -> Range {
179        let piece = self.pieces[index];
180        match self.also {
181            Some(also) if also + 1 == piece.start => Range { start: also, end: piece.end },
182            _ => piece,
183        }
184    }
185}
186
187/// What is live where.
188#[derive(Debug, Clone)]
189pub struct Live {
190    live_in: Rows,
191    live_out: Rows,
192    /// Every value's pieces end to end, since a vector per value would be a vector per value.
193    pieces: Vec<Range>,
194    /// Where each value's pieces are in that vector, by register number.
195    spans: Vec<(usize, usize)>,
196}
197
198impl Live {
199    /// Works it out for a function laid out in that order.
200    #[must_use]
201    pub fn of(func: &Func, order: &Order) -> Self {
202        let vregs = func.vregs();
203        let (used, defined) = exposed(func, order);
204        let (live_in, live_out) = flow(func, order, &used, &defined);
205        let (pieces, spans) = carve(func, order, &live_in, &live_out, vregs);
206        Self { live_in, live_out, pieces, spans }
207    }
208
209    /// Everywhere a virtual register is live, or `None` for one this function never mentions and
210    /// for a physical register.
211    #[must_use]
212    pub fn area(&self, reg: Reg) -> Option<Area<'_>> {
213        let pieces = self.pieces(reg);
214        if pieces.is_empty() {
215            return None;
216        }
217        Some(Area { pieces, also: None })
218    }
219
220    /// The interval a virtual register is live over, holes and all.
221    #[must_use]
222    pub fn range(&self, reg: Reg) -> Option<Range> {
223        self.area(reg).map(Area::hull)
224    }
225
226    /// Every virtual register that arrives in a block already holding a value.
227    ///
228    /// The block's own parameters are not among them. A parameter is written where it arrives,
229    /// which makes it a value the block defines rather than one it inherits.
230    pub fn live_in(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
231        self.live_in.iter(block.index())
232    }
233
234    /// Every virtual register that is still wanted after a block, which is what its successors
235    /// and the arguments its terminator carries between them ask for.
236    pub fn live_out(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
237        self.live_out.iter(block.index())
238    }
239
240    /// Everywhere a virtual register is live, as it is stored.
241    fn pieces(&self, reg: Reg) -> &[Range] {
242        let number = reg.number().and_then(|number| usize::try_from(number).ok());
243        let Some(&(from, to)) = number.and_then(|number| self.spans.get(number)) else {
244            return &[];
245        };
246        &self.pieces[from..to]
247    }
248}
249
250/// The pieces, from the blocks and from the instructions in them.
251///
252/// One block at a time, because a value's live points inside one block are one stretch and the
253/// whole job is working out where one stretch stops and the next begins. What comes back is every
254/// value's pieces end to end, and where each value's are.
255///
256/// The pieces go into one list as the blocks find them and are sorted by value at the end. They
257/// used to go into a list per value, and on jtckdint, with 190084 instructions in one function,
258/// finding each value's list and growing it a piece at a time was most of working out liveness.
259fn carve(
260    func: &Func,
261    order: &Order,
262    live_in: &Rows,
263    live_out: &Rows,
264    vregs: usize,
265) -> (Vec<Range>, Vec<(usize, usize)>) {
266    // Every piece with whose it is, in the order the blocks come, which for any one value is the
267    // order its pieces start in.
268    let mut found: Vec<(u32, Range)> = Vec::new();
269    // Where each value's last piece is in that list, so that the next block can carry it on.
270    let mut last = vec![u32::MAX; vregs];
271    let mut here: Vec<Option<Range>> = vec![None; vregs];
272    let mut touched: Vec<usize> = Vec::new();
273
274    for &block in order.blocks() {
275        // A block a value arrives in and leaves is one it is live through, whether or not
276        // anything in it says the value's name.
277        for reg in live_in.iter(block.index()) {
278            note(&mut here, &mut touched, reg, order.start(block));
279        }
280        for reg in live_out.iter(block.index()) {
281            note(&mut here, &mut touched, reg, order.end(block));
282        }
283        for param in &func[block].params {
284            note(&mut here, &mut touched, param.reg, order.start(block));
285        }
286        for inst in func.insts(block) {
287            for operand in &func[func[inst].operands] {
288                match operand.role {
289                    Role::Use => note(&mut here, &mut touched, operand.reg, order.early(inst)),
290                    Role::Def => note(&mut here, &mut touched, operand.reg, order.late(inst)),
291                    // A register written early is taken from before the operands are read, which
292                    // is the whole of what makes it different from a plain definition, and it is
293                    // still taken when the instruction is done. Both ends have to be said. Saying
294                    // only the first would leave a value nothing reads live at a point in front of
295                    // everything else the instruction writes, and the register it went to would
296                    // look free to them.
297                    Role::EarlyDef => {
298                        note(&mut here, &mut touched, operand.reg, order.early(inst));
299                        note(&mut here, &mut touched, operand.reg, order.late(inst));
300                    }
301                }
302            }
303        }
304        for call in &func[block].succs {
305            for &arg in &call.args {
306                note(&mut here, &mut touched, arg, order.end(block));
307            }
308        }
309
310        for &number in &touched {
311            let Some(piece) = here[number].take() else { continue };
312            match found.get_mut(last[number] as usize) {
313                // The points run on from one block into the next, so a stretch that begins where
314                // the last one stopped is the same run of blocks carried on. A gap of even one
315                // point means a block in between that the value is not live in.
316                Some((_, previous)) if previous.end + 1 == piece.start => previous.end = piece.end,
317                _ => {
318                    last[number] = u32::try_from(found.len()).expect("a piece number");
319                    found.push((u32::try_from(number).expect("a register number"), piece));
320                }
321            }
322        }
323        touched.clear();
324    }
325
326    // Counted out by value, which keeps each value's pieces in the order they were found.
327    let mut starts = vec![0usize; vregs + 1];
328    for &(number, _) in &found {
329        starts[number as usize + 1] += 1;
330    }
331    for number in 0..vregs {
332        starts[number + 1] += starts[number];
333    }
334    let mut filled = starts.clone();
335    let mut pieces = vec![Range { start: 0, end: 0 }; found.len()];
336    for &(number, piece) in &found {
337        let at = &mut filled[number as usize];
338        pieces[*at] = piece;
339        *at += 1;
340    }
341    let spans = (0..vregs).map(|number| (starts[number], starts[number + 1])).collect();
342    (pieces, spans)
343}
344
345/// Says that a value is live at a point of the block being carved.
346fn note(here: &mut [Option<Range>], touched: &mut Vec<usize>, reg: Reg, point: Point) {
347    let Some(number) = reg.number().and_then(|number| usize::try_from(number).ok()) else {
348        return;
349    };
350    let Some(slot) = here.get_mut(number) else { return };
351    match slot {
352        Some(range) => *range = range.with(point),
353        None => {
354            *slot = Some(Range { start: point, end: point });
355            touched.push(number);
356        }
357    }
358}
359
360/// What each block reads before writing, and what it writes.
361///
362/// The first is read backwards, because a value a block writes and then reads is one it does not
363/// want from anybody, while one it reads and then writes is.
364fn exposed(func: &Func, order: &Order) -> (Rows, Rows) {
365    let vregs = func.vregs();
366    let mut used = Vec::new();
367    let mut defined = Vec::new();
368    let mut reads = Building::new(vregs);
369    let mut writes = Building::new(vregs);
370    for &block in order.blocks() {
371        let row = block.index();
372        for call in &func[block].succs {
373            for &arg in &call.args {
374                reads.insert(arg);
375            }
376        }
377        let insts: Vec<_> = func.insts(block).collect();
378        for &inst in insts.iter().rev() {
379            let operands = &func[func[inst].operands];
380            for operand in operands.iter().filter(|operand| operand.role.is_def()) {
381                reads.remove(operand.reg);
382                writes.insert(operand.reg);
383            }
384            for operand in operands.iter().filter(|operand| !operand.role.is_def()) {
385                reads.insert(operand.reg);
386            }
387        }
388        for param in &func[block].params {
389            reads.remove(param.reg);
390            writes.insert(param.reg);
391        }
392        used.extend(reads.take().into_iter().map(|number| (row_of(row), number)));
393        defined.extend(writes.take().into_iter().map(|number| (row_of(row), number)));
394    }
395    (Rows::gather(func.block_count(), &used), Rows::gather(func.block_count(), &defined))
396}
397
398/// The fixpoint: what arrives live in each block, and what leaves live.
399///
400/// One value at a time rather than one block at a time. A value is live into every block a read of
401/// it can be reached from without passing something that writes it, so starting from the blocks
402/// that read it first and walking back through their predecessors until a block that writes it
403/// finds exactly those, and it visits each block the value is live in once. What that costs is the
404/// size of the answer. The list of blocks it replaced looked at a block again whenever anything
405/// arriving live after it changed and merged whole rows each time, and on jtckdint's function of
406/// 22000 blocks, with a few thousand values live across most of it, that merging was half of the
407/// whole `-O2` compile.
408///
409/// The rows come out in order for free, because the values are walked in the order their numbers
410/// sort in and each is only ever added to the end of a row.
411fn flow(func: &Func, order: &Order, used: &Rows, defined: &Rows) -> (Rows, Rows) {
412    let count = func.block_count();
413    let vregs = func.vregs();
414    let mut preds: Vec<Vec<usize>> = vec![Vec::new(); count];
415    for &block in order.blocks() {
416        for call in &func[block].succs {
417            preds[call.block.index()].push(block.index());
418        }
419    }
420    // The blocks that read each value before writing it, by register number, end to end.
421    let mut starts = vec![0usize; vregs + 1];
422    for &block in order.blocks() {
423        for &number in used.row(block.index()) {
424            starts[number as usize + 1] += 1;
425        }
426    }
427    for number in 0..vregs {
428        starts[number + 1] += starts[number];
429    }
430    let mut readers = vec![0usize; starts[vregs]];
431    let mut filled = starts.clone();
432    for &block in order.blocks() {
433        for &number in used.row(block.index()) {
434            readers[filled[number as usize]] = block.index();
435            filled[number as usize] += 1;
436        }
437    }
438    // And the blocks that write each one, the same way, so that whether a block stops the walk is
439    // a mark made once per value rather than a search of the block's row for every edge crossed.
440    let mut ends = vec![0usize; vregs + 1];
441    for &block in order.blocks() {
442        for &number in defined.row(block.index()) {
443            ends[number as usize + 1] += 1;
444        }
445    }
446    for number in 0..vregs {
447        ends[number + 1] += ends[number];
448    }
449    let mut writers = vec![0usize; ends[vregs]];
450    let mut filled = ends.clone();
451    for &block in order.blocks() {
452        for &number in defined.row(block.index()) {
453            writers[filled[number as usize]] = block.index();
454            filled[number as usize] += 1;
455        }
456    }
457
458    let mut live_in = Vec::new();
459    let mut live_out = Vec::new();
460    // The last value each block was found live into and live out of, which is all a block needs
461    // to remember when the values come one at a time.
462    let mut arrived = vec![u32::MAX; count];
463    let mut left = vec![u32::MAX; count];
464    let mut wrote = vec![u32::MAX; count];
465    let mut waiting = Vec::new();
466    for number in 0..vregs {
467        let value = u32::try_from(number).expect("a register number");
468        for &row in &writers[ends[number]..ends[number + 1]] {
469            wrote[row] = value;
470        }
471        for &row in &readers[starts[number]..starts[number + 1]] {
472            if arrived[row] != value {
473                arrived[row] = value;
474                live_in.push((row_of(row), value));
475                waiting.push(row);
476            }
477        }
478        while let Some(row) = waiting.pop() {
479            for &pred in &preds[row] {
480                if left[pred] != value {
481                    left[pred] = value;
482                    live_out.push((row_of(pred), value));
483                }
484                if arrived[pred] != value && wrote[pred] != value {
485                    arrived[pred] = value;
486                    live_in.push((row_of(pred), value));
487                    waiting.push(pred);
488                }
489            }
490        }
491    }
492    (Rows::transpose(count, &live_in), Rows::transpose(count, &live_out))
493}
494
495/// A set of virtual registers for each block, held as the numbers in it.
496///
497/// A bit per register per block is the obvious way to hold this and is what it was. The trouble is
498/// that a row is then as wide as the function has values however few of them the block is about,
499/// and every step of the fixpoint reads and writes every word of every row. A function with a lot
500/// of values in it has a lot of blocks too, so that is the size of the function squared, in memory
501/// as well as in time: jtckdint from the real corpus has one function with 190084 instructions and
502/// 22000 blocks, and four of these rows came to about two gigabytes of the compiler's footprint,
503/// with the fixpoint over them taking a third of the whole compile at `-O1`.
504///
505/// What is actually true of the answer is that a block is live in a handful of values and not in
506/// the other two hundred thousand, so the numbers themselves are smaller than the bits. They are
507/// kept in the order a register number sorts in rather than any order of the program.
508/// tamnd/rucc#1072.
509///
510/// The rows are one list end to end, laid out once every number is known. They used to be a list
511/// per block that each number was pushed onto as the fixpoint found it, and on jtckdint, with
512/// thousands of values live across most of 22000 blocks, growing those lists one number at a time
513/// and copying them every time one ran out of room was about half of working out liveness.
514#[derive(Debug, Clone)]
515struct Rows {
516    /// Where each row starts in `numbers`, with one more at the end for where the last one stops.
517    starts: Vec<usize>,
518    numbers: Vec<u32>,
519}
520
521impl Rows {
522    /// The rows out of a list of which row each number goes in. The numbers keep the order they
523    /// come in within a row, so a row is in order when the caller hands its numbers over in order.
524    ///
525    /// This is for a list that comes a row at a time, which puts each row's numbers down together.
526    /// One that comes a value at a time wants [`Rows::transpose`].
527    fn gather(rows: usize, pairs: &[(u32, u32)]) -> Self {
528        let (starts, mut filled) = Self::starts(rows, pairs);
529        let mut numbers = vec![0u32; pairs.len()];
530        for &(row, number) in pairs {
531            let at = &mut filled[row as usize];
532            numbers[*at] = number;
533            *at += 1;
534        }
535        Self { starts, numbers }
536    }
537
538    /// The same rows as [`Rows::gather`] makes, out of a list that comes a value at a time.
539    ///
540    /// Putting each number straight into its row writes to every row by turns, and with 22000
541    /// rows that is 22000 places being written at once, far more than stay in the cache, so nearly
542    /// every write missed. So the list is first sorted into at most [`Rows::WAYS`] runs of
543    /// neighbouring rows, and then each run into its rows, which is two passes that each write to
544    /// few enough places at a time to stay in the cache. Both keep the order the pairs came in, so
545    /// the rows are the same.
546    fn transpose(rows: usize, pairs: &[(u32, u32)]) -> Self {
547        let mut shift = 0;
548        while rows > Self::WAYS << shift {
549            shift += 1;
550        }
551        if shift == 0 {
552            return Self::gather(rows, pairs);
553        }
554        let (starts, mut filled) = Self::starts(rows, pairs);
555        // Where each run starts in `runs`, which is where the first row in it starts in `numbers`.
556        let mut next: Vec<usize> =
557            (0..rows.div_ceil(1 << shift)).map(|run| starts[run << shift]).collect();
558        let mut runs = vec![(0u32, 0u32); pairs.len()];
559        for &pair in pairs {
560            let at = &mut next[(pair.0 >> shift) as usize];
561            runs[*at] = pair;
562            *at += 1;
563        }
564        let mut numbers = vec![0u32; pairs.len()];
565        for &(row, number) in &runs {
566            let at = &mut filled[row as usize];
567            numbers[*at] = number;
568            *at += 1;
569        }
570        Self { starts, numbers }
571    }
572
573    /// How many runs of rows [`Rows::transpose`] sorts a list into before the rows themselves.
574    const WAYS: usize = 256;
575
576    /// Where each row starts, with one more at the end for where the last one stops, and a copy
577    /// to count up as the rows are filled.
578    fn starts(rows: usize, pairs: &[(u32, u32)]) -> (Vec<usize>, Vec<usize>) {
579        let mut starts = vec![0usize; rows + 1];
580        for &(row, _) in pairs {
581            starts[row as usize + 1] += 1;
582        }
583        for row in 0..rows {
584            starts[row + 1] += starts[row];
585        }
586        let filled = starts.clone();
587        (starts, filled)
588    }
589
590    fn row(&self, row: usize) -> &[u32] {
591        &self.numbers[self.starts[row]..self.starts[row + 1]]
592    }
593
594    fn iter(&self, row: usize) -> impl Iterator<Item = Reg> + '_ {
595        self.row(row).iter().copied().map(Reg::virtual_reg)
596    }
597}
598
599/// A block's index as the row it is in [`Rows`].
600fn row_of(index: usize) -> u32 {
601    u32::try_from(index).expect("a block number")
602}
603
604/// One block's set while it is being worked out, as a flag per register and a list of which to
605/// look at.
606///
607/// A row is held as the numbers in it, so putting a register into one twice would be a search and
608/// a shift of everything above it, and taking one out again would be another. Here both are a load
609/// and a store. What makes it affordable is the clear: the flags are as many as the function has
610/// values and the blocks are as many as it has blocks, so clearing all of the first for each of
611/// the second would be the cost this whole representation is here to avoid, and instead only what
612/// was set is walked. tamnd/rucc#1072.
613struct Building {
614    flags: Vec<bool>,
615    /// Every number set since the last [`Building::take`], which may name one twice when a
616    /// register was taken out and put back. The take drops the repeat rather than the caller
617    /// having to care.
618    touched: Vec<u32>,
619}
620
621impl Building {
622    fn new(vregs: usize) -> Self {
623        Self { flags: vec![false; vregs], touched: Vec::new() }
624    }
625
626    /// The register's number, or nothing for a physical register, which this does not track, and
627    /// nothing for a number this function has no value at, which cannot happen and is not worth a
628    /// panic if it does.
629    fn number(&self, reg: Reg) -> Option<usize> {
630        let number = usize::try_from(reg.number()?).ok()?;
631        (number < self.flags.len()).then_some(number)
632    }
633
634    fn insert(&mut self, reg: Reg) {
635        let Some(number) = self.number(reg) else { return };
636        if !self.flags[number] {
637            self.flags[number] = true;
638            self.touched.push(u32::try_from(number).expect("a register number"));
639        }
640    }
641
642    fn remove(&mut self, reg: Reg) {
643        if let Some(number) = self.number(reg) {
644            self.flags[number] = false;
645        }
646    }
647
648    /// What is in the set, in order, leaving it empty for the next block.
649    fn take(&mut self) -> Vec<u32> {
650        let flags = &mut self.flags;
651        let mut out: Vec<u32> = self
652            .touched
653            .drain(..)
654            .filter(|&number| std::mem::replace(&mut flags[number as usize], false))
655            .collect();
656        out.sort_unstable();
657        out
658    }
659}
660
661#[cfg(test)]
662mod tests {
663    use rucc_base::Interner;
664    use rucc_mir::{BlockCall, Constraint, Opcode, Operand};
665    use rucc_target::x86_64::GPR;
666
667    use super::*;
668
669    /// The registers live in or out of a block, in order, which is what an assertion reads.
670    fn regs(of: impl Iterator<Item = Reg>) -> Vec<u32> {
671        of.filter_map(Reg::number).collect()
672    }
673
674    #[test]
675    fn a_value_is_live_from_where_it_is_written_to_where_it_is_last_read() {
676        let mut names = Interner::new();
677        let mut func = Func::new(names.intern("f"));
678        let opcode = Opcode::new(names.intern("x64.nop"));
679        let block = func.create_block();
680        let value = func.new_vreg(GPR);
681        let other = func.new_vreg(GPR);
682        let write = func.build(block, opcode).def(value, GPR).finish();
683        let idle = func.build(block, opcode).def(other, GPR).finish();
684        let read = func.build(block, opcode).uses(value, GPR).finish();
685
686        let order = Order::of(&func);
687        let live = Live::of(&func, &order);
688        let range = live.range(value).expect("the value is live somewhere");
689        assert_eq!(range, Range { start: order.late(write), end: order.early(read) });
690        assert!(range.covers(order.early(idle)));
691        // A value nothing reads is live where it was written and nowhere else, because the
692        // register it went to was not free at that instant either.
693        assert_eq!(
694            live.range(other),
695            Some(Range { start: order.late(idle), end: order.late(idle) })
696        );
697        assert!(!range.overlaps(Range { start: order.late(read), end: order.late(read) }));
698        assert_eq!(regs(live.live_in(block)), Vec::<u32>::new());
699    }
700
701    #[test]
702    fn a_value_read_in_another_block_is_live_between_them() {
703        let mut names = Interner::new();
704        let mut func = Func::new(names.intern("f"));
705        let opcode = Opcode::new(names.intern("x64.nop"));
706        let head = func.create_block();
707        let middle = func.create_block();
708        let tail = func.create_block();
709        let value = func.new_vreg(GPR);
710        func.build(head, opcode).def(value, GPR).finish();
711        *func.succs_mut(head) = vec![BlockCall::to(middle)];
712        *func.succs_mut(middle) = vec![BlockCall::to(tail)];
713        let read = func.build(tail, opcode).uses(value, GPR).finish();
714
715        let order = Order::of(&func);
716        let live = Live::of(&func, &order);
717        // The block in between never mentions it and it is live all the way through, which is
718        // the whole reason this walks the blocks and not only the code that names it.
719        assert_eq!(regs(live.live_in(middle)), vec![0]);
720        assert_eq!(regs(live.live_out(middle)), vec![0]);
721        assert!(live.range(value).expect("live somewhere").covers(order.start(middle)));
722        assert_eq!(live.range(value).expect("live somewhere").end, order.early(read));
723    }
724
725    #[test]
726    fn a_block_the_value_never_reaches_is_a_hole_between_two_pieces() {
727        let mut names = Interner::new();
728        let mut func = Func::new(names.intern("f"));
729        let opcode = Opcode::new(names.intern("x64.nop"));
730        let entry = func.create_block();
731        let arm = func.create_block();
732        let tail = func.create_block();
733        let value = func.new_vreg(GPR);
734        let write = func.build(entry, opcode).def(value, GPR).finish();
735        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
736        let idle = func.build(arm, opcode).finish();
737        let read = func.build(tail, opcode).uses(value, GPR).finish();
738
739        let order = Order::of(&func);
740        let live = Live::of(&func, &order);
741        let area = live.area(value).expect("live somewhere");
742        // The arm is written between the two blocks the value is live in, so the interval around
743        // it covers the arm and the pieces do not. Both are true and they answer different
744        // questions, and it is the pieces that decide who may have a register.
745        assert!(live.range(value).expect("live somewhere").covers(order.early(idle)));
746        assert!(!area.covers(order.early(idle)));
747        assert_eq!(
748            area.pieces().collect::<Vec<_>>(),
749            vec![
750                Range { start: order.late(write), end: order.end(entry) },
751                Range { start: order.start(tail), end: order.early(read) },
752            ]
753        );
754    }
755
756    #[test]
757    fn a_value_in_a_hole_of_another_may_have_its_register() {
758        let mut names = Interner::new();
759        let mut func = Func::new(names.intern("f"));
760        let opcode = Opcode::new(names.intern("x64.nop"));
761        let entry = func.create_block();
762        let arm = func.create_block();
763        let tail = func.create_block();
764        let value = func.new_vreg(GPR);
765        let inside = func.new_vreg(GPR);
766        func.build(entry, opcode).def(value, GPR).finish();
767        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
768        func.build(arm, opcode).def(inside, GPR).finish();
769        func.build(arm, opcode).uses(inside, GPR).finish();
770        func.build(tail, opcode).uses(value, GPR).finish();
771
772        let order = Order::of(&func);
773        let live = Live::of(&func, &order);
774        let value = live.area(value).expect("live somewhere");
775        let inside = live.area(inside).expect("live somewhere");
776        // Nothing in the arm can reach the read in the tail, so whichever register the first value
777        // is in is a register the arm may take for as long as it likes. The intervals say the two
778        // are on top of each other and they are not.
779        assert!(value.hull().overlaps(inside.hull()));
780        assert!(!value.overlaps(inside));
781        assert!(!inside.overlaps(value));
782    }
783
784    #[test]
785    fn one_point_added_in_front_of_a_piece_is_part_of_the_area() {
786        let mut names = Interner::new();
787        let mut func = Func::new(names.intern("f"));
788        let opcode = Opcode::new(names.intern("x64.nop"));
789        let block = func.create_block();
790        let first = func.new_vreg(GPR);
791        let second = func.new_vreg(GPR);
792        let write = func.build(block, opcode).def(first, GPR).finish();
793        let both = func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
794
795        let order = Order::of(&func);
796        let live = Live::of(&func, &order);
797        let first = live.area(first).expect("live somewhere");
798        let second = live.area(second).expect("live somewhere");
799        // A two address instruction writes its answer into the register it read, so the answer is
800        // really in that register from the moment the instruction starts. Read that way the two
801        // values are on top of each other, and read the plain way they are not, which is the whole
802        // reason the extra point is the caller's to add.
803        assert!(!first.overlaps(second));
804        assert!(first.overlaps(second.with(order.early(both))));
805        assert!(second.with(order.early(both)).covers(order.early(both)));
806        assert_eq!(second.with(order.early(both)).hull().start, order.early(both));
807        assert_eq!(first.hull().start, order.late(write));
808    }
809
810    #[test]
811    fn the_point_added_in_front_joins_the_piece_it_belongs_to_and_not_the_first_one() {
812        let mut names = Interner::new();
813        let mut func = Func::new(names.intern("f"));
814        let nop = Opcode::new(names.intern("x64.nop"));
815        let add = Opcode::new(names.intern("x64.add"));
816        let entry = func.create_block();
817        let head = func.create_block();
818        let arm = func.create_block();
819        let latch = func.create_block();
820        let out = func.create_block();
821        let seed = func.new_vreg(GPR);
822        let sum = func.new_vreg(GPR);
823        let inside = func.new_vreg(GPR);
824        let loaded = func.new_vreg(GPR);
825        func.build(entry, nop).def(seed, GPR).finish();
826        func.build(entry, nop).def(sum, GPR).finish();
827        *func.succs_mut(entry) = vec![BlockCall::to(head)];
828        func.build(head, nop).uses(sum, GPR).finish();
829        *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
830        func.build(arm, nop).def(inside, GPR).finish();
831        func.build(arm, nop).uses(inside, GPR).finish();
832        *func.succs_mut(arm) = vec![BlockCall::to(out)];
833        func.build(latch, nop).def(loaded, GPR).finish();
834        let carry = func
835            .build(latch, add)
836            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
837            .uses(seed, GPR)
838            .uses(loaded, GPR)
839            .finish();
840        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
841
842        let order = Order::of(&func);
843        let live = Live::of(&func, &order);
844        let sum = live.area(sum).expect("live somewhere");
845        let loaded = live.area(loaded).expect("live somewhere");
846        // The answer is live in the entry and the head as well, which the arm is a hole in, so the
847        // piece the addition writes is the second one. Adding the point in front of the first piece
848        // instead would leave the addition reading a register the answer is about to be written to
849        // and nothing saying the two are on top of each other. tamnd/rucc#982.
850        assert_eq!(sum.pieces().count(), 2);
851        assert!(!sum.covers(order.early(carry)));
852        assert!(sum.with(order.early(carry)).covers(order.early(carry)));
853        assert!(!loaded.overlaps(sum));
854        assert!(loaded.overlaps(sum.with(order.early(carry))));
855    }
856
857    #[test]
858    fn a_value_carried_round_a_loop_is_live_round_all_of_it() {
859        let mut names = Interner::new();
860        let mut func = Func::new(names.intern("f"));
861        let opcode = Opcode::new(names.intern("x64.nop"));
862        let header = func.create_block();
863        let body = func.create_block();
864        let carried = func.append_param(header, GPR);
865        let next = func.new_vreg(GPR);
866        *func.succs_mut(header) = vec![BlockCall::to(body)];
867        func.build(body, opcode).def(next, GPR).uses(carried, GPR).finish();
868        *func.succs_mut(body) = vec![BlockCall::with(header, vec![next])];
869
870        let order = Order::of(&func);
871        let live = Live::of(&func, &order);
872        // The parameter arrives in the header, so the header does not want it from anybody, and
873        // the body does.
874        assert_eq!(regs(live.live_in(header)), Vec::<u32>::new());
875        assert_eq!(regs(live.live_in(body)), vec![carried.number().expect("virtual")]);
876        let range = live.range(next).expect("live somewhere");
877        assert_eq!(range.end, order.end(body));
878    }
879
880    #[test]
881    fn two_values_that_are_never_both_wanted_do_not_overlap() {
882        let mut names = Interner::new();
883        let mut func = Func::new(names.intern("f"));
884        let opcode = Opcode::new(names.intern("x64.nop"));
885        let block = func.create_block();
886        let first = func.new_vreg(GPR);
887        let second = func.new_vreg(GPR);
888        let write = func.build(block, opcode).def(first, GPR).finish();
889        func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
890
891        let order = Order::of(&func);
892        let live = Live::of(&func, &order);
893        let first = live.range(first).expect("live somewhere");
894        let second = live.range(second).expect("live somewhere");
895        // The second instruction reads the first value and writes its own, and it reads before
896        // it writes, so the two can be the same register. That is what a two address instruction
897        // needs to be true and it is a fact about the points rather than about the opcode.
898        assert!(!first.overlaps(second));
899        assert!(first.start > order.start(block));
900        assert_eq!(first.start, order.late(write));
901    }
902
903    #[test]
904    fn an_operand_written_early_is_wanted_where_the_operands_are_read() {
905        let mut names = Interner::new();
906        let mut func = Func::new(names.intern("f"));
907        let opcode = Opcode::new(names.intern("x64.nop"));
908        let block = func.create_block();
909        let source = func.new_vreg(GPR);
910        let early = func.new_vreg(GPR);
911        func.build(block, opcode).def(source, GPR).finish();
912        func.build(block, opcode)
913            .operand(Operand::write_early(early, GPR))
914            .operand(Operand::read(source, GPR))
915            .finish();
916
917        let order = Order::of(&func);
918        let live = Live::of(&func, &order);
919        let source = live.range(source).expect("live somewhere");
920        let early = live.range(early).expect("live somewhere");
921        // This is the difference between a division and an addition. The register the answer is
922        // going to is destroyed before the divisor is read, so the divisor may not be in it.
923        assert!(source.overlaps(early));
924    }
925
926    #[test]
927    fn a_register_a_memory_operand_names_is_read_like_any_other() {
928        use rucc_mir::Mem;
929
930        let mut names = Interner::new();
931        let mut func = Func::new(names.intern("f"));
932        let opcode = Opcode::new(names.intern("x64.nop"));
933        let block = func.create_block();
934        let address = func.new_vreg(GPR);
935        let write = func.build(block, opcode).def(address, GPR).finish();
936        let load = func.build(block, opcode).mem(Mem::at(Operand::read(address, GPR))).finish();
937
938        let order = Order::of(&func);
939        let live = Live::of(&func, &order);
940        assert_eq!(
941            live.range(address),
942            Some(Range { start: order.late(write), end: order.early(load) })
943        );
944    }
945
946    #[test]
947    fn rows_from_a_list_a_value_at_a_time_over_many_blocks_keep_the_order_the_numbers_came_in() {
948        // Far more rows than one pass of runs covers, so the list goes through both passes, and
949        // pairs that jump about the way the fixpoint's do.
950        let rows = 3000;
951        let mut pairs = Vec::new();
952        let mut seed = 7u32;
953        for number in 0..400 {
954            for _ in 0..30 {
955                seed = seed.wrapping_mul(1_103_515_245).wrapping_add(12345);
956                pairs.push(((seed >> 8) % 3000, number));
957            }
958        }
959        let gathered = Rows::transpose(rows, &pairs);
960        for row in 0..rows {
961            let wanted: Vec<u32> = pairs
962                .iter()
963                .filter(|&&(at, _)| at as usize == row)
964                .map(|&(_, number)| number)
965                .collect();
966            assert_eq!(gathered.row(row), wanted, "row {row}");
967        }
968    }
969}