cairo_lang_lowering/analysis/
dominator.rs1use std::fmt;
8
9use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
10use itertools::Itertools;
11
12use crate::analysis::core::{DataflowAnalyzer, Direction, StatementLocation};
13use crate::analysis::forward::ForwardDataflowAnalysis;
14use crate::{Block, BlockEnd, BlockId, Lowered};
15
16pub struct Dominators {
18 per_block: Vec<OrderedHashSet<BlockId>>,
20}
21
22impl Dominators {
23 pub fn analyze(lowered: &Lowered<'_>) -> Self {
25 let mut fwd = ForwardDataflowAnalysis::new(lowered, DominatorAnalyzer);
26 let per_block = fwd.run().into_iter().map(|opt| opt.unwrap_or_default()).collect();
27 Dominators { per_block }
28 }
29
30 pub fn dominates(&self, a: BlockId, b: BlockId) -> bool {
32 self.per_block[b.0].contains(&a)
33 }
34
35 pub fn dominators_of(&self, block: BlockId) -> &OrderedHashSet<BlockId> {
37 &self.per_block[block.0]
38 }
39}
40
41impl fmt::Debug for Dominators {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 let mut list = f.debug_list();
44 for (i, doms) in self.per_block.iter().enumerate() {
45 if doms.is_empty() {
46 list.entry(&format_args!("blk{i}: unreachable"));
47 } else {
48 let names = doms
49 .iter()
50 .map(|b| b.0)
51 .sorted()
52 .format_with(", ", |d, f| f(&format_args!("blk{d}")));
53 list.entry(&format_args!("blk{i}: {{{names}}}"));
54 }
55 }
56 list.finish()
57 }
58}
59
60struct DominatorAnalyzer;
62
63impl<'db, 'a> DataflowAnalyzer<'db, 'a> for DominatorAnalyzer {
64 type Info = OrderedHashSet<BlockId>;
65 const DIRECTION: Direction = Direction::Forward;
66
67 fn initial_info(&mut self, _block_id: BlockId, _block_end: &'a BlockEnd<'db>) -> Self::Info {
68 OrderedHashSet::default()
69 }
70
71 fn merge(
72 &mut self,
73 _lowered: &Lowered<'db>,
74 _statement_location: StatementLocation,
75 info1: Self::Info,
76 info2: Self::Info,
77 ) -> Self::Info {
78 let mut info1 = info1;
81 info1.retain(|id| info2.contains(id));
82 info1
83 }
84
85 fn transfer_block(&mut self, info: &mut Self::Info, block_id: BlockId, _block: &'a Block<'db>) {
86 info.insert(block_id);
88 }
89}
90
91#[cfg(test)]
92#[path = "dominator_test.rs"]
93mod dominator_test;