rapx/analysis/utils/
show_mir.rs

1use crate::analysis::utils::fn_info::*;
2use colorful::{Color, Colorful};
3use rustc_hir::def_id::DefId;
4use rustc_middle::mir::{
5    BasicBlockData, BasicBlocks, Body, LocalDecl, LocalDecls, Operand, Rvalue, Statement,
6    StatementKind, Terminator, TerminatorKind,
7};
8use rustc_middle::ty::{self, TyCtxt, TyKind};
9
10const NEXT_LINE: &str = "\n";
11const PADDING: &str = "    ";
12const EXPLAIN: &str = " @ ";
13
14// This trait is a wrapper towards std::Display or std::Debug, and is to resolve orphan restrictions.
15pub trait Display {
16    fn display(&self) -> String;
17}
18
19impl<'tcx> Display for Terminator<'tcx> {
20    fn display(&self) -> String {
21        let mut s = String::new();
22        s += &format!("{}{:?}{}", PADDING, self.kind, self.kind.display());
23        s
24    }
25}
26
27impl<'tcx> Display for TerminatorKind<'tcx> {
28    fn display(&self) -> String {
29        let mut s = String::new();
30        s += EXPLAIN;
31        match &self {
32            TerminatorKind::Goto { .. } => s += "Goto",
33            TerminatorKind::SwitchInt { .. } => s += "SwitchInt",
34            TerminatorKind::Return => s += "Return",
35            TerminatorKind::Unreachable => s += "Unreachable",
36            TerminatorKind::Drop { .. } => s += "Drop",
37            TerminatorKind::Assert { .. } => s += "Assert",
38            TerminatorKind::Yield { .. } => s += "Yield",
39            TerminatorKind::FalseEdge { .. } => s += "FalseEdge",
40            TerminatorKind::FalseUnwind { .. } => s += "FalseUnwind",
41            TerminatorKind::InlineAsm { .. } => s += "InlineAsm",
42            TerminatorKind::UnwindResume => s += "UnwindResume",
43            TerminatorKind::UnwindTerminate(..) => s += "UnwindTerminate",
44            TerminatorKind::CoroutineDrop => s += "CoroutineDrop",
45            TerminatorKind::Call { func, .. } => match func {
46                Operand::Constant(constant) => match constant.ty().kind() {
47                    ty::FnDef(id, ..) => {
48                        s += &format!("Call: FnDid: {}", id.index.as_usize()).as_str()
49                    }
50                    _ => (),
51                },
52                _ => (),
53            },
54            TerminatorKind::TailCall { .. } => todo!(),
55        };
56        s
57    }
58}
59
60impl<'tcx> Display for Statement<'tcx> {
61    fn display(&self) -> String {
62        let mut s = String::new();
63        s += &format!("{}{:?}{}", PADDING, self.kind, self.kind.display());
64        s
65    }
66}
67
68impl<'tcx> Display for StatementKind<'tcx> {
69    fn display(&self) -> String {
70        let mut s = String::new();
71        s += EXPLAIN;
72        match &self {
73            StatementKind::Assign(assign) => {
74                s += &format!("{:?}={:?}{}", assign.0, assign.1, assign.1.display());
75            }
76            StatementKind::FakeRead(..) => s += "FakeRead",
77            StatementKind::SetDiscriminant { .. } => s += "SetDiscriminant",
78            StatementKind::StorageLive(..) => s += "StorageLive",
79            StatementKind::StorageDead(..) => s += "StorageDead",
80            StatementKind::Retag(..) => s += "Retag",
81            StatementKind::AscribeUserType(..) => s += "AscribeUserType",
82            StatementKind::Coverage(..) => s += "Coverage",
83            StatementKind::Nop => s += "Nop",
84            StatementKind::PlaceMention(..) => s += "PlaceMention",
85            StatementKind::Intrinsic(..) => s += "Intrinsic",
86            StatementKind::ConstEvalCounter => s += "ConstEvalCounter",
87            _ => todo!(),
88        }
89        s
90    }
91}
92
93impl<'tcx> Display for Rvalue<'tcx> {
94    fn display(&self) -> String {
95        let mut s = String::new();
96        s += EXPLAIN;
97        match self {
98            Rvalue::Use(..) => s += "Use",
99            Rvalue::Repeat(..) => s += "Repeat",
100            Rvalue::Ref(..) => s += "Ref",
101            Rvalue::ThreadLocalRef(..) => s += "ThreadLocalRef",
102            Rvalue::Cast(..) => s += "Cast",
103            Rvalue::BinaryOp(..) => s += "BinaryOp",
104            Rvalue::NullaryOp(..) => s += "NullaryOp",
105            Rvalue::UnaryOp(..) => s += "UnaryOp",
106            Rvalue::Discriminant(..) => s += "Discriminant",
107            Rvalue::Aggregate(..) => s += "Aggregate",
108            Rvalue::ShallowInitBox(..) => s += "ShallowInitBox",
109            Rvalue::CopyForDeref(..) => s += "CopyForDeref",
110            Rvalue::RawPtr(_, _) => s += "RawPtr",
111            _ => todo!(),
112        }
113        s
114    }
115}
116
117impl<'tcx> Display for BasicBlocks<'tcx> {
118    fn display(&self) -> String {
119        let mut s = String::new();
120        for (index, bb) in self.iter().enumerate() {
121            s += &format!(
122                "bb {} {{{}{}}}{}",
123                index,
124                NEXT_LINE,
125                bb.display(),
126                NEXT_LINE
127            );
128        }
129        s
130    }
131}
132
133impl<'tcx> Display for BasicBlockData<'tcx> {
134    fn display(&self) -> String {
135        let mut s = String::new();
136        s += &format!("CleanUp: {}{}", self.is_cleanup, NEXT_LINE);
137        for stmt in self.statements.iter() {
138            s += &format!("{}{}", stmt.display(), NEXT_LINE);
139        }
140        s += &format!(
141            "{}{}",
142            self.terminator.clone().unwrap().display(),
143            NEXT_LINE
144        );
145        s
146    }
147}
148
149impl<'tcx> Display for LocalDecls<'tcx> {
150    fn display(&self) -> String {
151        let mut s = String::new();
152        for (index, ld) in self.iter().enumerate() {
153            s += &format!("_{}: {} {}", index, ld.display(), NEXT_LINE);
154        }
155        s
156    }
157}
158
159impl<'tcx> Display for LocalDecl<'tcx> {
160    fn display(&self) -> String {
161        let mut s = String::new();
162        s += &format!("{}{}", EXPLAIN, self.ty.kind().display());
163        s
164    }
165}
166
167impl<'tcx> Display for Body<'tcx> {
168    fn display(&self) -> String {
169        let mut s = String::new();
170        s += &self.local_decls.display();
171        s += &self.basic_blocks.display();
172        s
173    }
174}
175
176impl<'tcx> Display for TyKind<'tcx> {
177    fn display(&self) -> String {
178        let mut s = String::new();
179        s += &format!("{:?}", self);
180        s
181    }
182}
183
184impl Display for DefId {
185    fn display(&self) -> String {
186        format!("{:?}", self)
187    }
188}
189
190pub struct ShowMir<'tcx> {
191    pub tcx: TyCtxt<'tcx>,
192}
193
194// #[inline(always)]
195pub fn display_mir(did: DefId, body: &Body) {
196    rap_info!("{}", did.display().color(Color::LightRed));
197    rap_info!("{}", body.local_decls.display().color(Color::Green));
198    rap_info!(
199        "{}",
200        body.basic_blocks.display().color(Color::LightGoldenrod2a)
201    );
202}
203
204impl<'tcx> ShowMir<'tcx> {
205    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
206        Self { tcx }
207    }
208
209    pub fn start(&mut self) {
210        rap_info!("Show MIR");
211        let mir_keys = self.tcx.mir_keys(());
212        for each_mir in mir_keys {
213            let def_id = each_mir.to_def_id();
214            let body = self.tcx.instance_mir(ty::InstanceKind::Item(def_id));
215            display_mir(def_id, body);
216        }
217    }
218
219    pub fn start_generate_dot(&mut self) {
220        rap_info!("Generate MIR DOT");
221        std::process::Command::new("mkdir")
222            .args(["MIR_dot_graph"])
223            .output()
224            .expect("Failed to create directory");
225
226        let mir_keys = self.tcx.mir_keys(());
227        for each_mir in mir_keys {
228            let def_id = each_mir.to_def_id();
229            let _ = generate_mir_cfg_dot(self.tcx, def_id, &Vec::new());
230        }
231    }
232}