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//! One interval per virtual register, with no holes in it. A value that is dead in the middle of
15//! its range is treated as live there, which costs a register the allocator could have handed out
16//! and never claims one is free when it is not. Holes are what the backtracking allocator will
17//! want and it will want a different structure to hold them in, since a range it can split is a
18//! range with a list of pieces rather than two numbers.
19//!
20//! Physical registers in the operands are not in the answer. Nothing writes one before allocation
21//! except an instruction that must, and what a call destroys is a separate question that the ABI
22//! lowering asks, so a pass that reads this is reading about the values the allocator places.
23//!
24//! # How it is computed
25//!
26//! Which values arrive live in each block and which leave live is a fixpoint over the blocks, run
27//! backwards because liveness flows backwards, and it is a fixpoint rather than one pass because
28//! a loop carries a value from the end of a block round to a block in front of it. The intervals
29//! then come from one walk over the instructions. A block a value is live through contributes the
30//! whole of that block, which is what makes the interval cover the loop rather than stopping at
31//! the last instruction that mentions it.
32
33use rucc_mir::{Block, Func, Reg, Role};
34
35use crate::order::{Order, Point};
36
37/// The stretch of the function a value is live over.
38///
39/// Both ends are included: a value written at a point and read at a later one is live at both,
40/// and one written and never read is live where it was written, because the register it was
41/// written to is not free at the instant it was written to. A value written early is written
42/// before the instruction reads its operands and is still written when the instruction is done,
43/// so even one nothing reads covers the whole of the instruction that wrote it.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct Range {
46    /// Where the value is written.
47    pub start: Point,
48    /// The last place it is read, or where it is written if nothing reads it.
49    pub end: Point,
50}
51
52impl Range {
53    /// Whether the value is live at that point.
54    #[must_use]
55    pub fn covers(self, point: Point) -> bool {
56        self.start <= point && point <= self.end
57    }
58
59    /// Whether two values are both live anywhere, which is what stops them sharing a register.
60    #[must_use]
61    pub fn overlaps(self, other: Self) -> bool {
62        self.start <= other.end && other.start <= self.end
63    }
64
65    /// The smallest range covering both, which is how a range grows as more of the function is
66    /// read.
67    fn with(self, point: Point) -> Self {
68        Self { start: self.start.min(point), end: self.end.max(point) }
69    }
70}
71
72/// What is live where.
73#[derive(Debug, Clone)]
74pub struct Live {
75    live_in: Rows,
76    live_out: Rows,
77    ranges: Vec<Option<Range>>,
78}
79
80impl Live {
81    /// Works it out for a function laid out in that order.
82    #[must_use]
83    pub fn of(func: &Func, order: &Order) -> Self {
84        let vregs = func.vregs();
85        let (used, defined) = exposed(func, order);
86        let (live_in, live_out) = flow(func, order, &used, &defined);
87        let ranges = measure(func, order, &live_in, &live_out, vregs);
88        Self { live_in, live_out, ranges }
89    }
90
91    /// Where a virtual register is live, or `None` for one this function never mentions and for
92    /// a physical register.
93    #[must_use]
94    pub fn range(&self, reg: Reg) -> Option<Range> {
95        self.ranges.get(usize::try_from(reg.number()?).ok()?).copied().flatten()
96    }
97
98    /// Every virtual register that arrives in a block already holding a value.
99    ///
100    /// The block's own parameters are not among them. A parameter is written where it arrives,
101    /// which makes it a value the block defines rather than one it inherits.
102    pub fn live_in(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
103        self.live_in.iter(block.index())
104    }
105
106    /// Every virtual register that is still wanted after a block, which is what its successors
107    /// and the arguments its terminator carries between them ask for.
108    pub fn live_out(&self, block: Block) -> impl Iterator<Item = Reg> + '_ {
109        self.live_out.iter(block.index())
110    }
111}
112
113/// The intervals, from the blocks and from the instructions in them.
114fn measure(
115    func: &Func,
116    order: &Order,
117    live_in: &Rows,
118    live_out: &Rows,
119    vregs: usize,
120) -> Vec<Option<Range>> {
121    let mut ranges: Vec<Option<Range>> = vec![None; vregs];
122    let mut extend = |reg: Reg, point: Point| {
123        let Some(number) = reg.number().and_then(|number| usize::try_from(number).ok()) else {
124            return;
125        };
126        let Some(slot) = ranges.get_mut(number) else { return };
127        *slot = Some(match *slot {
128            Some(range) => range.with(point),
129            None => Range { start: point, end: point },
130        });
131    };
132
133    for &block in order.blocks() {
134        // A block a value arrives in and leaves is one it is live through, whether or not
135        // anything in it says the value's name.
136        for reg in live_in.iter(block.index()) {
137            extend(reg, order.start(block));
138        }
139        for reg in live_out.iter(block.index()) {
140            extend(reg, order.end(block));
141        }
142        for param in &func[block].params {
143            extend(param.reg, order.start(block));
144        }
145        for inst in func.insts(block) {
146            for operand in &func[func[inst].operands] {
147                match operand.role {
148                    Role::Use => extend(operand.reg, order.early(inst)),
149                    Role::Def => extend(operand.reg, order.late(inst)),
150                    // A register written early is taken from before the operands are read, which
151                    // is the whole of what makes it different from a plain definition, and it is
152                    // still taken when the instruction is done. Both ends have to be said. Saying
153                    // only the first would leave a value nothing reads live at a point in front of
154                    // everything else the instruction writes, and the register it went to would
155                    // look free to them.
156                    Role::EarlyDef => {
157                        extend(operand.reg, order.early(inst));
158                        extend(operand.reg, order.late(inst));
159                    }
160                }
161            }
162        }
163        for call in &func[block].succs {
164            for &arg in &call.args {
165                extend(arg, order.end(block));
166            }
167        }
168    }
169    ranges
170}
171
172/// What each block reads before writing, and what it writes.
173///
174/// The first is read backwards, because a value a block writes and then reads is one it does not
175/// want from anybody, while one it reads and then writes is.
176fn exposed(func: &Func, order: &Order) -> (Rows, Rows) {
177    let mut used = Rows::new(func.block_count(), func.vregs());
178    let mut defined = Rows::new(func.block_count(), func.vregs());
179    for &block in order.blocks() {
180        let row = block.index();
181        for call in &func[block].succs {
182            for &arg in &call.args {
183                used.insert(row, arg);
184            }
185        }
186        let insts: Vec<_> = func.insts(block).collect();
187        for &inst in insts.iter().rev() {
188            let operands = &func[func[inst].operands];
189            for operand in operands.iter().filter(|operand| operand.role.is_def()) {
190                used.remove(row, operand.reg);
191                defined.insert(row, operand.reg);
192            }
193            for operand in operands.iter().filter(|operand| !operand.role.is_def()) {
194                used.insert(row, operand.reg);
195            }
196        }
197        for param in &func[block].params {
198            used.remove(row, param.reg);
199            defined.insert(row, param.reg);
200        }
201    }
202    (used, defined)
203}
204
205/// The fixpoint: what arrives live in each block, and what leaves live.
206fn flow(func: &Func, order: &Order, used: &Rows, defined: &Rows) -> (Rows, Rows) {
207    let mut live_in = Rows::new(func.block_count(), func.vregs());
208    let mut live_out = Rows::new(func.block_count(), func.vregs());
209    let width = live_in.width;
210    let mut next = vec![0u64; width];
211    let mut changed = true;
212    while changed {
213        changed = false;
214        for &block in order.blocks().iter().rev() {
215            let row = block.index();
216            for call in &func[block].succs {
217                let successor = call.block.index();
218                for (word, &incoming) in
219                    live_out.row_mut(row).iter_mut().zip(live_in.row(successor))
220                {
221                    *word |= incoming;
222                }
223            }
224            for (index, word) in next.iter_mut().enumerate() {
225                *word =
226                    used.row(row)[index] | (live_out.row(row)[index] & !defined.row(row)[index]);
227            }
228            if live_in.row(row) != next.as_slice() {
229                live_in.row_mut(row).copy_from_slice(&next);
230                changed = true;
231            }
232        }
233    }
234    (live_in, live_out)
235}
236
237/// A set of virtual registers for each block.
238#[derive(Debug, Clone)]
239struct Rows {
240    words: Vec<u64>,
241    /// How many words one row is, which is at least one so that a row is a slice rather than
242    /// nothing.
243    width: usize,
244}
245
246impl Rows {
247    fn new(rows: usize, columns: usize) -> Self {
248        let width = columns.div_ceil(64).max(1);
249        Self { words: vec![0; rows * width], width }
250    }
251
252    fn row(&self, row: usize) -> &[u64] {
253        &self.words[row * self.width..(row + 1) * self.width]
254    }
255
256    fn row_mut(&mut self, row: usize) -> &mut [u64] {
257        &mut self.words[row * self.width..(row + 1) * self.width]
258    }
259
260    /// The column a register is, or nothing for a physical one, which this does not track.
261    fn column(&self, reg: Reg) -> Option<usize> {
262        let number = usize::try_from(reg.number()?).ok()?;
263        (number < self.width * 64).then_some(number)
264    }
265
266    fn insert(&mut self, row: usize, reg: Reg) {
267        if let Some(column) = self.column(reg) {
268            self.row_mut(row)[column / 64] |= 1 << (column % 64);
269        }
270    }
271
272    fn remove(&mut self, row: usize, reg: Reg) {
273        if let Some(column) = self.column(reg) {
274            self.row_mut(row)[column / 64] &= !(1 << (column % 64));
275        }
276    }
277
278    fn iter(&self, row: usize) -> impl Iterator<Item = Reg> + '_ {
279        self.row(row).iter().enumerate().flat_map(|(word, &bits)| {
280            (0..64).filter(move |bit| bits & (1 << bit) != 0).map(move |bit| {
281                Reg::virtual_reg(u32::try_from(word * 64 + bit).expect("a register number"))
282            })
283        })
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use rucc_base::Interner;
290    use rucc_mir::{BlockCall, Opcode, Operand};
291    use rucc_target::x86_64::GPR;
292
293    use super::*;
294
295    /// The registers live in or out of a block, in order, which is what an assertion reads.
296    fn regs(of: impl Iterator<Item = Reg>) -> Vec<u32> {
297        of.filter_map(Reg::number).collect()
298    }
299
300    #[test]
301    fn a_value_is_live_from_where_it_is_written_to_where_it_is_last_read() {
302        let mut names = Interner::new();
303        let mut func = Func::new(names.intern("f"));
304        let opcode = Opcode::new(names.intern("x64.nop"));
305        let block = func.create_block();
306        let value = func.new_vreg(GPR);
307        let other = func.new_vreg(GPR);
308        let write = func.build(block, opcode).def(value, GPR).finish();
309        let idle = func.build(block, opcode).def(other, GPR).finish();
310        let read = func.build(block, opcode).uses(value, GPR).finish();
311
312        let order = Order::of(&func);
313        let live = Live::of(&func, &order);
314        let range = live.range(value).expect("the value is live somewhere");
315        assert_eq!(range, Range { start: order.late(write), end: order.early(read) });
316        assert!(range.covers(order.early(idle)));
317        // A value nothing reads is live where it was written and nowhere else, because the
318        // register it went to was not free at that instant either.
319        assert_eq!(
320            live.range(other),
321            Some(Range { start: order.late(idle), end: order.late(idle) })
322        );
323        assert!(!range.overlaps(Range { start: order.late(read), end: order.late(read) }));
324        assert_eq!(regs(live.live_in(block)), Vec::<u32>::new());
325    }
326
327    #[test]
328    fn a_value_read_in_another_block_is_live_between_them() {
329        let mut names = Interner::new();
330        let mut func = Func::new(names.intern("f"));
331        let opcode = Opcode::new(names.intern("x64.nop"));
332        let head = func.create_block();
333        let middle = func.create_block();
334        let tail = func.create_block();
335        let value = func.new_vreg(GPR);
336        func.build(head, opcode).def(value, GPR).finish();
337        *func.succs_mut(head) = vec![BlockCall::to(middle)];
338        *func.succs_mut(middle) = vec![BlockCall::to(tail)];
339        let read = func.build(tail, opcode).uses(value, GPR).finish();
340
341        let order = Order::of(&func);
342        let live = Live::of(&func, &order);
343        // The block in between never mentions it and it is live all the way through, which is
344        // the whole reason this is a fixpoint over the blocks and not a walk over the code.
345        assert_eq!(regs(live.live_in(middle)), vec![0]);
346        assert_eq!(regs(live.live_out(middle)), vec![0]);
347        assert!(live.range(value).expect("live somewhere").covers(order.start(middle)));
348        assert_eq!(live.range(value).expect("live somewhere").end, order.early(read));
349    }
350
351    #[test]
352    fn a_value_carried_round_a_loop_is_live_round_all_of_it() {
353        let mut names = Interner::new();
354        let mut func = Func::new(names.intern("f"));
355        let opcode = Opcode::new(names.intern("x64.nop"));
356        let header = func.create_block();
357        let body = func.create_block();
358        let carried = func.append_param(header, GPR);
359        let next = func.new_vreg(GPR);
360        *func.succs_mut(header) = vec![BlockCall::to(body)];
361        func.build(body, opcode).def(next, GPR).uses(carried, GPR).finish();
362        *func.succs_mut(body) = vec![BlockCall::with(header, vec![next])];
363
364        let order = Order::of(&func);
365        let live = Live::of(&func, &order);
366        // The parameter arrives in the header, so the header does not want it from anybody, and
367        // the body does.
368        assert_eq!(regs(live.live_in(header)), Vec::<u32>::new());
369        assert_eq!(regs(live.live_in(body)), vec![carried.number().expect("virtual")]);
370        let range = live.range(next).expect("live somewhere");
371        assert_eq!(range.end, order.end(body));
372    }
373
374    #[test]
375    fn two_values_that_are_never_both_wanted_do_not_overlap() {
376        let mut names = Interner::new();
377        let mut func = Func::new(names.intern("f"));
378        let opcode = Opcode::new(names.intern("x64.nop"));
379        let block = func.create_block();
380        let first = func.new_vreg(GPR);
381        let second = func.new_vreg(GPR);
382        let write = func.build(block, opcode).def(first, GPR).finish();
383        func.build(block, opcode).def(second, GPR).uses(first, GPR).finish();
384
385        let order = Order::of(&func);
386        let live = Live::of(&func, &order);
387        let first = live.range(first).expect("live somewhere");
388        let second = live.range(second).expect("live somewhere");
389        // The second instruction reads the first value and writes its own, and it reads before
390        // it writes, so the two can be the same register. That is what a two address instruction
391        // needs to be true and it is a fact about the points rather than about the opcode.
392        assert!(!first.overlaps(second));
393        assert!(first.start > order.start(block));
394        assert_eq!(first.start, order.late(write));
395    }
396
397    #[test]
398    fn an_operand_written_early_is_wanted_where_the_operands_are_read() {
399        let mut names = Interner::new();
400        let mut func = Func::new(names.intern("f"));
401        let opcode = Opcode::new(names.intern("x64.nop"));
402        let block = func.create_block();
403        let source = func.new_vreg(GPR);
404        let early = func.new_vreg(GPR);
405        func.build(block, opcode).def(source, GPR).finish();
406        func.build(block, opcode)
407            .operand(Operand::write_early(early, GPR))
408            .operand(Operand::read(source, GPR))
409            .finish();
410
411        let order = Order::of(&func);
412        let live = Live::of(&func, &order);
413        let source = live.range(source).expect("live somewhere");
414        let early = live.range(early).expect("live somewhere");
415        // This is the difference between a division and an addition. The register the answer is
416        // going to is destroyed before the divisor is read, so the divisor may not be in it.
417        assert!(source.overlaps(early));
418    }
419
420    #[test]
421    fn a_register_a_memory_operand_names_is_read_like_any_other() {
422        use rucc_mir::Mem;
423
424        let mut names = Interner::new();
425        let mut func = Func::new(names.intern("f"));
426        let opcode = Opcode::new(names.intern("x64.nop"));
427        let block = func.create_block();
428        let address = func.new_vreg(GPR);
429        let write = func.build(block, opcode).def(address, GPR).finish();
430        let load = func.build(block, opcode).mem(Mem::at(Operand::read(address, GPR))).finish();
431
432        let order = Order::of(&func);
433        let live = Live::of(&func, &order);
434        assert_eq!(
435            live.range(address),
436            Some(Range { start: order.late(write), end: order.early(load) })
437        );
438    }
439}