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) {
66 let at = value.index();
67 self.words[at / 64] |= 1 << (at % 64);
68 }
69
70 fn remove(&mut self, value: Value) {
71 let at = value.index();
72 self.words[at / 64] &= !(1 << (at % 64));
73 }
74
75 fn union_with(&mut self, other: &Self) -> bool {
77 let mut changed = false;
78 for (mine, theirs) in self.words.iter_mut().zip(&other.words) {
79 let before = *mine;
80 *mine |= theirs;
81 changed |= *mine != before;
82 }
83 changed
84 }
85
86 fn len(&self) -> usize {
87 self.words.iter().map(|word| word.count_ones() as usize).sum()
88 }
89
90 fn iter(&self) -> impl Iterator<Item = Value> + use<'_> {
91 self.words.iter().enumerate().flat_map(|(at, &word)| {
92 (0..64)
93 .filter(move |bit| word & (1 << bit) != 0)
94 .map(move |bit| Value::new((at * 64 + bit) as u32))
95 })
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct Liveness {
106 live_in: Vec<Set>,
107 live_out: Vec<Set>,
108}
109
110impl Liveness {
111 #[must_use]
113 pub fn of(func: &Func, cfg: &Cfg) -> Self {
114 let blocks = cfg.capacity();
115 let values = func.counts().values;
116 let empty = Set::with_room_for(values);
117 let mut live_in = vec![empty.clone(); blocks];
118 let mut live_out = vec![empty; blocks];
119
120 let order: Vec<Block> = cfg.postorder().to_vec();
123 let mut again = true;
124 while again {
125 again = false;
126 for &block in &order {
127 let mut out = Set::with_room_for(values);
128 for &successor in cfg.successors(block) {
129 out.union_with(&live_in[successor.index()]);
130 }
131 let mut set = out.clone();
132 walk(func, block, &mut set, |_, _| {});
133 for ¶m in &func[block].params {
134 set.remove(param);
135 }
136 again |= live_out[block.index()].union_with(&out);
137 again |= live_in[block.index()].union_with(&set);
138 }
139 }
140
141 Self { live_in, live_out }
142 }
143
144 pub fn live_in(&self, block: Block) -> impl Iterator<Item = Value> + use<'_> {
146 self.live_in[block.index()].iter()
147 }
148
149 pub fn live_out(&self, block: Block) -> impl Iterator<Item = Value> + use<'_> {
151 self.live_out[block.index()].iter()
152 }
153
154 #[must_use]
156 pub fn is_live_in(&self, block: Block, value: Value) -> bool {
157 self.live_in[block.index()].contains(value)
158 }
159
160 #[must_use]
162 pub fn is_live_out(&self, block: Block, value: Value) -> bool {
163 self.live_out[block.index()].contains(value)
164 }
165
166 #[must_use]
168 pub fn count_in(&self, block: Block) -> usize {
169 self.live_in[block.index()].len()
170 }
171
172 #[must_use]
174 pub fn count_out(&self, block: Block) -> usize {
175 self.live_out[block.index()].len()
176 }
177
178 pub fn through(&self, func: &Func, block: Block, mut at: impl FnMut(Inst, &LiveHere<'_>)) {
185 let mut set = self.live_out[block.index()].clone();
186 walk(func, block, &mut set, |inst, set| at(inst, &LiveHere { set }));
187 }
188}
189
190#[derive(Debug)]
195pub struct LiveHere<'a> {
196 set: &'a Set,
197}
198
199impl LiveHere<'_> {
200 #[must_use]
202 pub fn contains(&self, value: Value) -> bool {
203 self.set.contains(value)
204 }
205
206 #[must_use]
208 pub fn len(&self) -> usize {
209 self.set.len()
210 }
211
212 #[must_use]
214 pub fn is_empty(&self) -> bool {
215 self.len() == 0
216 }
217
218 pub fn iter(&self) -> impl Iterator<Item = Value> + use<'_> {
220 self.set.iter()
221 }
222}
223
224fn walk(func: &Func, block: Block, set: &mut Set, mut at: impl FnMut(Inst, &Set)) {
231 for this in func.insts_backwards(block) {
232 let data = &func[this];
233 for result in data.results() {
234 set.remove(result);
235 }
236 for &arg in &func[data.args] {
237 set.insert(arg);
238 }
239 for call in func.successors(this) {
242 for &arg in &func[call.args] {
243 set.insert(arg);
244 }
245 }
246 at(this, set);
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use rucc_base::Interner;
253 use rucc_ir::{Block, Builder, Flags, Func, Opcode, Signature, Type};
254
255 use super::Liveness;
256 use crate::cfg::Cfg;
257
258 const I32: Type = Type::int(32);
259
260 fn blank(count: usize) -> (Func, Vec<Block>) {
261 let mut names = Interner::new();
262 let mut func = Func::new(names.intern("f"), Signature::new());
263 let blocks: Vec<Block> = (0..count).map(|_| func.create_block()).collect();
264 (func, blocks)
265 }
266
267 fn liveness(func: &Func) -> (Cfg, Liveness) {
268 let cfg = Cfg::new(func);
269 let live = Liveness::of(func, &cfg);
270 (cfg, live)
271 }
272
273 #[test]
274 fn a_value_made_and_read_in_one_block_never_crosses_an_edge() {
275 let (mut func, blocks) = blank(1);
276 let mut build = Builder::new(&mut func, blocks[0]);
277 let one = build.iconst(I32, 1);
278 let two = build.iconst(I32, 2);
279 let sum = build.binary(Opcode::Add, one, two, Flags::NONE);
280 build.ret(&[sum]);
281
282 let (_, live) = liveness(&func);
283 assert_eq!(live.count_in(blocks[0]), 0);
284 assert_eq!(live.count_out(blocks[0]), 0);
285 }
286
287 #[test]
288 fn a_value_read_in_a_later_block_is_live_on_the_edge_between_them() {
289 let (mut func, blocks) = blank(2);
290 let mut build = Builder::new(&mut func, blocks[0]);
291 let kept = build.iconst(I32, 7);
292 build.jump(blocks[1], &[]);
293 let mut build = Builder::new(&mut func, blocks[1]);
294 build.ret(&[kept]);
295
296 let (_, live) = liveness(&func);
297 assert!(live.is_live_out(blocks[0], kept), "it is read after the branch");
298 assert!(live.is_live_in(blocks[1], kept), "and it has to arrive there to be read");
299 assert!(!live.is_live_in(blocks[0], kept), "it does not exist before it is made");
300 }
301
302 #[test]
303 fn a_value_passed_on_the_branch_is_used_by_the_branch_and_not_by_the_block_it_arrives_at() {
304 let (mut func, blocks) = blank(2);
308 let param = func.append_param(blocks[1], I32);
309 let mut build = Builder::new(&mut func, blocks[0]);
310 let sent = build.iconst(I32, 7);
311 build.jump(blocks[1], &[sent]);
312 let mut build = Builder::new(&mut func, blocks[1]);
313 build.ret(&[param]);
314
315 let (_, live) = liveness(&func);
316 let mut at_the_jump = false;
319 live.through(&func, blocks[0], |inst, here| {
320 if func[inst].opcode == Opcode::Jump {
321 at_the_jump = here.contains(sent);
322 }
323 });
324 assert!(at_the_jump, "the branch uses it");
325 assert!(!live.is_live_out(blocks[0], sent), "and it does not survive the edge");
326 assert!(!live.is_live_in(blocks[1], param), "a parameter is defined by arriving");
327 assert!(!live.is_live_in(blocks[1], sent), "nor does it arrive under its own name");
328 assert_eq!(live.count_in(blocks[1]), 0);
329 }
330
331 #[test]
332 fn a_value_read_on_one_arm_only_is_live_on_that_arm_and_not_the_other() {
333 let (mut func, blocks) = blank(4);
334 let mut build = Builder::new(&mut func, blocks[0]);
335 let kept = build.iconst(I32, 7);
336 let cond = build.iconst(Type::I1, 1);
337 build.br_if(cond, blocks[1], &[], blocks[2], &[]);
338 let mut build = Builder::new(&mut func, blocks[1]);
339 build.jump(blocks[3], &[]);
340 let mut build = Builder::new(&mut func, blocks[2]);
341 build.ret(&[kept]);
342 let mut build = Builder::new(&mut func, blocks[3]);
343 build.ret(&[]);
344
345 let (_, live) = liveness(&func);
346 assert!(live.is_live_out(blocks[0], kept), "one arm reads it, so it survives the branch");
347 assert!(live.is_live_in(blocks[2], kept));
348 assert!(!live.is_live_in(blocks[1], kept), "this arm never mentions it");
349 }
350
351 #[test]
352 fn a_value_read_after_the_loop_stays_live_all_the_way_round_it() {
353 let (mut func, blocks) = blank(3);
357 let mut build = Builder::new(&mut func, blocks[0]);
358 let kept = build.iconst(I32, 7);
359 let cond = build.iconst(Type::I1, 1);
360 build.jump(blocks[1], &[]);
361 let mut build = Builder::new(&mut func, blocks[1]);
362 build.br_if(cond, blocks[1], &[], blocks[2], &[]);
363 let mut build = Builder::new(&mut func, blocks[2]);
364 build.ret(&[kept]);
365
366 let (_, live) = liveness(&func);
367 assert!(live.is_live_in(blocks[1], kept), "it has to survive the loop to be read after it");
368 assert!(live.is_live_out(blocks[1], kept), "including round the back edge");
369 assert!(live.is_live_in(blocks[2], kept));
370 }
371
372 #[test]
373 fn nothing_is_live_in_a_block_control_never_reaches() {
374 let (mut func, blocks) = blank(2);
375 let mut build = Builder::new(&mut func, blocks[0]);
376 let kept = build.iconst(I32, 7);
377 build.ret(&[kept]);
378 let mut build = Builder::new(&mut func, blocks[1]);
379 build.ret(&[]);
380
381 let (cfg, live) = liveness(&func);
382 assert!(!cfg.reaches(blocks[1]));
383 assert_eq!(live.count_in(blocks[1]), 0);
384 assert_eq!(live.count_out(blocks[1]), 0);
385 }
386
387 #[test]
388 fn the_walk_through_a_block_says_what_is_live_before_each_instruction() {
389 let (mut func, blocks) = blank(2);
390 let mut build = Builder::new(&mut func, blocks[0]);
391 let one = build.iconst(I32, 1);
392 let two = build.iconst(I32, 2);
393 let sum = build.binary(Opcode::Add, one, two, Flags::NONE);
394 let jump = build.jump(blocks[1], &[sum]);
395 let param = func.append_param(blocks[1], I32);
396 let mut build = Builder::new(&mut func, blocks[1]);
397 build.ret(&[param]);
398
399 let (_, live) = liveness(&func);
400 let mut counts = Vec::new();
401 live.through(&func, blocks[0], |inst, here| counts.push((inst, here.len())));
402 assert_eq!(counts.len(), 4);
405 assert_eq!(counts[0], (jump, 1));
406 assert_eq!(counts[1].1, 2, "the add's two operands");
407 assert_eq!(counts[2].1, 1);
408 assert_eq!(counts[3].1, 0);
409 assert!(counts[0].1 <= counts[1].1, "the sum replaces the two it was made from");
410 }
411
412 #[test]
413 fn a_value_that_is_its_own_operand_stays_live_across_the_instruction_that_redefines_nothing() {
414 let (mut func, blocks) = blank(1);
417 let mut build = Builder::new(&mut func, blocks[0]);
418 let start = build.iconst(I32, 1);
419 let doubled = build.binary(Opcode::Add, start, start, Flags::NONE);
420 build.ret(&[doubled]);
421
422 let (_, live) = liveness(&func);
423 let mut most = 0;
424 live.through(&func, blocks[0], |_, here| most = most.max(here.len()));
425 assert_eq!(most, 1, "one value used twice is one value");
426 }
427}