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    /// The same area with one more point in it, joined to the piece that starts just after it.
111    ///
112    /// A point already inside a piece changes nothing, which is what a value a loop carries round
113    /// looks like: it is live on the way into the instruction that writes it anyway.
114    #[must_use]
115    pub fn with(self, point: Point) -> Self {
116        Self { also: Some(point), ..self }
117    }
118
119    /// The interval around the whole area, holes and all, which is what a sweep in the order
120    /// values start reads.
121    #[must_use]
122    pub fn hull(self) -> Range {
123        Range { start: self.piece(0).start, end: self.pieces[self.pieces.len() - 1].end }
124    }
125
126    /// Whether the value is live at that point.
127    #[must_use]
128    pub fn covers(self, point: Point) -> bool {
129        (0..self.pieces.len()).any(|piece| self.piece(piece).covers(point))
130    }
131
132    /// Whether two values are both live somewhere, which is what stops them sharing a register.
133    ///
134    /// Both lists are in order and neither is long, so this walks them together and stops at the
135    /// first pair that touches rather than comparing every piece with every other.
136    #[must_use]
137    pub fn overlaps(self, other: Self) -> bool {
138        let (mut mine, mut theirs) = (0, 0);
139        while mine < self.pieces.len() && theirs < other.pieces.len() {
140            let (one, two) = (self.piece(mine), other.piece(theirs));
141            if one.overlaps(two) {
142                return true;
143            }
144            // Whichever stops first cannot reach anything further along the other list.
145            if one.end < two.end {
146                mine += 1;
147            } else {
148                theirs += 1;
149            }
150        }
151        false
152    }
153
154    /// The pieces themselves, in order.
155    pub fn pieces(self) -> impl Iterator<Item = Range> + 'a {
156        (0..self.pieces.len()).map(move |piece| self.piece(piece))
157    }
158
159    /// One piece, stretched down over the extra point when that point is the one just in front of
160    /// it.
161    fn piece(self, index: usize) -> Range {
162        let piece = self.pieces[index];
163        match self.also {
164            Some(also) if also + 1 == piece.start => Range { start: also, end: piece.end },
165            _ => piece,
166        }
167    }
168}
169
170/// What is live where.
171#[derive(Debug, Clone)]
172pub struct Live {
173    live_in: Rows,
174    live_out: Rows,
175    /// Every value's pieces end to end, since a vector per value would be a vector per value.
176    pieces: Vec<Range>,
177    /// Where each value's pieces are in that vector, by register number.
178    spans: Vec<(usize, usize)>,
179}
180
181impl Live {
182    /// Works it out for a function laid out in that order.
183    #[must_use]
184    pub fn of(func: &Func, order: &Order) -> Self {
185        let vregs = func.vregs();
186        let (used, defined) = exposed(func, order);
187        let (live_in, live_out) = flow(func, order, &used, &defined);
188        let (pieces, spans) = carve(func, order, &live_in, &live_out, vregs);
189        Self { live_in, live_out, pieces, spans }
190    }
191
192    /// Everywhere a virtual register is live, or `None` for one this function never mentions and
193    /// for a physical register.
194    #[must_use]
195    pub fn area(&self, reg: Reg) -> Option<Area<'_>> {
196        let pieces = self.pieces(reg);
197        if pieces.is_empty() {
198            return None;
199        }
200        Some(Area { pieces, also: None })
201    }
202
203    /// The interval a virtual register is live over, holes and all.
204    #[must_use]
205    pub fn range(&self, reg: Reg) -> Option<Range> {
206        self.area(reg).map(Area::hull)
207    }
208
209    /// Every virtual register that arrives in a block already holding a value.
210    ///
211    /// The block's own parameters are not among them. A parameter is written where it arrives,
212    /// which makes it a value the block defines rather than one it inherits.
213    pub fn live_in(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
214        self.live_in.iter(block.index())
215    }
216
217    /// Every virtual register that is still wanted after a block, which is what its successors
218    /// and the arguments its terminator carries between them ask for.
219    pub fn live_out(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
220        self.live_out.iter(block.index())
221    }
222
223    /// Everywhere a virtual register is live, as it is stored.
224    fn pieces(&self, reg: Reg) -> &[Range] {
225        let number = reg.number().and_then(|number| usize::try_from(number).ok());
226        let Some(&(from, to)) = number.and_then(|number| self.spans.get(number)) else {
227            return &[];
228        };
229        &self.pieces[from..to]
230    }
231}
232
233/// The pieces, from the blocks and from the instructions in them.
234///
235/// One block at a time, because a value's live points inside one block are one stretch and the
236/// whole job is working out where one stretch stops and the next begins. What comes back is every
237/// value's pieces end to end, and where each value's are.
238fn carve(
239    func: &Func,
240    order: &Order,
241    live_in: &Rows,
242    live_out: &Rows,
243    vregs: usize,
244) -> (Vec<Range>, Vec<(usize, usize)>) {
245    let mut lists: Vec<Vec<Range>> = vec![Vec::new(); vregs];
246    let mut here: Vec<Option<Range>> = vec![None; vregs];
247    let mut touched: Vec<usize> = Vec::new();
248
249    for &block in order.blocks() {
250        // A block a value arrives in and leaves is one it is live through, whether or not
251        // anything in it says the value's name.
252        for reg in live_in.iter(block.index()) {
253            note(&mut here, &mut touched, reg, order.start(block));
254        }
255        for reg in live_out.iter(block.index()) {
256            note(&mut here, &mut touched, reg, order.end(block));
257        }
258        for param in &func[block].params {
259            note(&mut here, &mut touched, param.reg, order.start(block));
260        }
261        for inst in func.insts(block) {
262            for operand in &func[func[inst].operands] {
263                match operand.role {
264                    Role::Use => note(&mut here, &mut touched, operand.reg, order.early(inst)),
265                    Role::Def => note(&mut here, &mut touched, operand.reg, order.late(inst)),
266                    // A register written early is taken from before the operands are read, which
267                    // is the whole of what makes it different from a plain definition, and it is
268                    // still taken when the instruction is done. Both ends have to be said. Saying
269                    // only the first would leave a value nothing reads live at a point in front of
270                    // everything else the instruction writes, and the register it went to would
271                    // look free to them.
272                    Role::EarlyDef => {
273                        note(&mut here, &mut touched, operand.reg, order.early(inst));
274                        note(&mut here, &mut touched, operand.reg, order.late(inst));
275                    }
276                }
277            }
278        }
279        for call in &func[block].succs {
280            for &arg in &call.args {
281                note(&mut here, &mut touched, arg, order.end(block));
282            }
283        }
284
285        for &number in &touched {
286            let Some(piece) = here[number].take() else { continue };
287            match lists[number].last_mut() {
288                // The points run on from one block into the next, so a stretch that begins where
289                // the last one stopped is the same run of blocks carried on. A gap of even one
290                // point means a block in between that the value is not live in.
291                Some(last) if last.end + 1 == piece.start => last.end = piece.end,
292                _ => lists[number].push(piece),
293            }
294        }
295        touched.clear();
296    }
297
298    let mut pieces = Vec::new();
299    let mut spans = Vec::with_capacity(vregs);
300    for list in &lists {
301        let from = pieces.len();
302        pieces.extend_from_slice(list);
303        spans.push((from, pieces.len()));
304    }
305    (pieces, spans)
306}
307
308/// Says that a value is live at a point of the block being carved.
309fn note(here: &mut [Option<Range>], touched: &mut Vec<usize>, reg: Reg, point: Point) {
310    let Some(number) = reg.number().and_then(|number| usize::try_from(number).ok()) else {
311        return;
312    };
313    let Some(slot) = here.get_mut(number) else { return };
314    match slot {
315        Some(range) => *range = range.with(point),
316        None => {
317            *slot = Some(Range { start: point, end: point });
318            touched.push(number);
319        }
320    }
321}
322
323/// What each block reads before writing, and what it writes.
324///
325/// The first is read backwards, because a value a block writes and then reads is one it does not
326/// want from anybody, while one it reads and then writes is.
327fn exposed(func: &Func, order: &Order) -> (Rows, Rows) {
328    let vregs = func.vregs();
329    let mut used = Rows::new(func.block_count());
330    let mut defined = Rows::new(func.block_count());
331    let mut reads = Building::new(vregs);
332    let mut writes = Building::new(vregs);
333    for &block in order.blocks() {
334        let row = block.index();
335        for call in &func[block].succs {
336            for &arg in &call.args {
337                reads.insert(arg);
338            }
339        }
340        let insts: Vec<_> = func.insts(block).collect();
341        for &inst in insts.iter().rev() {
342            let operands = &func[func[inst].operands];
343            for operand in operands.iter().filter(|operand| operand.role.is_def()) {
344                reads.remove(operand.reg);
345                writes.insert(operand.reg);
346            }
347            for operand in operands.iter().filter(|operand| !operand.role.is_def()) {
348                reads.insert(operand.reg);
349            }
350        }
351        for param in &func[block].params {
352            reads.remove(param.reg);
353            writes.insert(param.reg);
354        }
355        used.set(row, &reads.take());
356        defined.set(row, &writes.take());
357    }
358    (used, defined)
359}
360
361/// The fixpoint: what arrives live in each block, and what leaves live.
362///
363/// One value at a time rather than one block at a time. A value is live into every block a read of
364/// it can be reached from without passing something that writes it, so starting from the blocks
365/// that read it first and walking back through their predecessors until a block that writes it
366/// finds exactly those, and it visits each block the value is live in once. What that costs is the
367/// size of the answer. The list of blocks it replaced looked at a block again whenever anything
368/// arriving live after it changed and merged whole rows each time, and on jtckdint's function of
369/// 22000 blocks, with a few thousand values live across most of it, that merging was half of the
370/// whole `-O2` compile.
371///
372/// The rows come out in order for free, because the values are walked in the order their numbers
373/// sort in and each is only ever added to the end of a row.
374fn flow(func: &Func, order: &Order, used: &Rows, defined: &Rows) -> (Rows, Rows) {
375    let count = func.block_count();
376    let vregs = func.vregs();
377    let mut preds: Vec<Vec<usize>> = vec![Vec::new(); count];
378    for &block in order.blocks() {
379        for call in &func[block].succs {
380            preds[call.block.index()].push(block.index());
381        }
382    }
383    // The blocks that read each value before writing it, by register number, end to end.
384    let mut starts = vec![0usize; vregs + 1];
385    for &block in order.blocks() {
386        for &number in used.row(block.index()) {
387            starts[number as usize + 1] += 1;
388        }
389    }
390    for number in 0..vregs {
391        starts[number + 1] += starts[number];
392    }
393    let mut readers = vec![0usize; starts[vregs]];
394    let mut filled = starts.clone();
395    for &block in order.blocks() {
396        for &number in used.row(block.index()) {
397            readers[filled[number as usize]] = block.index();
398            filled[number as usize] += 1;
399        }
400    }
401    // And the blocks that write each one, the same way, so that whether a block stops the walk is
402    // a mark made once per value rather than a search of the block's row for every edge crossed.
403    let mut ends = vec![0usize; vregs + 1];
404    for &block in order.blocks() {
405        for &number in defined.row(block.index()) {
406            ends[number as usize + 1] += 1;
407        }
408    }
409    for number in 0..vregs {
410        ends[number + 1] += ends[number];
411    }
412    let mut writers = vec![0usize; ends[vregs]];
413    let mut filled = ends.clone();
414    for &block in order.blocks() {
415        for &number in defined.row(block.index()) {
416            writers[filled[number as usize]] = block.index();
417            filled[number as usize] += 1;
418        }
419    }
420
421    let mut live_in = Rows::new(count);
422    let mut live_out = Rows::new(count);
423    // The last value each block was found live into and live out of, which is all a block needs
424    // to remember when the values come one at a time.
425    let mut arrived = vec![u32::MAX; count];
426    let mut left = vec![u32::MAX; count];
427    let mut wrote = vec![u32::MAX; count];
428    let mut waiting = Vec::new();
429    for number in 0..vregs {
430        let value = u32::try_from(number).expect("a register number");
431        for &row in &writers[ends[number]..ends[number + 1]] {
432            wrote[row] = value;
433        }
434        for &row in &readers[starts[number]..starts[number + 1]] {
435            if arrived[row] != value {
436                arrived[row] = value;
437                live_in.push(row, value);
438                waiting.push(row);
439            }
440        }
441        while let Some(row) = waiting.pop() {
442            for &pred in &preds[row] {
443                if left[pred] != value {
444                    left[pred] = value;
445                    live_out.push(pred, value);
446                }
447                if arrived[pred] != value && wrote[pred] != value {
448                    arrived[pred] = value;
449                    live_in.push(pred, value);
450                    waiting.push(pred);
451                }
452            }
453        }
454    }
455    (live_in, live_out)
456}
457
458/// A set of virtual registers for each block, held as the numbers in it.
459///
460/// A bit per register per block is the obvious way to hold this and is what it was. The trouble is
461/// that a row is then as wide as the function has values however few of them the block is about,
462/// and every step of the fixpoint reads and writes every word of every row. A function with a lot
463/// of values in it has a lot of blocks too, so that is the size of the function squared, in memory
464/// as well as in time: jtckdint from the real corpus has one function with 190084 instructions and
465/// 22000 blocks, and four of these rows came to about two gigabytes of the compiler's footprint,
466/// with the fixpoint over them taking a third of the whole compile at `-O1`.
467///
468/// What is actually true of the answer is that a block is live in a handful of values and not in
469/// the other two hundred thousand, so the numbers themselves are smaller than the bits. They are
470/// kept in the order a register number sorts in rather than any order of the program.
471/// tamnd/rucc#1072.
472#[derive(Debug, Clone)]
473struct Rows {
474    rows: Vec<Vec<u32>>,
475}
476
477impl Rows {
478    fn new(rows: usize) -> Self {
479        Self { rows: vec![Vec::new(); rows] }
480    }
481
482    fn row(&self, row: usize) -> &[u32] {
483        &self.rows[row]
484    }
485
486    /// Puts the numbers in the row in place of whatever it had.
487    fn set(&mut self, row: usize, numbers: &[u32]) {
488        let row = &mut self.rows[row];
489        row.clear();
490        row.extend_from_slice(numbers);
491    }
492
493    /// Adds a number past everything the row has, which keeps it in order only because the caller
494    /// adds them in order.
495    fn push(&mut self, row: usize, number: u32) {
496        self.rows[row].push(number);
497    }
498
499    fn iter(&self, row: usize) -> impl Iterator<Item = Reg> + '_ {
500        self.rows[row].iter().copied().map(Reg::virtual_reg)
501    }
502}
503
504/// One block's set while it is being worked out, as a flag per register and a list of which to
505/// look at.
506///
507/// A row is held as the numbers in it, so putting a register into one twice would be a search and
508/// a shift of everything above it, and taking one out again would be another. Here both are a load
509/// and a store. What makes it affordable is the clear: the flags are as many as the function has
510/// values and the blocks are as many as it has blocks, so clearing all of the first for each of
511/// the second would be the cost this whole representation is here to avoid, and instead only what
512/// was set is walked. tamnd/rucc#1072.
513struct Building {
514    flags: Vec<bool>,
515    /// Every number set since the last [`Building::take`], which may name one twice when a
516    /// register was taken out and put back. The take drops the repeat rather than the caller
517    /// having to care.
518    touched: Vec<u32>,
519}
520
521impl Building {
522    fn new(vregs: usize) -> Self {
523        Self { flags: vec![false; vregs], touched: Vec::new() }
524    }
525
526    /// The register's number, or nothing for a physical register, which this does not track, and
527    /// nothing for a number this function has no value at, which cannot happen and is not worth a
528    /// panic if it does.
529    fn number(&self, reg: Reg) -> Option<usize> {
530        let number = usize::try_from(reg.number()?).ok()?;
531        (number < self.flags.len()).then_some(number)
532    }
533
534    fn insert(&mut self, reg: Reg) {
535        let Some(number) = self.number(reg) else { return };
536        if !self.flags[number] {
537            self.flags[number] = true;
538            self.touched.push(u32::try_from(number).expect("a register number"));
539        }
540    }
541
542    fn remove(&mut self, reg: Reg) {
543        if let Some(number) = self.number(reg) {
544            self.flags[number] = false;
545        }
546    }
547
548    /// What is in the set, in order, leaving it empty for the next block.
549    fn take(&mut self) -> Vec<u32> {
550        let flags = &mut self.flags;
551        let mut out: Vec<u32> = self
552            .touched
553            .drain(..)
554            .filter(|&number| std::mem::replace(&mut flags[number as usize], false))
555            .collect();
556        out.sort_unstable();
557        out
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use rucc_base::Interner;
564    use rucc_mir::{BlockCall, Constraint, Opcode, Operand};
565    use rucc_target::x86_64::GPR;
566
567    use super::*;
568
569    /// The registers live in or out of a block, in order, which is what an assertion reads.
570    fn regs(of: impl Iterator<Item = Reg>) -> Vec<u32> {
571        of.filter_map(Reg::number).collect()
572    }
573
574    #[test]
575    fn a_value_is_live_from_where_it_is_written_to_where_it_is_last_read() {
576        let mut names = Interner::new();
577        let mut func = Func::new(names.intern("f"));
578        let opcode = Opcode::new(names.intern("x64.nop"));
579        let block = func.create_block();
580        let value = func.new_vreg(GPR);
581        let other = func.new_vreg(GPR);
582        let write = func.build(block, opcode).def(value, GPR).finish();
583        let idle = func.build(block, opcode).def(other, GPR).finish();
584        let read = func.build(block, opcode).uses(value, GPR).finish();
585
586        let order = Order::of(&func);
587        let live = Live::of(&func, &order);
588        let range = live.range(value).expect("the value is live somewhere");
589        assert_eq!(range, Range { start: order.late(write), end: order.early(read) });
590        assert!(range.covers(order.early(idle)));
591        // A value nothing reads is live where it was written and nowhere else, because the
592        // register it went to was not free at that instant either.
593        assert_eq!(
594            live.range(other),
595            Some(Range { start: order.late(idle), end: order.late(idle) })
596        );
597        assert!(!range.overlaps(Range { start: order.late(read), end: order.late(read) }));
598        assert_eq!(regs(live.live_in(block)), Vec::<u32>::new());
599    }
600
601    #[test]
602    fn a_value_read_in_another_block_is_live_between_them() {
603        let mut names = Interner::new();
604        let mut func = Func::new(names.intern("f"));
605        let opcode = Opcode::new(names.intern("x64.nop"));
606        let head = func.create_block();
607        let middle = func.create_block();
608        let tail = func.create_block();
609        let value = func.new_vreg(GPR);
610        func.build(head, opcode).def(value, GPR).finish();
611        *func.succs_mut(head) = vec![BlockCall::to(middle)];
612        *func.succs_mut(middle) = vec![BlockCall::to(tail)];
613        let read = func.build(tail, opcode).uses(value, GPR).finish();
614
615        let order = Order::of(&func);
616        let live = Live::of(&func, &order);
617        // The block in between never mentions it and it is live all the way through, which is
618        // the whole reason this walks the blocks and not only the code that names it.
619        assert_eq!(regs(live.live_in(middle)), vec![0]);
620        assert_eq!(regs(live.live_out(middle)), vec![0]);
621        assert!(live.range(value).expect("live somewhere").covers(order.start(middle)));
622        assert_eq!(live.range(value).expect("live somewhere").end, order.early(read));
623    }
624
625    #[test]
626    fn a_block_the_value_never_reaches_is_a_hole_between_two_pieces() {
627        let mut names = Interner::new();
628        let mut func = Func::new(names.intern("f"));
629        let opcode = Opcode::new(names.intern("x64.nop"));
630        let entry = func.create_block();
631        let arm = func.create_block();
632        let tail = func.create_block();
633        let value = func.new_vreg(GPR);
634        let write = func.build(entry, opcode).def(value, GPR).finish();
635        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
636        let idle = func.build(arm, opcode).finish();
637        let read = func.build(tail, opcode).uses(value, GPR).finish();
638
639        let order = Order::of(&func);
640        let live = Live::of(&func, &order);
641        let area = live.area(value).expect("live somewhere");
642        // The arm is written between the two blocks the value is live in, so the interval around
643        // it covers the arm and the pieces do not. Both are true and they answer different
644        // questions, and it is the pieces that decide who may have a register.
645        assert!(live.range(value).expect("live somewhere").covers(order.early(idle)));
646        assert!(!area.covers(order.early(idle)));
647        assert_eq!(
648            area.pieces().collect::<Vec<_>>(),
649            vec![
650                Range { start: order.late(write), end: order.end(entry) },
651                Range { start: order.start(tail), end: order.early(read) },
652            ]
653        );
654    }
655
656    #[test]
657    fn a_value_in_a_hole_of_another_may_have_its_register() {
658        let mut names = Interner::new();
659        let mut func = Func::new(names.intern("f"));
660        let opcode = Opcode::new(names.intern("x64.nop"));
661        let entry = func.create_block();
662        let arm = func.create_block();
663        let tail = func.create_block();
664        let value = func.new_vreg(GPR);
665        let inside = func.new_vreg(GPR);
666        func.build(entry, opcode).def(value, GPR).finish();
667        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
668        func.build(arm, opcode).def(inside, GPR).finish();
669        func.build(arm, opcode).uses(inside, GPR).finish();
670        func.build(tail, opcode).uses(value, GPR).finish();
671
672        let order = Order::of(&func);
673        let live = Live::of(&func, &order);
674        let value = live.area(value).expect("live somewhere");
675        let inside = live.area(inside).expect("live somewhere");
676        // Nothing in the arm can reach the read in the tail, so whichever register the first value
677        // is in is a register the arm may take for as long as it likes. The intervals say the two
678        // are on top of each other and they are not.
679        assert!(value.hull().overlaps(inside.hull()));
680        assert!(!value.overlaps(inside));
681        assert!(!inside.overlaps(value));
682    }
683
684    #[test]
685    fn one_point_added_in_front_of_a_piece_is_part_of_the_area() {
686        let mut names = Interner::new();
687        let mut func = Func::new(names.intern("f"));
688        let opcode = Opcode::new(names.intern("x64.nop"));
689        let block = func.create_block();
690        let first = func.new_vreg(GPR);
691        let second = func.new_vreg(GPR);
692        let write = func.build(block, opcode).def(first, GPR).finish();
693        let both = func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
694
695        let order = Order::of(&func);
696        let live = Live::of(&func, &order);
697        let first = live.area(first).expect("live somewhere");
698        let second = live.area(second).expect("live somewhere");
699        // A two address instruction writes its answer into the register it read, so the answer is
700        // really in that register from the moment the instruction starts. Read that way the two
701        // values are on top of each other, and read the plain way they are not, which is the whole
702        // reason the extra point is the caller's to add.
703        assert!(!first.overlaps(second));
704        assert!(first.overlaps(second.with(order.early(both))));
705        assert!(second.with(order.early(both)).covers(order.early(both)));
706        assert_eq!(second.with(order.early(both)).hull().start, order.early(both));
707        assert_eq!(first.hull().start, order.late(write));
708    }
709
710    #[test]
711    fn the_point_added_in_front_joins_the_piece_it_belongs_to_and_not_the_first_one() {
712        let mut names = Interner::new();
713        let mut func = Func::new(names.intern("f"));
714        let nop = Opcode::new(names.intern("x64.nop"));
715        let add = Opcode::new(names.intern("x64.add"));
716        let entry = func.create_block();
717        let head = func.create_block();
718        let arm = func.create_block();
719        let latch = func.create_block();
720        let out = func.create_block();
721        let seed = func.new_vreg(GPR);
722        let sum = func.new_vreg(GPR);
723        let inside = func.new_vreg(GPR);
724        let loaded = func.new_vreg(GPR);
725        func.build(entry, nop).def(seed, GPR).finish();
726        func.build(entry, nop).def(sum, GPR).finish();
727        *func.succs_mut(entry) = vec![BlockCall::to(head)];
728        func.build(head, nop).uses(sum, GPR).finish();
729        *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
730        func.build(arm, nop).def(inside, GPR).finish();
731        func.build(arm, nop).uses(inside, GPR).finish();
732        *func.succs_mut(arm) = vec![BlockCall::to(out)];
733        func.build(latch, nop).def(loaded, GPR).finish();
734        let carry = func
735            .build(latch, add)
736            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
737            .uses(seed, GPR)
738            .uses(loaded, GPR)
739            .finish();
740        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
741
742        let order = Order::of(&func);
743        let live = Live::of(&func, &order);
744        let sum = live.area(sum).expect("live somewhere");
745        let loaded = live.area(loaded).expect("live somewhere");
746        // The answer is live in the entry and the head as well, which the arm is a hole in, so the
747        // piece the addition writes is the second one. Adding the point in front of the first piece
748        // instead would leave the addition reading a register the answer is about to be written to
749        // and nothing saying the two are on top of each other. tamnd/rucc#982.
750        assert_eq!(sum.pieces().count(), 2);
751        assert!(!sum.covers(order.early(carry)));
752        assert!(sum.with(order.early(carry)).covers(order.early(carry)));
753        assert!(!loaded.overlaps(sum));
754        assert!(loaded.overlaps(sum.with(order.early(carry))));
755    }
756
757    #[test]
758    fn a_value_carried_round_a_loop_is_live_round_all_of_it() {
759        let mut names = Interner::new();
760        let mut func = Func::new(names.intern("f"));
761        let opcode = Opcode::new(names.intern("x64.nop"));
762        let header = func.create_block();
763        let body = func.create_block();
764        let carried = func.append_param(header, GPR);
765        let next = func.new_vreg(GPR);
766        *func.succs_mut(header) = vec![BlockCall::to(body)];
767        func.build(body, opcode).def(next, GPR).uses(carried, GPR).finish();
768        *func.succs_mut(body) = vec![BlockCall::with(header, vec![next])];
769
770        let order = Order::of(&func);
771        let live = Live::of(&func, &order);
772        // The parameter arrives in the header, so the header does not want it from anybody, and
773        // the body does.
774        assert_eq!(regs(live.live_in(header)), Vec::<u32>::new());
775        assert_eq!(regs(live.live_in(body)), vec![carried.number().expect("virtual")]);
776        let range = live.range(next).expect("live somewhere");
777        assert_eq!(range.end, order.end(body));
778    }
779
780    #[test]
781    fn two_values_that_are_never_both_wanted_do_not_overlap() {
782        let mut names = Interner::new();
783        let mut func = Func::new(names.intern("f"));
784        let opcode = Opcode::new(names.intern("x64.nop"));
785        let block = func.create_block();
786        let first = func.new_vreg(GPR);
787        let second = func.new_vreg(GPR);
788        let write = func.build(block, opcode).def(first, GPR).finish();
789        func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
790
791        let order = Order::of(&func);
792        let live = Live::of(&func, &order);
793        let first = live.range(first).expect("live somewhere");
794        let second = live.range(second).expect("live somewhere");
795        // The second instruction reads the first value and writes its own, and it reads before
796        // it writes, so the two can be the same register. That is what a two address instruction
797        // needs to be true and it is a fact about the points rather than about the opcode.
798        assert!(!first.overlaps(second));
799        assert!(first.start > order.start(block));
800        assert_eq!(first.start, order.late(write));
801    }
802
803    #[test]
804    fn an_operand_written_early_is_wanted_where_the_operands_are_read() {
805        let mut names = Interner::new();
806        let mut func = Func::new(names.intern("f"));
807        let opcode = Opcode::new(names.intern("x64.nop"));
808        let block = func.create_block();
809        let source = func.new_vreg(GPR);
810        let early = func.new_vreg(GPR);
811        func.build(block, opcode).def(source, GPR).finish();
812        func.build(block, opcode)
813            .operand(Operand::write_early(early, GPR))
814            .operand(Operand::read(source, GPR))
815            .finish();
816
817        let order = Order::of(&func);
818        let live = Live::of(&func, &order);
819        let source = live.range(source).expect("live somewhere");
820        let early = live.range(early).expect("live somewhere");
821        // This is the difference between a division and an addition. The register the answer is
822        // going to is destroyed before the divisor is read, so the divisor may not be in it.
823        assert!(source.overlaps(early));
824    }
825
826    #[test]
827    fn a_register_a_memory_operand_names_is_read_like_any_other() {
828        use rucc_mir::Mem;
829
830        let mut names = Interner::new();
831        let mut func = Func::new(names.intern("f"));
832        let opcode = Opcode::new(names.intern("x64.nop"));
833        let block = func.create_block();
834        let address = func.new_vreg(GPR);
835        let write = func.build(block, opcode).def(address, GPR).finish();
836        let load = func.build(block, opcode).mem(Mem::at(Operand::read(address, GPR))).finish();
837
838        let order = Order::of(&func);
839        let live = Live::of(&func, &order);
840        assert_eq!(
841            live.range(address),
842            Some(Range { start: order.late(write), end: order.early(load) })
843        );
844    }
845}