cairo_lang_lowering/analysis/
def_site.rs1use std::fmt;
9
10use crate::analysis::DefLocation;
11use crate::analysis::core::{DataflowAnalyzer, Direction, Edge, StatementLocation};
12use crate::analysis::forward::ForwardDataflowAnalysis;
13use crate::{BlockEnd, BlockId, Lowered, Statement};
14
15pub struct DefSites(pub Vec<Option<DefLocation>>);
20
21impl std::ops::Deref for DefSites {
22 type Target = [Option<DefLocation>];
23 fn deref(&self) -> &Self::Target {
24 &self.0
25 }
26}
27
28impl fmt::Debug for DefSites {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 let mut list = f.debug_list();
31 for (idx, def) in self.0.iter().enumerate() {
32 match def {
33 Some(loc) => list.entry(&format_args!("v{idx}: {loc:?}")),
34 None => list.entry(&format_args!("v{idx}: undefined")),
35 };
36 }
37 list.finish()
38 }
39}
40
41pub struct DefSiteAnalysis<'db, 'a> {
43 lowered: &'a Lowered<'db>,
44 def_sites: Vec<Option<DefLocation>>,
48}
49
50impl DefSiteAnalysis<'_, '_> {
51 pub fn analyze(lowered: &Lowered<'_>) -> DefSites {
60 let analyzer = DefSiteAnalysis { lowered, def_sites: vec![None; lowered.variables.len()] };
61 let mut fwd = ForwardDataflowAnalysis::new(lowered, analyzer);
62 fwd.run();
63 DefSites(fwd.analyzer.def_sites)
64 }
65}
66
67impl<'db, 'a> DataflowAnalyzer<'db, 'a> for DefSiteAnalysis<'db, 'a> {
68 type Info = ();
69 const DIRECTION: Direction = Direction::Forward;
70
71 fn initial_info(&mut self, _block_id: BlockId, _block_end: &'a BlockEnd<'db>) -> Self::Info {
72 for ¶m in &self.lowered.parameters {
73 self.def_sites[param.index()] = Some(DefLocation::BlockEntry(BlockId::root()));
74 }
75 }
76
77 fn merge(
78 &mut self,
79 _lowered: &Lowered<'db>,
80 _statement_location: StatementLocation,
81 _info1: Self::Info,
82 _info2: Self::Info,
83 ) -> Self::Info {
84 }
85
86 fn transfer_stmt(
87 &mut self,
88 _info: &mut Self::Info,
89 statement_location: StatementLocation,
90 stmt: &'a Statement<'db>,
91 ) {
92 for &output in stmt.outputs() {
93 self.def_sites[output.index()] = Some(DefLocation::Statement(statement_location));
94 }
95 }
96
97 fn transfer_edge(&mut self, _info: &Self::Info, edge: &Edge<'db, 'a>) -> Self::Info {
98 match edge {
99 Edge::Goto { target, remapping } => {
100 for (&dst, _) in remapping.iter() {
101 self.def_sites[dst.index()] = Some(DefLocation::BlockEntry(*target));
102 }
103 }
104 Edge::MatchArm { arm, .. } => {
105 for &var in &arm.var_ids {
106 self.def_sites[var.index()] = Some(DefLocation::BlockEntry(arm.block_id));
107 }
108 }
109 Edge::Return { .. } | Edge::Panic { .. } => {}
110 }
111 }
112}