rapx/analysis/core/dataflow/
mod.rs

1pub mod debug;
2pub mod default;
3pub mod graph;
4
5use std::{
6    collections::{HashMap, HashSet},
7    fmt::{self, Debug, Display},
8    fs::File,
9    io::Write,
10    process::Command,
11};
12
13use crate::{analysis::Analysis, utils::source::get_fn_name_byid};
14
15use rustc_hir::{def::DefKind, def_id::DefId};
16use rustc_index::IndexVec;
17use rustc_middle::{
18    mir::{Body, Local},
19    ty::TyCtxt,
20};
21use rustc_span::Span;
22
23pub type Arg2Ret = IndexVec<Local, bool>;
24pub type Arg2RetMap = HashMap<DefId, IndexVec<Local, bool>>;
25#[derive(Clone)]
26pub struct DataFlowGraph {
27    pub nodes: GraphNodes,
28    pub edges: GraphEdges,
29    pub param_ret_deps: Arg2Ret,
30}
31pub type DataFlowGraphMap = HashMap<DefId, DataFlowGraph>;
32
33pub struct Arg2RetWrapper(pub Arg2Ret);
34pub struct Arg2RetMapWrapper(pub Arg2RetMap);
35pub struct DataFlowGraphWrapper(pub DataFlowGraph);
36pub struct DataFlowGraphMapWrapper(pub HashMap<DefId, DataFlowGraph>);
37
38pub type EdgeIdx = usize;
39pub type GraphNodes = IndexVec<Local, GraphNode>;
40pub type GraphEdges = IndexVec<EdgeIdx, GraphEdge>;
41
42#[derive(Clone, Debug)]
43pub struct GraphEdge {
44    pub src: Local,
45    pub dst: Local,
46    pub op: EdgeOp,
47    pub seq: usize,
48}
49
50#[derive(Clone, Debug)]
51pub struct GraphNode {
52    pub ops: Vec<NodeOp>,
53    pub span: Span, //the corresponding code span
54    pub seq: usize, //the sequence number, edges with the same seq number are added in the same batch within a statement or terminator
55    pub out_edges: Vec<EdgeIdx>,
56    pub in_edges: Vec<EdgeIdx>,
57}
58
59/// This trait provides features related to dataflow analysis.
60pub trait DataFlowAnalysis: Analysis {
61    /// The function returns the dataflow graph for the given function id.
62    fn get_fn_dataflow(&self, def_id: DefId) -> Option<DataFlowGraph>;
63
64    /// The function returns the dataflow graph for all functions.
65    fn get_all_dataflow(&self) -> DataFlowGraphMap;
66
67    /// If there is a dataflow between `local1` and `local2` within the function specified by
68    /// `def_id`, the function returns ture; otherwise, it returns false.
69    fn has_flow_between(&self, def_id: DefId, local1: Local, local2: Local) -> bool;
70
71    /// The function returns a set of Locals that are equivelent to the given `local`.
72    fn collect_equivalent_locals(&self, def_id: DefId, local: Local) -> HashSet<Local>;
73
74    /// The function returns an IndexVec of whether the returned Local depends on the parameter Local.
75    fn get_fn_arg2ret(&self, def_id: DefId) -> Arg2Ret;
76
77    /// The function returns the dataflow between the arguments and return value for all functions
78    fn get_all_arg2ret(&self) -> Arg2RetMap;
79}
80
81impl fmt::Display for Arg2RetWrapper {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        let arg2ret: &Arg2Ret = &self.0;
84        for (local, depends) in arg2ret.iter_enumerated() {
85            if local.as_u32() > 0 {
86                if *depends {
87                    writeln!(f, "Argument {:?} ---> Return value _0", local)?;
88                }
89            }
90        }
91        Ok(())
92    }
93}
94
95impl fmt::Display for Arg2RetMapWrapper {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        writeln!(f, "=== Print dataflow analysis results ===")?;
98        for (def_id, arg2ret) in &self.0 {
99            let fn_name = get_fn_name_byid(def_id);
100            writeln!(
101                f,
102                "Function: {:?}\n{}",
103                fn_name,
104                Arg2RetWrapper(arg2ret.clone())
105            )?;
106        }
107        Ok(())
108    }
109}
110
111impl Display for DataFlowGraphWrapper {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        let graph = &self.0;
114        write!(
115            f,
116            "Graph statistics: {} nodes, {} edges.\n",
117            graph.nodes.len(),
118            graph.edges.len()
119        )?;
120        if graph.param_ret_deps.len() > 1 {
121            write!(f, "Return value dependencies: \n")?;
122        }
123        for (node_idx, deps) in graph.param_ret_deps.iter_enumerated() {
124            if node_idx.as_u32() > 0 {
125                if *deps {
126                    write!(f, "Argument {:?} ---> Return value _0.\n", node_idx)?;
127                }
128            }
129        }
130
131        for (node_idx, node) in graph.nodes.iter_enumerated() {
132            let node_adj: Vec<Local> = node
133                .out_edges
134                .iter()
135                .map(|edge_idx| graph.edges[*edge_idx].dst)
136                .collect();
137            if !node_adj.is_empty() {
138                write!(f, "Node {:?} -> Node {:?}\n", node_idx, node_adj)?;
139            }
140        }
141        Ok(())
142    }
143}
144
145impl Debug for DataFlowGraphWrapper {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        writeln!(f, "Nodes:")?;
148        for node in &self.0.nodes {
149            writeln!(f, "  {:?}", node)?;
150        }
151        writeln!(f, "Edges:")?;
152        for edge in &self.0.edges {
153            writeln!(f, "  {:?}", edge)?;
154        }
155        Ok(())
156    }
157}
158
159impl Display for DataFlowGraphMapWrapper {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        writeln!(f, "===Print dataflow analysis resuts===")?;
162        for (def_id, dfg) in &self.0 {
163            let fn_name = get_fn_name_byid(def_id);
164            writeln!(
165                f,
166                "Function: {:?}\n{}",
167                fn_name,
168                DataFlowGraphWrapper(dfg.clone())
169            )?;
170        }
171        Ok(())
172    }
173}
174
175impl Debug for DataFlowGraphMapWrapper {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        for (def_id, dfg) in &self.0 {
178            writeln!(
179                f,
180                "DefId: {:?}\n{:?}",
181                def_id,
182                DataFlowGraphWrapper(dfg.clone())
183            )?;
184        }
185        Ok(())
186    }
187}
188
189#[derive(Clone, Debug)]
190pub enum NodeOp {
191    //warning: the fields are related to the version of the backend rustc version
192    Nop,
193    Err,
194    Const(String, String),
195    //Rvalue
196    Use,
197    Repeat,
198    Ref,
199    ThreadLocalRef,
200    AddressOf,
201    Len,
202    Cast,
203    BinaryOp,
204    CheckedBinaryOp,
205    NullaryOp,
206    UnaryOp,
207    Discriminant,
208    Aggregate(AggKind),
209    ShallowInitBox,
210    CopyForDeref,
211    RawPtr,
212    //TerminatorKind
213    Call(DefId),
214    CallOperand, // the first in_edge is the func
215}
216
217#[derive(Clone, Debug)]
218pub enum EdgeOp {
219    Nop,
220    //Operand
221    Move,
222    Copy,
223    Const,
224    //Mutability
225    Immut,
226    Mut,
227    //Place
228    Deref,
229    Field(String),
230    Downcast(String),
231    Index,
232    ConstIndex,
233    SubSlice,
234    SubType,
235}
236
237#[derive(Clone, Copy, Debug)]
238pub enum AggKind {
239    Array,
240    Tuple,
241    Adt(DefId),
242    Closure(DefId),
243    Coroutine(DefId),
244    RawPtr,
245}