1use rucc_ir::{Block, Func, Inst, Value};
39
40use crate::cfg::Cfg;
41
42#[derive(Debug, Clone, PartialEq, Eq)]
47struct Set {
48 words: Vec<u64>,
49}
50
51impl Set {
52 fn with_room_for(values: usize) -> Self {
54 Self { words: vec![0; values.div_ceil(64)] }
55 }
56
57 fn contains(&self, value: Value) -> bool {
58 let at = value.index();
59 match self.words.get(at / 64) {
60 Some(word) => word & (1 << (at % 64)) != 0,
61 None => false,
62 }
63 }
64
65 fn insert(&mut self, value: Value) -> bool {
67 let at = value.index();
68 let word = &mut self.words[at / 64];
69 let bit = 1 << (at % 64);
70 let had = *word & bit != 0;
71 *word |= bit;
72 !had
73 }
74
75 fn remove(&mut self, value: Value) -> bool {
77 let at = value.index();
78 let word = &mut self.words[at / 64];
79 let bit = 1 << (at % 64);
80 let had = *word & bit != 0;
81 *word &= !bit;
82 had
83 }
84
85 fn union_with(&mut self, other: &Self) -> bool {
87 let mut changed = false;
88 for (mine, theirs) in self.words.iter_mut().zip(&other.words) {
89 let before = *mine;
90 *mine |= theirs;
91 changed |= *mine != before;
92 }
93 changed
94 }
95
96 fn len(&self) -> usize {
97 self.words.iter().map(|word| word.count_ones() as usize).sum()
98 }
99
100 fn iter(&self) -> impl Iterator<Item = Value> + use<'_> {
108 self.words.iter().enumerate().filter(|&(_, &word)| word != 0).flat_map(|(at, &word)| {
109 Bits(word).map(move |bit| Value::new((at * 64 + bit as usize) as u32))
110 })
111 }
112}
113
114struct Bits(u64);
119
120impl Iterator for Bits {
121 type Item = u32;
122
123 fn next(&mut self) -> Option<u32> {
124 if self.0 == 0 {
125 return None;
126 }
127 let bit = self.0.trailing_zeros();
128 self.0 &= self.0 - 1;
129 Some(bit)
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Liveness {
140 live_in: Vec<Set>,
141 live_out: Vec<Set>,
142}
143
144impl Liveness {
145 #[must_use]
147 pub fn of(func: &Func, cfg: &Cfg) -> Self {
148 let blocks = cfg.capacity();
149 let values = func.counts().values;
150 let empty = Set::with_room_for(values);
151 let mut live_in = vec![empty.clone(); blocks];
152 let mut live_out = vec![empty; blocks];
153
154 let order: Vec<Block> = cfg.postorder().to_vec();
157 let mut again = true;
158 while again {
159 again = false;
160 for &block in &order {
161 let mut out = Set::with_room_for(values);
162 for &successor in cfg.successors(block) {
163 out.union_with(&live_in[successor.index()]);
164 }
165 let mut set = out.clone();
166 walk(func, block, &mut set, |_, _, _| {});
167 for ¶m in &func[block].params {
168 set.remove(param);
169 }
170 again |= live_out[block.index()].union_with(&out);
171 again |= live_in[block.index()].union_with(&set);
172 }
173 }
174
175 Self { live_in, live_out }
176 }
177
178 pub fn live_in(&self, block: Block) -> impl Iterator<Item = Value> + use<'_> {
180 self.live_in[block.index()].iter()
181 }
182
183 pub fn live_out(&self, block: Block) -> impl Iterator<Item = Value> + use<'_> {
185 self.live_out[block.index()].iter()
186 }
187
188 #[must_use]
190 pub fn is_live_in(&self, block: Block, value: Value) -> bool {
191 self.live_in[block.index()].contains(value)
192 }
193
194 #[must_use]
196 pub fn is_live_out(&self, block: Block, value: Value) -> bool {
197 self.live_out[block.index()].contains(value)
198 }
199
200 #[must_use]
202 pub fn count_in(&self, block: Block) -> usize {
203 self.live_in[block.index()].len()
204 }
205
206 #[must_use]
208 pub fn count_out(&self, block: Block) -> usize {
209 self.live_out[block.index()].len()
210 }
211
212 pub fn through(&self, func: &Func, block: Block, mut at: impl FnMut(Inst, &LiveHere<'_>)) {
219 let mut set = self.live_out[block.index()].clone();
220 walk(func, block, &mut set, |inst, set, _| at(inst, &LiveHere { set }));
221 }
222
223 pub fn changes(&self, func: &Func, block: Block, mut at: impl FnMut(Inst, &Change)) {
232 let mut set = self.live_out[block.index()].clone();
233 walk(func, block, &mut set, |inst, _, change| at(inst, change));
234 }
235}
236
237#[derive(Debug, Default)]
242pub struct Change {
243 pub gone: Vec<Value>,
245 pub arrived: Vec<Value>,
247}
248
249#[derive(Debug)]
254pub struct LiveHere<'a> {
255 set: &'a Set,
256}
257
258impl LiveHere<'_> {
259 #[must_use]
261 pub fn contains(&self, value: Value) -> bool {
262 self.set.contains(value)
263 }
264
265 #[must_use]
267 pub fn len(&self) -> usize {
268 self.set.len()
269 }
270
271 #[must_use]
273 pub fn is_empty(&self) -> bool {
274 self.len() == 0
275 }
276
277 pub fn iter(&self) -> impl Iterator<Item = Value> + use<'_> {
279 self.set.iter()
280 }
281}
282
283fn walk(func: &Func, block: Block, set: &mut Set, mut at: impl FnMut(Inst, &Set, &Change)) {
290 let mut change = Change::default();
291 for this in func.insts_backwards(block) {
292 change.gone.clear();
293 change.arrived.clear();
294 let data = &func[this];
295 for result in data.results() {
296 if set.remove(result) {
297 change.gone.push(result);
298 }
299 }
300 for &arg in &func[data.args] {
301 if set.insert(arg) {
302 change.arrived.push(arg);
303 }
304 }
305 for call in func.successors(this) {
308 for &arg in &func[call.args] {
309 if set.insert(arg) {
310 change.arrived.push(arg);
311 }
312 }
313 }
314 at(this, set, &change);
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use rucc_base::Interner;
321 use rucc_ir::{Block, Builder, Flags, Func, Opcode, Signature, Type};
322
323 use super::Liveness;
324 use crate::cfg::Cfg;
325
326 const I32: Type = Type::int(32);
327
328 fn blank(count: usize) -> (Func, Vec<Block>) {
329 let mut names = Interner::new();
330 let mut func = Func::new(names.intern("f"), Signature::new());
331 let blocks: Vec<Block> = (0..count).map(|_| func.create_block()).collect();
332 (func, blocks)
333 }
334
335 fn liveness(func: &Func) -> (Cfg, Liveness) {
336 let cfg = Cfg::new(func);
337 let live = Liveness::of(func, &cfg);
338 (cfg, live)
339 }
340
341 #[test]
342 fn a_value_made_and_read_in_one_block_never_crosses_an_edge() {
343 let (mut func, blocks) = blank(1);
344 let mut build = Builder::new(&mut func, blocks[0]);
345 let one = build.iconst(I32, 1);
346 let two = build.iconst(I32, 2);
347 let sum = build.binary(Opcode::Add, one, two, Flags::NONE);
348 build.ret(&[sum]);
349
350 let (_, live) = liveness(&func);
351 assert_eq!(live.count_in(blocks[0]), 0);
352 assert_eq!(live.count_out(blocks[0]), 0);
353 }
354
355 #[test]
356 fn a_value_read_in_a_later_block_is_live_on_the_edge_between_them() {
357 let (mut func, blocks) = blank(2);
358 let mut build = Builder::new(&mut func, blocks[0]);
359 let kept = build.iconst(I32, 7);
360 build.jump(blocks[1], &[]);
361 let mut build = Builder::new(&mut func, blocks[1]);
362 build.ret(&[kept]);
363
364 let (_, live) = liveness(&func);
365 assert!(live.is_live_out(blocks[0], kept), "it is read after the branch");
366 assert!(live.is_live_in(blocks[1], kept), "and it has to arrive there to be read");
367 assert!(!live.is_live_in(blocks[0], kept), "it does not exist before it is made");
368 }
369
370 #[test]
371 fn a_value_passed_on_the_branch_is_used_by_the_branch_and_not_by_the_block_it_arrives_at() {
372 let (mut func, blocks) = blank(2);
376 let param = func.append_param(blocks[1], I32);
377 let mut build = Builder::new(&mut func, blocks[0]);
378 let sent = build.iconst(I32, 7);
379 build.jump(blocks[1], &[sent]);
380 let mut build = Builder::new(&mut func, blocks[1]);
381 build.ret(&[param]);
382
383 let (_, live) = liveness(&func);
384 let mut at_the_jump = false;
387 live.through(&func, blocks[0], |inst, here| {
388 if func[inst].opcode == Opcode::Jump {
389 at_the_jump = here.contains(sent);
390 }
391 });
392 assert!(at_the_jump, "the branch uses it");
393 assert!(!live.is_live_out(blocks[0], sent), "and it does not survive the edge");
394 assert!(!live.is_live_in(blocks[1], param), "a parameter is defined by arriving");
395 assert!(!live.is_live_in(blocks[1], sent), "nor does it arrive under its own name");
396 assert_eq!(live.count_in(blocks[1]), 0);
397 }
398
399 #[test]
400 fn a_value_read_on_one_arm_only_is_live_on_that_arm_and_not_the_other() {
401 let (mut func, blocks) = blank(4);
402 let mut build = Builder::new(&mut func, blocks[0]);
403 let kept = build.iconst(I32, 7);
404 let cond = build.iconst(Type::I1, 1);
405 build.br_if(cond, blocks[1], &[], blocks[2], &[]);
406 let mut build = Builder::new(&mut func, blocks[1]);
407 build.jump(blocks[3], &[]);
408 let mut build = Builder::new(&mut func, blocks[2]);
409 build.ret(&[kept]);
410 let mut build = Builder::new(&mut func, blocks[3]);
411 build.ret(&[]);
412
413 let (_, live) = liveness(&func);
414 assert!(live.is_live_out(blocks[0], kept), "one arm reads it, so it survives the branch");
415 assert!(live.is_live_in(blocks[2], kept));
416 assert!(!live.is_live_in(blocks[1], kept), "this arm never mentions it");
417 }
418
419 #[test]
420 fn a_value_read_after_the_loop_stays_live_all_the_way_round_it() {
421 let (mut func, blocks) = blank(3);
425 let mut build = Builder::new(&mut func, blocks[0]);
426 let kept = build.iconst(I32, 7);
427 let cond = build.iconst(Type::I1, 1);
428 build.jump(blocks[1], &[]);
429 let mut build = Builder::new(&mut func, blocks[1]);
430 build.br_if(cond, blocks[1], &[], blocks[2], &[]);
431 let mut build = Builder::new(&mut func, blocks[2]);
432 build.ret(&[kept]);
433
434 let (_, live) = liveness(&func);
435 assert!(live.is_live_in(blocks[1], kept), "it has to survive the loop to be read after it");
436 assert!(live.is_live_out(blocks[1], kept), "including round the back edge");
437 assert!(live.is_live_in(blocks[2], kept));
438 }
439
440 #[test]
441 fn nothing_is_live_in_a_block_control_never_reaches() {
442 let (mut func, blocks) = blank(2);
443 let mut build = Builder::new(&mut func, blocks[0]);
444 let kept = build.iconst(I32, 7);
445 build.ret(&[kept]);
446 let mut build = Builder::new(&mut func, blocks[1]);
447 build.ret(&[]);
448
449 let (cfg, live) = liveness(&func);
450 assert!(!cfg.reaches(blocks[1]));
451 assert_eq!(live.count_in(blocks[1]), 0);
452 assert_eq!(live.count_out(blocks[1]), 0);
453 }
454
455 #[test]
456 fn the_walk_through_a_block_says_what_is_live_before_each_instruction() {
457 let (mut func, blocks) = blank(2);
458 let mut build = Builder::new(&mut func, blocks[0]);
459 let one = build.iconst(I32, 1);
460 let two = build.iconst(I32, 2);
461 let sum = build.binary(Opcode::Add, one, two, Flags::NONE);
462 let jump = build.jump(blocks[1], &[sum]);
463 let param = func.append_param(blocks[1], I32);
464 let mut build = Builder::new(&mut func, blocks[1]);
465 build.ret(&[param]);
466
467 let (_, live) = liveness(&func);
468 let mut counts = Vec::new();
469 live.through(&func, blocks[0], |inst, here| counts.push((inst, here.len())));
470 assert_eq!(counts.len(), 4);
473 assert_eq!(counts[0], (jump, 1));
474 assert_eq!(counts[1].1, 2, "the add's two operands");
475 assert_eq!(counts[2].1, 1);
476 assert_eq!(counts[3].1, 0);
477 assert!(counts[0].1 <= counts[1].1, "the sum replaces the two it was made from");
478 }
479
480 #[test]
481 fn a_value_that_is_its_own_operand_stays_live_across_the_instruction_that_redefines_nothing() {
482 let (mut func, blocks) = blank(1);
485 let mut build = Builder::new(&mut func, blocks[0]);
486 let start = build.iconst(I32, 1);
487 let doubled = build.binary(Opcode::Add, start, start, Flags::NONE);
488 build.ret(&[doubled]);
489
490 let (_, live) = liveness(&func);
491 let mut most = 0;
492 live.through(&func, blocks[0], |_, here| most = most.max(here.len()));
493 assert_eq!(most, 1, "one value used twice is one value");
494 }
495}