1use rucc_ir::Func;
36
37use crate::predict::Callees;
38use crate::{
39 Cfg, ControlDependence, Dominators, Frequencies, Frontiers, Liveness, Loops, PostDominators,
40 Pressure,
41};
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub enum Analysis {
50 Cfg,
52 Dominators,
54 PostDominators,
56 Loops,
58 Frontiers,
60 ControlDependence,
62 Frequencies,
64 Liveness,
66 Pressure,
68}
69
70impl Analysis {
71 pub const EVERY: &'static [Analysis] = &[
73 Analysis::Cfg,
74 Analysis::Dominators,
75 Analysis::PostDominators,
76 Analysis::Loops,
77 Analysis::Frontiers,
78 Analysis::ControlDependence,
79 Analysis::Frequencies,
80 Analysis::Liveness,
81 Analysis::Pressure,
82 ];
83
84 #[must_use]
86 pub const fn name(self) -> &'static str {
87 match self {
88 Self::Cfg => "the control flow graph",
89 Self::Dominators => "the dominator tree",
90 Self::PostDominators => "the post-dominator tree",
91 Self::Loops => "the loop forest",
92 Self::Frontiers => "the dominance frontiers",
93 Self::ControlDependence => "the control dependence relation",
94 Self::Frequencies => "the block frequencies",
95 Self::Liveness => "the liveness",
96 Self::Pressure => "the register pressure",
97 }
98 }
99
100 #[must_use]
105 pub const fn needs(self) -> &'static [Analysis] {
106 match self {
107 Self::Cfg => &[],
108 Self::Dominators | Self::PostDominators => &[Analysis::Cfg],
109 Self::Loops | Self::Frontiers => &[Analysis::Cfg, Analysis::Dominators],
110 Self::ControlDependence => &[Analysis::Cfg, Analysis::PostDominators],
111 Self::Frequencies => &[Analysis::Cfg, Analysis::Dominators, Analysis::Loops],
112 Self::Liveness => &[Analysis::Cfg],
113 Self::Pressure => &[Analysis::Cfg, Analysis::Liveness],
114 }
115 }
116
117 const fn bit(self) -> u16 {
119 1 << (self as u16)
120 }
121}
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
131pub struct Preserved(u16);
132
133impl Preserved {
134 pub const ALL: Preserved = Preserved(u16::MAX);
136
137 pub const NONE: Preserved = Preserved(0);
139
140 #[must_use]
142 pub const fn and(self, analysis: Analysis) -> Self {
143 Self(self.0 | analysis.bit())
144 }
145
146 #[must_use]
152 pub const fn without(self, analysis: Analysis) -> Self {
153 Self(self.0 & !analysis.bit())
154 }
155
156 #[must_use]
158 pub const fn keeps(self, analysis: Analysis) -> bool {
159 self.0 & analysis.bit() != 0
160 }
161}
162
163#[derive(Clone, Debug, Default)]
168pub struct Analyses {
169 cfg: Option<Cfg>,
170 doms: Option<Dominators>,
171 post: Option<PostDominators>,
172 loops: Option<Loops>,
173 frontiers: Option<Frontiers>,
174 control: Option<ControlDependence>,
175 frequencies: Option<Frequencies>,
176 live: Option<Liveness>,
177 pressure: Option<Pressure>,
178}
179
180impl Analyses {
181 #[must_use]
183 pub fn new() -> Self {
184 Self::default()
185 }
186
187 pub fn cfg(&mut self, func: &Func) -> &Cfg {
189 self.cfg.get_or_insert_with(|| Cfg::new(func))
190 }
191
192 pub fn dominators(&mut self, func: &Func) -> &Dominators {
199 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
200 self.doms.get_or_insert_with(|| Dominators::new(cfg))
201 }
202
203 pub fn post_dominators(&mut self, func: &Func) -> &PostDominators {
210 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
211 self.post.get_or_insert_with(|| PostDominators::new(cfg))
212 }
213
214 pub fn loops(&mut self, func: &Func) -> &Loops {
216 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
217 let doms: &Dominators = self.doms.get_or_insert_with(|| Dominators::new(cfg));
218 self.loops.get_or_insert_with(|| Loops::new(cfg, doms))
219 }
220
221 pub fn frontiers(&mut self, func: &Func) -> &Frontiers {
223 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
224 let doms: &Dominators = self.doms.get_or_insert_with(|| Dominators::new(cfg));
225 self.frontiers.get_or_insert_with(|| Frontiers::new(cfg, doms))
226 }
227
228 pub fn control_dependence(&mut self, func: &Func) -> &ControlDependence {
234 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
235 let post: &PostDominators = self.post.get_or_insert_with(|| PostDominators::new(cfg));
236 self.control.get_or_insert_with(|| ControlDependence::new(cfg, post))
237 }
238
239 pub fn frequencies(&mut self, func: &Func) -> &Frequencies {
248 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
249 let doms: &Dominators = self.doms.get_or_insert_with(|| Dominators::new(cfg));
250 let loops: &Loops = self.loops.get_or_insert_with(|| Loops::new(cfg, doms));
251 self.frequencies
252 .get_or_insert_with(|| Frequencies::of(func, cfg, loops, &Callees::nothing()))
253 }
254
255 pub fn live(&mut self, func: &Func) -> &Liveness {
257 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
258 self.live.get_or_insert_with(|| Liveness::of(func, cfg))
259 }
260
261 pub fn pressure(&mut self, func: &Func) -> &Pressure {
268 let cfg: &Cfg = self.cfg.get_or_insert_with(|| Cfg::new(func));
269 let live: &Liveness = self.live.get_or_insert_with(|| Liveness::of(func, cfg));
270 self.pressure.get_or_insert_with(|| Pressure::of(func, cfg, live))
271 }
272
273 #[must_use]
279 pub fn holds(&self, analysis: Analysis) -> bool {
280 match analysis {
281 Analysis::Cfg => self.cfg.is_some(),
282 Analysis::Dominators => self.doms.is_some(),
283 Analysis::PostDominators => self.post.is_some(),
284 Analysis::Loops => self.loops.is_some(),
285 Analysis::Frontiers => self.frontiers.is_some(),
286 Analysis::ControlDependence => self.control.is_some(),
287 Analysis::Frequencies => self.frequencies.is_some(),
288 Analysis::Liveness => self.live.is_some(),
289 Analysis::Pressure => self.pressure.is_some(),
290 }
291 }
292
293 pub fn settle(&mut self, func: &Func, keeps: Preserved, check: bool) -> Vec<Analysis> {
305 let lied = if check { self.lies(func, keeps) } else { Vec::new() };
306 let mut keeps = keeps;
311 for &analysis in &lied {
312 keeps = keeps.without(analysis);
313 }
314 let mut alive = [false; Analysis::EVERY.len()];
319 for &analysis in Analysis::EVERY {
320 let kept =
321 keeps.keeps(analysis) && analysis.needs().iter().all(|&need| alive[need as usize]);
322 alive[analysis as usize] = kept;
323 if !kept {
324 self.drop(analysis);
325 }
326 }
327 lied
328 }
329
330 pub fn clear(&mut self) {
335 *self = Self::default();
336 }
337
338 fn drop(&mut self, analysis: Analysis) {
340 match analysis {
341 Analysis::Cfg => self.cfg = None,
342 Analysis::Dominators => self.doms = None,
343 Analysis::PostDominators => self.post = None,
344 Analysis::Loops => self.loops = None,
345 Analysis::Frontiers => self.frontiers = None,
346 Analysis::ControlDependence => self.control = None,
347 Analysis::Frequencies => self.frequencies = None,
348 Analysis::Liveness => self.live = None,
349 Analysis::Pressure => self.pressure = None,
350 }
351 }
352
353 fn lies(&self, func: &Func, keeps: Preserved) -> Vec<Analysis> {
360 let wanted: Vec<Analysis> = Analysis::EVERY
361 .iter()
362 .copied()
363 .filter(|&it| self.holds(it) && keeps.keeps(it))
364 .collect();
365 if wanted.is_empty() {
366 return Vec::new();
367 }
368 let cfg = Cfg::new(func);
371 let mut lied = Vec::new();
372 for analysis in wanted {
373 let same = match analysis {
374 Analysis::Cfg => self.cfg.as_ref() == Some(&cfg),
375 Analysis::Dominators => self.doms.as_ref() == Some(&Dominators::new(&cfg)),
376 Analysis::PostDominators => self.post.as_ref() == Some(&PostDominators::new(&cfg)),
377 Analysis::Loops => {
378 self.loops.as_ref() == Some(&Loops::new(&cfg, &Dominators::new(&cfg)))
379 }
380 Analysis::Frontiers => {
381 self.frontiers.as_ref() == Some(&Frontiers::new(&cfg, &Dominators::new(&cfg)))
382 }
383 Analysis::ControlDependence => {
384 self.control.as_ref()
385 == Some(&ControlDependence::new(&cfg, &PostDominators::new(&cfg)))
386 }
387 Analysis::Frequencies => {
388 let doms = Dominators::new(&cfg);
389 let loops = Loops::new(&cfg, &doms);
390 let now = Frequencies::of(func, &cfg, &loops, &Callees::nothing());
391 self.frequencies.as_ref() == Some(&now)
392 }
393 Analysis::Liveness => self.live.as_ref() == Some(&Liveness::of(func, &cfg)),
394 Analysis::Pressure => {
395 let live = Liveness::of(func, &cfg);
396 self.pressure.as_ref() == Some(&Pressure::of(func, &cfg, &live))
397 }
398 };
399 if !same {
400 lied.push(analysis);
401 }
402 }
403 lied
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use rucc_base::Interner;
410 use rucc_ir::{Block, Func, Signature};
411
412 use super::{Analyses, Analysis, Preserved};
413 use crate::testing::graph;
414
415 fn func() -> Func {
418 graph(&[&[1, 2], &[3], &[3], &[4, 1], &[]])
419 }
420
421 #[test]
422 fn an_analysis_is_built_out_of_ones_that_come_before_it() {
423 for &analysis in Analysis::EVERY {
426 for &need in analysis.needs() {
427 assert!(need < analysis, "{} is built out of a later analysis", analysis.name());
428 }
429 }
430 }
431
432 #[test]
433 fn every_analysis_is_in_the_list_once() {
434 for &analysis in Analysis::EVERY {
435 let found = Analysis::EVERY.iter().filter(|&&it| it == analysis).count();
436 assert_eq!(found, 1, "{} appears twice", analysis.name());
437 }
438 assert_eq!(Analysis::EVERY.len(), 9);
439 }
440
441 #[test]
442 fn all_keeps_everything_and_none_keeps_nothing() {
443 for &analysis in Analysis::EVERY {
444 assert!(Preserved::ALL.keeps(analysis));
445 assert!(!Preserved::NONE.keeps(analysis));
446 }
447 }
448
449 #[test]
450 fn a_named_set_holds_what_was_named_and_nothing_else() {
451 let keeps = Preserved::NONE.and(Analysis::Cfg).and(Analysis::Loops);
452 assert!(keeps.keeps(Analysis::Cfg));
453 assert!(keeps.keeps(Analysis::Loops));
454 assert!(!keeps.keeps(Analysis::Dominators));
455 assert!(!keeps.keeps(Analysis::PostDominators));
456 }
457
458 #[test]
459 fn nothing_is_computed_until_it_is_asked_for() {
460 let mut an = Analyses::new();
461 for &analysis in Analysis::EVERY {
462 assert!(!an.holds(analysis));
463 }
464 let func = func();
465 an.dominators(&func);
466 assert!(an.holds(Analysis::Cfg));
469 assert!(an.holds(Analysis::Dominators));
470 assert!(!an.holds(Analysis::Loops));
471 assert!(!an.holds(Analysis::PostDominators));
472 }
473
474 #[test]
475 fn asking_twice_gives_the_same_answer_and_the_second_one_is_free() {
476 let func = func();
477 let mut an = Analyses::new();
478 let first = an.cfg(&func).clone();
479 let second = an.cfg(&func);
480 assert_eq!(&first, second);
481 }
482
483 #[test]
484 fn the_loop_forest_pulls_in_what_it_is_built_out_of() {
485 let func = func();
486 let mut an = Analyses::new();
487 an.loops(&func);
488 assert!(an.holds(Analysis::Cfg));
489 assert!(an.holds(Analysis::Dominators));
490 assert!(an.holds(Analysis::Loops));
491 }
492
493 #[test]
494 fn preserving_everything_keeps_everything() {
495 let func = func();
496 let mut an = Analyses::new();
497 an.loops(&func);
498 an.frontiers(&func);
499 an.control_dependence(&func);
500 an.frequencies(&func);
501 an.pressure(&func);
502 assert!(an.settle(&func, Preserved::ALL, true).is_empty());
503 for &analysis in Analysis::EVERY {
504 assert!(an.holds(analysis), "{} was thrown away", analysis.name());
505 }
506 }
507
508 #[test]
509 fn the_pressure_falls_with_the_liveness_it_was_counted_from() {
510 let func = func();
511 let mut an = Analyses::new();
512 an.pressure(&func);
513 assert!(an.holds(Analysis::Liveness), "it had to be computed to count anything");
514 let keeps = Preserved::NONE.and(Analysis::Cfg).and(Analysis::Pressure);
515 an.settle(&func, keeps, false);
516 assert!(an.holds(Analysis::Cfg));
517 assert!(!an.holds(Analysis::Liveness));
518 assert!(!an.holds(Analysis::Pressure), "a count outlived what it counted");
519 }
520
521 #[test]
522 fn preserving_nothing_empties_the_cache() {
523 let func = func();
524 let mut an = Analyses::new();
525 an.loops(&func);
526 an.frontiers(&func);
527 an.control_dependence(&func);
528 an.settle(&func, Preserved::NONE, false);
529 for &analysis in Analysis::EVERY {
530 assert!(!an.holds(analysis), "{} outlived the pass", analysis.name());
531 }
532 }
533
534 #[test]
535 fn losing_the_graph_loses_what_was_built_on_it() {
536 let func = func();
537 let mut an = Analyses::new();
538 an.loops(&func);
539 an.post_dominators(&func);
540 let keeps = Preserved::NONE
544 .and(Analysis::Dominators)
545 .and(Analysis::PostDominators)
546 .and(Analysis::Loops);
547 an.settle(&func, keeps, false);
548 for &analysis in Analysis::EVERY {
549 assert!(!an.holds(analysis), "{} outlived the graph", analysis.name());
550 }
551 }
552
553 #[test]
554 fn losing_the_dominator_tree_loses_the_forest_and_leaves_the_graph() {
555 let func = func();
556 let mut an = Analyses::new();
557 an.loops(&func);
558 an.post_dominators(&func);
559 let keeps =
560 Preserved::NONE.and(Analysis::Cfg).and(Analysis::PostDominators).and(Analysis::Loops);
561 an.settle(&func, keeps, false);
562 assert!(an.holds(Analysis::Cfg));
563 assert!(an.holds(Analysis::PostDominators));
564 assert!(!an.holds(Analysis::Dominators), "the tree was not preserved");
565 assert!(!an.holds(Analysis::Loops), "the forest outlived the tree it needs");
566 }
567
568 #[test]
569 fn each_frontier_falls_with_the_tree_it_was_walked_on_and_not_the_other_one() {
570 let func = func();
574 let mut an = Analyses::new();
575 an.frontiers(&func);
576 an.control_dependence(&func);
577 let keeps = Preserved::NONE
578 .and(Analysis::Cfg)
579 .and(Analysis::Dominators)
580 .and(Analysis::Frontiers)
581 .and(Analysis::ControlDependence);
582 an.settle(&func, keeps, false);
583 assert!(an.holds(Analysis::Frontiers), "the frontier stands on a tree that stood");
584 assert!(!an.holds(Analysis::ControlDependence), "the post-dominator tree went with it");
585 }
586
587 #[test]
588 fn the_frequencies_fall_with_the_loop_forest_they_were_worked_out_from() {
589 let func = func();
590 let mut an = Analyses::new();
591 an.frequencies(&func);
592 for analysis in [Analysis::Cfg, Analysis::Dominators, Analysis::Loops] {
595 assert!(an.holds(analysis), "{} was not pulled in", analysis.name());
596 }
597 let keeps =
598 Preserved::NONE.and(Analysis::Cfg).and(Analysis::Dominators).and(Analysis::Frequencies);
599 an.settle(&func, keeps, false);
600 assert!(!an.holds(Analysis::Loops), "the forest was not preserved");
601 assert!(!an.holds(Analysis::Frequencies), "a frequency outlived the loop it counted");
602 }
603
604 #[test]
605 fn a_pass_that_says_it_kept_the_graph_and_moved_an_edge_is_caught() {
606 let mut func = func();
607 let mut an = Analyses::new();
608 an.loops(&func);
609 let block = Block::from_usize(3);
613 let term = func.terminator(block).expect("the helper gives every block a terminator");
614 func.remove_inst(term);
615 let mut build = rucc_ir::Builder::new(&mut func, block);
616 build.ret(&[]);
617 let lied = an.settle(&func, Preserved::ALL, true);
618 assert_eq!(lied, vec![Analysis::Cfg, Analysis::Dominators, Analysis::Loops]);
619 for &analysis in Analysis::EVERY {
622 assert!(!an.holds(analysis));
623 }
624 }
625
626 #[test]
627 fn a_lie_about_the_frontiers_is_caught_the_same_way() {
628 let mut func = func();
629 let mut an = Analyses::new();
630 an.frontiers(&func);
631 an.control_dependence(&func);
632 let block = Block::from_usize(3);
635 let term = func.terminator(block).expect("the helper gives every block a terminator");
636 func.remove_inst(term);
637 let mut build = rucc_ir::Builder::new(&mut func, block);
638 build.ret(&[]);
639 let lied = an.settle(&func, Preserved::ALL, true);
640 assert!(lied.contains(&Analysis::Frontiers));
641 assert!(lied.contains(&Analysis::ControlDependence));
642 }
643
644 #[test]
645 fn the_check_costs_nothing_when_it_is_off() {
646 let mut func = func();
647 let mut an = Analyses::new();
648 an.cfg(&func);
649 let block = Block::from_usize(3);
650 let term = func.terminator(block).expect("the helper gives every block a terminator");
651 func.remove_inst(term);
652 let mut build = rucc_ir::Builder::new(&mut func, block);
653 build.ret(&[]);
654 assert!(an.settle(&func, Preserved::ALL, false).is_empty());
655 assert!(an.holds(Analysis::Cfg));
658 }
659
660 #[test]
661 fn an_analysis_nobody_asked_for_is_not_checked() {
662 let func = func();
663 let mut an = Analyses::new();
664 assert!(an.settle(&func, Preserved::ALL, true).is_empty());
665 }
666
667 #[test]
668 fn a_declaration_has_analyses_like_anything_else() {
669 let mut names = Interner::new();
672 let func = Func::new(names.intern("declared"), Signature::new());
673 let mut an = Analyses::new();
674 assert!(an.cfg(&func).entry().is_none());
675 an.loops(&func);
676 an.post_dominators(&func);
677 assert!(an.settle(&func, Preserved::ALL, true).is_empty());
678 }
679
680 #[test]
681 fn clearing_takes_everything() {
682 let func = func();
683 let mut an = Analyses::new();
684 an.loops(&func);
685 an.clear();
686 for &analysis in Analysis::EVERY {
687 assert!(!an.holds(analysis));
688 }
689 }
690}