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 a fixpoint over the blocks, run
37//! backwards because liveness flows backwards, and it is a fixpoint rather than one pass because
38//! a loop carries a value from the end of a block round to a block in front of it. The pieces then
39//! come from one walk over the instructions, a block at a time.
40//!
41//! Inside one block a value's live points are one stretch and never two, because the machine IR is
42//! in SSA form and a value is written once. The stretch runs from the start of the block if the
43//! value arrives live and from where it is written otherwise, and to the end of the block if it
44//! leaves live and to its last read otherwise. Two stretches join into one piece when the blocks
45//! they are in are next to each other in the line, which is what makes a value carried round a loop
46//! one piece over the whole loop rather than one per block in it.
47
48use rucc_mir::{Block, Func, Reg, Role};
49
50use crate::order::{Order, Point};
51
52/// The stretch of the function a value is live over.
53///
54/// Both ends are included: a value written at a point and read at a later one is live at both,
55/// and one written and never read is live where it was written, because the register it was
56/// written to is not free at the instant it was written to. A value written early is written
57/// before the instruction reads its operands and is still written when the instruction is done,
58/// so even one nothing reads covers the whole of the instruction that wrote it.
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct Range {
61    /// Where the value is written.
62    pub start: Point,
63    /// The last place it is read, or where it is written if nothing reads it.
64    pub end: Point,
65}
66
67impl Range {
68    /// Whether the value is live at that point.
69    #[must_use]
70    pub fn covers(self, point: Point) -> bool {
71        self.start <= point && point <= self.end
72    }
73
74    /// Whether two values are both live anywhere, which is what stops them sharing a register.
75    #[must_use]
76    pub fn overlaps(self, other: Self) -> bool {
77        self.start <= other.end && other.start <= self.end
78    }
79
80    /// The smallest range covering both, which is how a range grows as more of the function is
81    /// read.
82    fn with(self, point: Point) -> Self {
83        Self { start: self.start.min(point), end: self.end.max(point) }
84    }
85}
86
87/// Everywhere one value is live, which is one or more pieces and at most one more point in front
88/// of the piece that follows it.
89///
90/// That one extra point is the only thing about a live area anybody adjusts. A value a two address
91/// instruction writes into a register it read is really live from where that instruction reads its
92/// operands, which is one point in front of where it is written, and both the allocator and the
93/// checker add that point before asking anything. It is one point rather than a new start because
94/// a value can be live in several pieces and the one to stretch is the piece the instruction
95/// writes, which is not always the first. Reading an area this way only ever makes it bigger, so
96/// it is still an area and every answer below still holds of it.
97#[derive(Debug, Clone, Copy)]
98pub struct Area<'a> {
99    pieces: &'a [Range],
100    also: Option<Point>,
101}
102
103impl<'a> Area<'a> {
104    /// The same area with one more point in it, joined to the piece that starts just after it.
105    ///
106    /// A point already inside a piece changes nothing, which is what a value a loop carries round
107    /// looks like: it is live on the way into the instruction that writes it anyway.
108    #[must_use]
109    pub fn with(self, point: Point) -> Self {
110        Self { also: Some(point), ..self }
111    }
112
113    /// The interval around the whole area, holes and all, which is what a sweep in the order
114    /// values start reads.
115    #[must_use]
116    pub fn hull(self) -> Range {
117        Range { start: self.piece(0).start, end: self.pieces[self.pieces.len() - 1].end }
118    }
119
120    /// Whether the value is live at that point.
121    #[must_use]
122    pub fn covers(self, point: Point) -> bool {
123        (0..self.pieces.len()).any(|piece| self.piece(piece).covers(point))
124    }
125
126    /// Whether two values are both live somewhere, which is what stops them sharing a register.
127    ///
128    /// Both lists are in order and neither is long, so this walks them together and stops at the
129    /// first pair that touches rather than comparing every piece with every other.
130    #[must_use]
131    pub fn overlaps(self, other: Self) -> bool {
132        let (mut mine, mut theirs) = (0, 0);
133        while mine < self.pieces.len() && theirs < other.pieces.len() {
134            let (one, two) = (self.piece(mine), other.piece(theirs));
135            if one.overlaps(two) {
136                return true;
137            }
138            // Whichever stops first cannot reach anything further along the other list.
139            if one.end < two.end {
140                mine += 1;
141            } else {
142                theirs += 1;
143            }
144        }
145        false
146    }
147
148    /// The pieces themselves, in order.
149    pub fn pieces(self) -> impl Iterator<Item = Range> + 'a {
150        (0..self.pieces.len()).map(move |piece| self.piece(piece))
151    }
152
153    /// One piece, stretched down over the extra point when that point is the one just in front of
154    /// it.
155    fn piece(self, index: usize) -> Range {
156        let piece = self.pieces[index];
157        match self.also {
158            Some(also) if also + 1 == piece.start => Range { start: also, end: piece.end },
159            _ => piece,
160        }
161    }
162}
163
164/// What is live where.
165#[derive(Debug, Clone)]
166pub struct Live {
167    live_in: Rows,
168    live_out: Rows,
169    /// Every value's pieces end to end, since a vector per value would be a vector per value.
170    pieces: Vec<Range>,
171    /// Where each value's pieces are in that vector, by register number.
172    spans: Vec<(usize, usize)>,
173}
174
175impl Live {
176    /// Works it out for a function laid out in that order.
177    #[must_use]
178    pub fn of(func: &Func, order: &Order) -> Self {
179        let vregs = func.vregs();
180        let (used, defined) = exposed(func, order);
181        let (live_in, live_out) = flow(func, order, &used, &defined);
182        let (pieces, spans) = carve(func, order, &live_in, &live_out, vregs);
183        Self { live_in, live_out, pieces, spans }
184    }
185
186    /// Everywhere a virtual register is live, or `None` for one this function never mentions and
187    /// for a physical register.
188    #[must_use]
189    pub fn area(&self, reg: Reg) -> Option<Area<'_>> {
190        let pieces = self.pieces(reg);
191        if pieces.is_empty() {
192            return None;
193        }
194        Some(Area { pieces, also: None })
195    }
196
197    /// The interval a virtual register is live over, holes and all.
198    #[must_use]
199    pub fn range(&self, reg: Reg) -> Option<Range> {
200        self.area(reg).map(Area::hull)
201    }
202
203    /// Every virtual register that arrives in a block already holding a value.
204    ///
205    /// The block's own parameters are not among them. A parameter is written where it arrives,
206    /// which makes it a value the block defines rather than one it inherits.
207    pub fn live_in(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
208        self.live_in.iter(block.index())
209    }
210
211    /// Every virtual register that is still wanted after a block, which is what its successors
212    /// and the arguments its terminator carries between them ask for.
213    pub fn live_out(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
214        self.live_out.iter(block.index())
215    }
216
217    /// Everywhere a virtual register is live, as it is stored.
218    fn pieces(&self, reg: Reg) -> &[Range] {
219        let number = reg.number().and_then(|number| usize::try_from(number).ok());
220        let Some(&(from, to)) = number.and_then(|number| self.spans.get(number)) else {
221            return &[];
222        };
223        &self.pieces[from..to]
224    }
225}
226
227/// The pieces, from the blocks and from the instructions in them.
228///
229/// One block at a time, because a value's live points inside one block are one stretch and the
230/// whole job is working out where one stretch stops and the next begins. What comes back is every
231/// value's pieces end to end, and where each value's are.
232fn carve(
233    func: &Func,
234    order: &Order,
235    live_in: &Rows,
236    live_out: &Rows,
237    vregs: usize,
238) -> (Vec<Range>, Vec<(usize, usize)>) {
239    let mut lists: Vec<Vec<Range>> = vec![Vec::new(); vregs];
240    let mut here: Vec<Option<Range>> = vec![None; vregs];
241    let mut touched: Vec<usize> = Vec::new();
242
243    for &block in order.blocks() {
244        // A block a value arrives in and leaves is one it is live through, whether or not
245        // anything in it says the value's name.
246        for reg in live_in.iter(block.index()) {
247            note(&mut here, &mut touched, reg, order.start(block));
248        }
249        for reg in live_out.iter(block.index()) {
250            note(&mut here, &mut touched, reg, order.end(block));
251        }
252        for param in &func[block].params {
253            note(&mut here, &mut touched, param.reg, order.start(block));
254        }
255        for inst in func.insts(block) {
256            for operand in &func[func[inst].operands] {
257                match operand.role {
258                    Role::Use => note(&mut here, &mut touched, operand.reg, order.early(inst)),
259                    Role::Def => note(&mut here, &mut touched, operand.reg, order.late(inst)),
260                    // A register written early is taken from before the operands are read, which
261                    // is the whole of what makes it different from a plain definition, and it is
262                    // still taken when the instruction is done. Both ends have to be said. Saying
263                    // only the first would leave a value nothing reads live at a point in front of
264                    // everything else the instruction writes, and the register it went to would
265                    // look free to them.
266                    Role::EarlyDef => {
267                        note(&mut here, &mut touched, operand.reg, order.early(inst));
268                        note(&mut here, &mut touched, operand.reg, order.late(inst));
269                    }
270                }
271            }
272        }
273        for call in &func[block].succs {
274            for &arg in &call.args {
275                note(&mut here, &mut touched, arg, order.end(block));
276            }
277        }
278
279        for &number in &touched {
280            let Some(piece) = here[number].take() else { continue };
281            match lists[number].last_mut() {
282                // The points run on from one block into the next, so a stretch that begins where
283                // the last one stopped is the same run of blocks carried on. A gap of even one
284                // point means a block in between that the value is not live in.
285                Some(last) if last.end + 1 == piece.start => last.end = piece.end,
286                _ => lists[number].push(piece),
287            }
288        }
289        touched.clear();
290    }
291
292    let mut pieces = Vec::new();
293    let mut spans = Vec::with_capacity(vregs);
294    for list in &lists {
295        let from = pieces.len();
296        pieces.extend_from_slice(list);
297        spans.push((from, pieces.len()));
298    }
299    (pieces, spans)
300}
301
302/// Says that a value is live at a point of the block being carved.
303fn note(here: &mut [Option<Range>], touched: &mut Vec<usize>, reg: Reg, point: Point) {
304    let Some(number) = reg.number().and_then(|number| usize::try_from(number).ok()) else {
305        return;
306    };
307    let Some(slot) = here.get_mut(number) else { return };
308    match slot {
309        Some(range) => *range = range.with(point),
310        None => {
311            *slot = Some(Range { start: point, end: point });
312            touched.push(number);
313        }
314    }
315}
316
317/// What each block reads before writing, and what it writes.
318///
319/// The first is read backwards, because a value a block writes and then reads is one it does not
320/// want from anybody, while one it reads and then writes is.
321fn exposed(func: &Func, order: &Order) -> (Rows, Rows) {
322    let mut used = Rows::new(func.block_count(), func.vregs());
323    let mut defined = Rows::new(func.block_count(), func.vregs());
324    for &block in order.blocks() {
325        let row = block.index();
326        for call in &func[block].succs {
327            for &arg in &call.args {
328                used.insert(row, arg);
329            }
330        }
331        let insts: Vec<_> = func.insts(block).collect();
332        for &inst in insts.iter().rev() {
333            let operands = &func[func[inst].operands];
334            for operand in operands.iter().filter(|operand| operand.role.is_def()) {
335                used.remove(row, operand.reg);
336                defined.insert(row, operand.reg);
337            }
338            for operand in operands.iter().filter(|operand| !operand.role.is_def()) {
339                used.insert(row, operand.reg);
340            }
341        }
342        for param in &func[block].params {
343            used.remove(row, param.reg);
344            defined.insert(row, param.reg);
345        }
346    }
347    (used, defined)
348}
349
350/// The fixpoint: what arrives live in each block, and what leaves live.
351fn flow(func: &Func, order: &Order, used: &Rows, defined: &Rows) -> (Rows, Rows) {
352    let mut live_in = Rows::new(func.block_count(), func.vregs());
353    let mut live_out = Rows::new(func.block_count(), func.vregs());
354    let width = live_in.width;
355    let mut next = vec![0u64; width];
356    let mut changed = true;
357    while changed {
358        changed = false;
359        for &block in order.blocks().iter().rev() {
360            let row = block.index();
361            for call in &func[block].succs {
362                let successor = call.block.index();
363                for (word, &incoming) in
364                    live_out.row_mut(row).iter_mut().zip(live_in.row(successor))
365                {
366                    *word |= incoming;
367                }
368            }
369            for (index, word) in next.iter_mut().enumerate() {
370                *word =
371                    used.row(row)[index] | (live_out.row(row)[index] & !defined.row(row)[index]);
372            }
373            if live_in.row(row) != next.as_slice() {
374                live_in.row_mut(row).copy_from_slice(&next);
375                changed = true;
376            }
377        }
378    }
379    (live_in, live_out)
380}
381
382/// A set of virtual registers for each block.
383#[derive(Debug, Clone)]
384struct Rows {
385    words: Vec<u64>,
386    /// How many words one row is, which is at least one so that a row is a slice rather than
387    /// nothing.
388    width: usize,
389}
390
391impl Rows {
392    fn new(rows: usize, columns: usize) -> Self {
393        let width = columns.div_ceil(64).max(1);
394        Self { words: vec![0; rows * width], width }
395    }
396
397    fn row(&self, row: usize) -> &[u64] {
398        &self.words[row * self.width..(row + 1) * self.width]
399    }
400
401    fn row_mut(&mut self, row: usize) -> &mut [u64] {
402        &mut self.words[row * self.width..(row + 1) * self.width]
403    }
404
405    /// The column a register is, or nothing for a physical one, which this does not track.
406    fn column(&self, reg: Reg) -> Option<usize> {
407        let number = usize::try_from(reg.number()?).ok()?;
408        (number < self.width * 64).then_some(number)
409    }
410
411    fn insert(&mut self, row: usize, reg: Reg) {
412        if let Some(column) = self.column(reg) {
413            self.row_mut(row)[column / 64] |= 1 << (column % 64);
414        }
415    }
416
417    fn remove(&mut self, row: usize, reg: Reg) {
418        if let Some(column) = self.column(reg) {
419            self.row_mut(row)[column / 64] &= !(1 << (column % 64));
420        }
421    }
422
423    fn iter(&self, row: usize) -> impl Iterator<Item = Reg> + '_ {
424        self.row(row).iter().enumerate().flat_map(|(word, &bits)| {
425            (0..64).filter(move |bit| bits & (1 << bit) != 0).map(move |bit| {
426                Reg::virtual_reg(u32::try_from(word * 64 + bit).expect("a register number"))
427            })
428        })
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use rucc_base::Interner;
435    use rucc_mir::{BlockCall, Constraint, Opcode, Operand};
436    use rucc_target::x86_64::GPR;
437
438    use super::*;
439
440    /// The registers live in or out of a block, in order, which is what an assertion reads.
441    fn regs(of: impl Iterator<Item = Reg>) -> Vec<u32> {
442        of.filter_map(Reg::number).collect()
443    }
444
445    #[test]
446    fn a_value_is_live_from_where_it_is_written_to_where_it_is_last_read() {
447        let mut names = Interner::new();
448        let mut func = Func::new(names.intern("f"));
449        let opcode = Opcode::new(names.intern("x64.nop"));
450        let block = func.create_block();
451        let value = func.new_vreg(GPR);
452        let other = func.new_vreg(GPR);
453        let write = func.build(block, opcode).def(value, GPR).finish();
454        let idle = func.build(block, opcode).def(other, GPR).finish();
455        let read = func.build(block, opcode).uses(value, GPR).finish();
456
457        let order = Order::of(&func);
458        let live = Live::of(&func, &order);
459        let range = live.range(value).expect("the value is live somewhere");
460        assert_eq!(range, Range { start: order.late(write), end: order.early(read) });
461        assert!(range.covers(order.early(idle)));
462        // A value nothing reads is live where it was written and nowhere else, because the
463        // register it went to was not free at that instant either.
464        assert_eq!(
465            live.range(other),
466            Some(Range { start: order.late(idle), end: order.late(idle) })
467        );
468        assert!(!range.overlaps(Range { start: order.late(read), end: order.late(read) }));
469        assert_eq!(regs(live.live_in(block)), Vec::<u32>::new());
470    }
471
472    #[test]
473    fn a_value_read_in_another_block_is_live_between_them() {
474        let mut names = Interner::new();
475        let mut func = Func::new(names.intern("f"));
476        let opcode = Opcode::new(names.intern("x64.nop"));
477        let head = func.create_block();
478        let middle = func.create_block();
479        let tail = func.create_block();
480        let value = func.new_vreg(GPR);
481        func.build(head, opcode).def(value, GPR).finish();
482        *func.succs_mut(head) = vec![BlockCall::to(middle)];
483        *func.succs_mut(middle) = vec![BlockCall::to(tail)];
484        let read = func.build(tail, opcode).uses(value, GPR).finish();
485
486        let order = Order::of(&func);
487        let live = Live::of(&func, &order);
488        // The block in between never mentions it and it is live all the way through, which is
489        // the whole reason this is a fixpoint over the blocks and not a walk over the code.
490        assert_eq!(regs(live.live_in(middle)), vec![0]);
491        assert_eq!(regs(live.live_out(middle)), vec![0]);
492        assert!(live.range(value).expect("live somewhere").covers(order.start(middle)));
493        assert_eq!(live.range(value).expect("live somewhere").end, order.early(read));
494    }
495
496    #[test]
497    fn a_block_the_value_never_reaches_is_a_hole_between_two_pieces() {
498        let mut names = Interner::new();
499        let mut func = Func::new(names.intern("f"));
500        let opcode = Opcode::new(names.intern("x64.nop"));
501        let entry = func.create_block();
502        let arm = func.create_block();
503        let tail = func.create_block();
504        let value = func.new_vreg(GPR);
505        let write = func.build(entry, opcode).def(value, GPR).finish();
506        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
507        let idle = func.build(arm, opcode).finish();
508        let read = func.build(tail, opcode).uses(value, GPR).finish();
509
510        let order = Order::of(&func);
511        let live = Live::of(&func, &order);
512        let area = live.area(value).expect("live somewhere");
513        // The arm is written between the two blocks the value is live in, so the interval around
514        // it covers the arm and the pieces do not. Both are true and they answer different
515        // questions, and it is the pieces that decide who may have a register.
516        assert!(live.range(value).expect("live somewhere").covers(order.early(idle)));
517        assert!(!area.covers(order.early(idle)));
518        assert_eq!(
519            area.pieces().collect::<Vec<_>>(),
520            vec![
521                Range { start: order.late(write), end: order.end(entry) },
522                Range { start: order.start(tail), end: order.early(read) },
523            ]
524        );
525    }
526
527    #[test]
528    fn a_value_in_a_hole_of_another_may_have_its_register() {
529        let mut names = Interner::new();
530        let mut func = Func::new(names.intern("f"));
531        let opcode = Opcode::new(names.intern("x64.nop"));
532        let entry = func.create_block();
533        let arm = func.create_block();
534        let tail = func.create_block();
535        let value = func.new_vreg(GPR);
536        let inside = func.new_vreg(GPR);
537        func.build(entry, opcode).def(value, GPR).finish();
538        *func.succs_mut(entry) = vec![BlockCall::to(arm), BlockCall::to(tail)];
539        func.build(arm, opcode).def(inside, GPR).finish();
540        func.build(arm, opcode).uses(inside, GPR).finish();
541        func.build(tail, opcode).uses(value, GPR).finish();
542
543        let order = Order::of(&func);
544        let live = Live::of(&func, &order);
545        let value = live.area(value).expect("live somewhere");
546        let inside = live.area(inside).expect("live somewhere");
547        // Nothing in the arm can reach the read in the tail, so whichever register the first value
548        // is in is a register the arm may take for as long as it likes. The intervals say the two
549        // are on top of each other and they are not.
550        assert!(value.hull().overlaps(inside.hull()));
551        assert!(!value.overlaps(inside));
552        assert!(!inside.overlaps(value));
553    }
554
555    #[test]
556    fn one_point_added_in_front_of_a_piece_is_part_of_the_area() {
557        let mut names = Interner::new();
558        let mut func = Func::new(names.intern("f"));
559        let opcode = Opcode::new(names.intern("x64.nop"));
560        let block = func.create_block();
561        let first = func.new_vreg(GPR);
562        let second = func.new_vreg(GPR);
563        let write = func.build(block, opcode).def(first, GPR).finish();
564        let both = func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
565
566        let order = Order::of(&func);
567        let live = Live::of(&func, &order);
568        let first = live.area(first).expect("live somewhere");
569        let second = live.area(second).expect("live somewhere");
570        // A two address instruction writes its answer into the register it read, so the answer is
571        // really in that register from the moment the instruction starts. Read that way the two
572        // values are on top of each other, and read the plain way they are not, which is the whole
573        // reason the extra point is the caller's to add.
574        assert!(!first.overlaps(second));
575        assert!(first.overlaps(second.with(order.early(both))));
576        assert!(second.with(order.early(both)).covers(order.early(both)));
577        assert_eq!(second.with(order.early(both)).hull().start, order.early(both));
578        assert_eq!(first.hull().start, order.late(write));
579    }
580
581    #[test]
582    fn the_point_added_in_front_joins_the_piece_it_belongs_to_and_not_the_first_one() {
583        let mut names = Interner::new();
584        let mut func = Func::new(names.intern("f"));
585        let nop = Opcode::new(names.intern("x64.nop"));
586        let add = Opcode::new(names.intern("x64.add"));
587        let entry = func.create_block();
588        let head = func.create_block();
589        let arm = func.create_block();
590        let latch = func.create_block();
591        let out = func.create_block();
592        let seed = func.new_vreg(GPR);
593        let sum = func.new_vreg(GPR);
594        let inside = func.new_vreg(GPR);
595        let loaded = func.new_vreg(GPR);
596        func.build(entry, nop).def(seed, GPR).finish();
597        func.build(entry, nop).def(sum, GPR).finish();
598        *func.succs_mut(entry) = vec![BlockCall::to(head)];
599        func.build(head, nop).uses(sum, GPR).finish();
600        *func.succs_mut(head) = vec![BlockCall::to(arm), BlockCall::to(latch)];
601        func.build(arm, nop).def(inside, GPR).finish();
602        func.build(arm, nop).uses(inside, GPR).finish();
603        *func.succs_mut(arm) = vec![BlockCall::to(out)];
604        func.build(latch, nop).def(loaded, GPR).finish();
605        let carry = func
606            .build(latch, add)
607            .operand(Operand::write(sum, GPR).with(Constraint::Reuse(1)))
608            .uses(seed, GPR)
609            .uses(loaded, GPR)
610            .finish();
611        *func.succs_mut(latch) = vec![BlockCall::to(head), BlockCall::to(out)];
612
613        let order = Order::of(&func);
614        let live = Live::of(&func, &order);
615        let sum = live.area(sum).expect("live somewhere");
616        let loaded = live.area(loaded).expect("live somewhere");
617        // The answer is live in the entry and the head as well, which the arm is a hole in, so the
618        // piece the addition writes is the second one. Adding the point in front of the first piece
619        // instead would leave the addition reading a register the answer is about to be written to
620        // and nothing saying the two are on top of each other. tamnd/rucc#982.
621        assert_eq!(sum.pieces().count(), 2);
622        assert!(!sum.covers(order.early(carry)));
623        assert!(sum.with(order.early(carry)).covers(order.early(carry)));
624        assert!(!loaded.overlaps(sum));
625        assert!(loaded.overlaps(sum.with(order.early(carry))));
626    }
627
628    #[test]
629    fn a_value_carried_round_a_loop_is_live_round_all_of_it() {
630        let mut names = Interner::new();
631        let mut func = Func::new(names.intern("f"));
632        let opcode = Opcode::new(names.intern("x64.nop"));
633        let header = func.create_block();
634        let body = func.create_block();
635        let carried = func.append_param(header, GPR);
636        let next = func.new_vreg(GPR);
637        *func.succs_mut(header) = vec![BlockCall::to(body)];
638        func.build(body, opcode).def(next, GPR).uses(carried, GPR).finish();
639        *func.succs_mut(body) = vec![BlockCall::with(header, vec![next])];
640
641        let order = Order::of(&func);
642        let live = Live::of(&func, &order);
643        // The parameter arrives in the header, so the header does not want it from anybody, and
644        // the body does.
645        assert_eq!(regs(live.live_in(header)), Vec::<u32>::new());
646        assert_eq!(regs(live.live_in(body)), vec![carried.number().expect("virtual")]);
647        let range = live.range(next).expect("live somewhere");
648        assert_eq!(range.end, order.end(body));
649    }
650
651    #[test]
652    fn two_values_that_are_never_both_wanted_do_not_overlap() {
653        let mut names = Interner::new();
654        let mut func = Func::new(names.intern("f"));
655        let opcode = Opcode::new(names.intern("x64.nop"));
656        let block = func.create_block();
657        let first = func.new_vreg(GPR);
658        let second = func.new_vreg(GPR);
659        let write = func.build(block, opcode).def(first, GPR).finish();
660        func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
661
662        let order = Order::of(&func);
663        let live = Live::of(&func, &order);
664        let first = live.range(first).expect("live somewhere");
665        let second = live.range(second).expect("live somewhere");
666        // The second instruction reads the first value and writes its own, and it reads before
667        // it writes, so the two can be the same register. That is what a two address instruction
668        // needs to be true and it is a fact about the points rather than about the opcode.
669        assert!(!first.overlaps(second));
670        assert!(first.start > order.start(block));
671        assert_eq!(first.start, order.late(write));
672    }
673
674    #[test]
675    fn an_operand_written_early_is_wanted_where_the_operands_are_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 source = func.new_vreg(GPR);
681        let early = func.new_vreg(GPR);
682        func.build(block, opcode).def(source, GPR).finish();
683        func.build(block, opcode)
684            .operand(Operand::write_early(early, GPR))
685            .operand(Operand::read(source, GPR))
686            .finish();
687
688        let order = Order::of(&func);
689        let live = Live::of(&func, &order);
690        let source = live.range(source).expect("live somewhere");
691        let early = live.range(early).expect("live somewhere");
692        // This is the difference between a division and an addition. The register the answer is
693        // going to is destroyed before the divisor is read, so the divisor may not be in it.
694        assert!(source.overlaps(early));
695    }
696
697    #[test]
698    fn a_register_a_memory_operand_names_is_read_like_any_other() {
699        use rucc_mir::Mem;
700
701        let mut names = Interner::new();
702        let mut func = Func::new(names.intern("f"));
703        let opcode = Opcode::new(names.intern("x64.nop"));
704        let block = func.create_block();
705        let address = func.new_vreg(GPR);
706        let write = func.build(block, opcode).def(address, GPR).finish();
707        let load = func.build(block, opcode).mem(Mem::at(Operand::read(address, GPR))).finish();
708
709        let order = Order::of(&func);
710        let live = Live::of(&func, &order);
711        assert_eq!(
712            live.range(address),
713            Some(Range { start: order.late(write), end: order.early(load) })
714        );
715    }
716}