rapx/analysis/rcanary/ranalyzer/
order.rs

1use rustc_middle::mir::TerminatorKind;
2
3use std::collections::BinaryHeap;
4//use stopwatch::Stopwatch;
5
6use super::super::ranalyzer::{FlowAnalysis, NodeOrder};
7use super::super::RcxMut;
8use super::mir_body;
9
10impl<'tcx, 'a> FlowAnalysis<'tcx, 'a> {
11    pub fn order(&mut self) {
12        // Get the Global TyCtxt from rustc
13        // Grasp all mir Keys defined in current crate
14
15        //let mut sw = Stopwatch::start_new();
16
17        let tcx = self.tcx();
18        let mir_keys = tcx.mir_keys(());
19
20        for each_mir in mir_keys {
21            // Get the defid of current crate and get mir Body through this id
22            let def_id = each_mir.to_def_id();
23            let body = mir_body(tcx, def_id);
24
25            let mut path = NodeOrder::new(body);
26            let mut lev: Vec<usize> = vec![0; body.basic_blocks.len()];
27
28            path.collect_edges(&mut lev);
29            path.topo_order(&mut lev);
30            self.rcx_mut()
31                .mir_graph_mut()
32                .insert(def_id, path.graph_mut().clone());
33        }
34
35        //self.rcx_mut().add_time_build(sw.elapsed_ms());
36        //sw.stop();
37    }
38}
39
40impl<'tcx> NodeOrder<'tcx> {
41    /// !Note: this function does not collect the edges that belongs to unwind paths.
42    pub(crate) fn collect_edges(&mut self, lev: &mut Vec<usize>) {
43        let bbs = &self.body().basic_blocks;
44        for (block, data) in bbs.iter().enumerate() {
45            let mut result: Vec<usize> = vec![];
46            match &data.terminator().kind {
47                TerminatorKind::Goto { target } => result.push(target.as_usize()),
48                TerminatorKind::SwitchInt { targets, .. } => {
49                    for bb in targets.all_targets() {
50                        result.push(bb.as_usize());
51                    }
52                }
53                TerminatorKind::Return => (),
54                TerminatorKind::Unreachable => (),
55                TerminatorKind::Drop { target, .. } => result.push(target.as_usize()),
56                TerminatorKind::Assert { target, .. } => result.push(target.as_usize()),
57                TerminatorKind::Yield { .. } => (),
58                TerminatorKind::FalseEdge { .. } => (),
59                TerminatorKind::FalseUnwind { .. } => (),
60                TerminatorKind::InlineAsm { .. } => (),
61                TerminatorKind::UnwindResume => (),
62                TerminatorKind::UnwindTerminate(..) => (),
63                TerminatorKind::CoroutineDrop => (),
64                TerminatorKind::Call { target, .. } => {
65                    // We check the destination due to following case.
66                    // Terminator { source_info: SourceInfo { span: src/main.rs:100:9: 100:35 (#7), scope: scope[0] },
67                    // kind: core::panicking::panic(const "assertion failed: index <= self.len") -> bb24 },
68                    // destination -> None, cleanup -> Some(bb24)
69                    match target {
70                        Some(t) => result.push(t.as_usize()),
71                        None => (),
72                    }
73                }
74                TerminatorKind::TailCall { .. } => todo!(),
75            }
76            // Update the lev for generating topo order.
77            for index in result.iter() {
78                lev[*index] = lev[*index] + 1;
79                self.graph_mut().get_pre_mut()[*index].push(block);
80            }
81            self.graph_mut().get_edges_mut()[block] = result;
82        }
83    }
84
85    pub(crate) fn topo_order(&mut self, lev: &mut Vec<usize>) {
86        let mut q: BinaryHeap<usize> = BinaryHeap::new();
87        q.push(0);
88        while !q.is_empty() {
89            let top = q.pop().unwrap();
90            self.graph_mut().get_topo_mut().push(top);
91            for cnt in 0..self.graph().e[top].len() {
92                let next = self.graph().e[top][cnt];
93                lev[next] = lev[next] - 1;
94                if lev[next] == 0 {
95                    q.push(next);
96                }
97            }
98        }
99    }
100}