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