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