rapx/analysis/core/
range_analysis.rs

1#![allow(non_snake_case)]
2#![allow(unused_variables)]
3#![allow(dead_code)]
4
5use crate::analysis::core::range_analysis::domain::domain::ConstConvert;
6use crate::analysis::core::range_analysis::domain::domain::IntervalArithmetic;
7use crate::analysis::core::range_analysis::domain::range::Range;
8use crate::rap_info;
9
10pub mod PassRunner;
11pub mod SSA;
12pub mod domain;
13use crate::analysis::Analysis;
14use domain::ConstraintGraph::ConstraintGraph;
15use rustc_data_structures::fx::FxHashMap;
16use rustc_hir::def::DefKind;
17use rustc_hir::def_id::DefId;
18use rustc_hir::def_id::LocalDefId;
19use rustc_middle::mir::Body;
20use rustc_middle::mir::Local;
21use rustc_middle::ty::TyCtxt;
22use std::{
23    collections::{HashMap, HashSet},
24    fmt::Debug,
25};
26use PassRunner::*;
27pub struct SSATrans<'tcx> {
28    pub tcx: TyCtxt<'tcx>,
29    pub debug: bool,
30}
31
32impl<'tcx> SSATrans<'tcx> {
33    pub fn new(tcx: TyCtxt<'tcx>, debug: bool) -> Self {
34        Self { tcx: tcx, debug }
35    }
36
37    pub fn start(&mut self) {
38        for local_def_id in self.tcx.iter_local_def_id() {
39            if matches!(self.tcx.def_kind(local_def_id), DefKind::Fn) {
40                if self.tcx.hir_maybe_body_owned_by(local_def_id).is_some() {
41                    if let Some(def_id) = self
42                        .tcx
43                        .hir_body_owners()
44                        .find(|id| self.tcx.def_path_str(*id) == "main")
45                    {
46                        if let Some(ssa_def_id) =
47                            self.tcx.hir_crate_items(()).free_items().find(|id| {
48                                let hir_id = id.hir_id();
49                                if let Some(ident_name) = self.tcx.hir_opt_name(hir_id) {
50                                    ident_name.to_string() == "SSAstmt"
51                                } else {
52                                    false
53                                }
54                            })
55                        {
56                            let ssa_def_id = ssa_def_id.owner_id.to_def_id();
57                            if let Some(essa_def_id) =
58                                self.tcx.hir_crate_items(()).free_items().find(|id| {
59                                    let hir_id = id.hir_id();
60                                    if let Some(ident_name) = self.tcx.hir_opt_name(hir_id) {
61                                        ident_name.to_string() == "ESSAstmt"
62                                    } else {
63                                        false
64                                    }
65                                })
66                            {
67                                let essa_def_id = essa_def_id.owner_id.to_def_id();
68                                self.analyze_mir(self.tcx, def_id, ssa_def_id, essa_def_id);
69                            }
70                        }
71                    }
72                }
73            }
74        }
75    }
76    fn analyze_mir(
77        &mut self,
78        tcx: TyCtxt<'tcx>,
79        def_id: LocalDefId,
80        ssa_def_id: DefId,
81        essa_def_id: DefId,
82    ) {
83        let mut body = tcx.optimized_mir(def_id).clone();
84        {
85            let body_mut_ref: &mut Body<'tcx> = unsafe { &mut *(&mut body as *mut Body<'tcx>) };
86            let mut passrunner = PassRunner::PassRunner::new(tcx);
87            passrunner.run_pass(body_mut_ref, ssa_def_id, essa_def_id);
88            // passrunner.print_diff(body_mut_ref);
89            let essa_mir_string = passrunner.get_final_ssa_as_string(body_mut_ref);
90            // rap_info!("final SSA {:?}\n", &essa_mir_string);
91            rap_info!("ssa lvalue check {:?}", lvalue_check(&essa_mir_string));
92        }
93    }
94}
95
96pub trait RangeAnalysis<'tcx, T: IntervalArithmetic + ConstConvert + Debug>: Analysis {
97    fn get_fn_range(&self, def_id: DefId) -> Option<HashMap<Local, Range<T>>>;
98    fn get_all_fn_ranges(&self) -> FxHashMap<DefId, HashMap<Local, Range<T>>>;
99    fn get_fn_local_range(&self, def_id: DefId, local: Local) -> Option<Range<T>>;
100}
101
102pub struct DefaultRange<'tcx, T: IntervalArithmetic + ConstConvert + Debug> {
103    pub tcx: TyCtxt<'tcx>,
104    pub debug: bool,
105    pub ssa_def_id: Option<DefId>,
106    pub essa_def_id: Option<DefId>,
107    pub final_vars: FxHashMap<DefId, HashMap<Local, Range<T>>>,
108    pub ssa_locals_mapping: FxHashMap<DefId, HashMap<Local, HashSet<Local>>>,
109}
110impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> Analysis for DefaultRange<'tcx, T>
111where
112    T: IntervalArithmetic + ConstConvert + Debug,
113{
114    fn name(&self) -> &'static str {
115        "Range Analysis"
116    }
117
118    fn run(&mut self) {
119        for local_def_id in self.tcx.iter_local_def_id() {
120            if matches!(self.tcx.def_kind(local_def_id), DefKind::Fn) {
121                if self.tcx.hir_maybe_body_owned_by(local_def_id).is_some() {
122                    rap_info!(
123                        "Analyzing function: {}",
124                        self.tcx.def_path_str(local_def_id)
125                    );
126                    self.analyze_mir(local_def_id);
127                }
128            }
129        }
130    }
131
132    fn reset(&mut self) {
133        self.final_vars.clear();
134        self.ssa_locals_mapping.clear();
135    }
136}
137
138impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> RangeAnalysis<'tcx, T>
139    for DefaultRange<'tcx, T>
140where
141    T: IntervalArithmetic + ConstConvert + Debug,
142{
143    fn get_fn_range(&self, def_id: DefId) -> Option<HashMap<Local, Range<T>>> {
144        self.final_vars.get(&def_id).cloned()
145    }
146
147    fn get_all_fn_ranges(&self) -> FxHashMap<DefId, HashMap<Local, Range<T>>> {
148        // REFACTOR: Using `.clone()` is more explicit that a copy is being returned.
149        self.final_vars.clone()
150    }
151
152    // REFACTOR: This lookup is now much more efficient.
153    fn get_fn_local_range(&self, def_id: DefId, local: Local) -> Option<Range<T>> {
154        self.final_vars
155            .get(&def_id)
156            .and_then(|vars| vars.get(&local).cloned())
157    }
158}
159
160impl<'tcx, T> DefaultRange<'tcx, T>
161where
162    T: IntervalArithmetic + ConstConvert + Debug,
163{
164    pub fn new(tcx: TyCtxt<'tcx>, debug: bool) -> Self {
165        let mut ssa_id = None;
166        let mut essa_id = None;
167
168        if let Some(ssa_def_id) = tcx.hir_crate_items(()).free_items().find(|id| {
169            let hir_id = id.hir_id();
170            if let Some(ident_name) = tcx.hir_opt_name(hir_id) {
171                ident_name.to_string() == "SSAstmt"
172            } else {
173                false
174            }
175        }) {
176            ssa_id = Some(ssa_def_id.owner_id.to_def_id());
177            if let Some(essa_def_id) = tcx.hir_crate_items(()).free_items().find(|id| {
178                let hir_id = id.hir_id();
179                if let Some(ident_name) = tcx.hir_opt_name(hir_id) {
180                    ident_name.to_string() == "ESSAstmt"
181                } else {
182                    false
183                }
184            }) {
185                essa_id = Some(essa_def_id.owner_id.to_def_id());
186            }
187        }
188        Self {
189            tcx: tcx,
190            debug,
191            ssa_def_id: ssa_id,
192            essa_def_id: essa_id,
193            final_vars: HashMap::default(),
194            ssa_locals_mapping: HashMap::default(),
195        }
196    }
197
198    fn analyze_mir(&mut self, def_id: LocalDefId) {
199        let mut body = self.tcx.optimized_mir(def_id).clone();
200        {
201            let ssa_def_id = self.ssa_def_id.expect("SSA definition ID is not set");
202            let essa_def_id = self.essa_def_id.expect("ESSA definition ID is not set");
203
204            let body_mut_ref: &mut Body<'tcx> = unsafe { &mut *(&mut body as *mut Body<'tcx>) };
205            let mut passrunner = PassRunner::PassRunner::new(self.tcx);
206            passrunner.run_pass(body_mut_ref, ssa_def_id, essa_def_id);
207            // print_diff(tcx, body_mut_ref);
208            let mut cg: ConstraintGraph<'tcx, T> = ConstraintGraph::new(essa_def_id, ssa_def_id);
209            cg.build_graph(body_mut_ref);
210            cg.build_nuutila(false);
211            cg.find_intervals();
212            cg.rap_print_vars();
213            let (r#final, not_found) = cg.build_final_vars(&passrunner.locals_map);
214            cg.rap_print_final_vars();
215
216            self.ssa_locals_mapping
217                .insert(def_id.into(), passrunner.locals_map.clone());
218
219            let mut r_final = HashMap::default();
220
221            for (&place, varnode) in r#final.iter() {
222                r_final.insert(place.local, varnode.get_range().clone());
223            }
224            self.final_vars.insert(def_id.into(), r_final);
225        }
226    }
227}