]>
Commit | Line | Data |
---|---|---|
a2a8927a XL |
1 | use std::borrow::Cow; |
2 | ||
3 | use rustc_middle::mir::{self, Body, MirPhase}; | |
4 | use rustc_middle::ty::TyCtxt; | |
5 | use rustc_session::Session; | |
6 | ||
7 | use crate::{validate, MirPass}; | |
8 | ||
9 | /// Just like `MirPass`, except it cannot mutate `Body`. | |
10 | pub trait MirLint<'tcx> { | |
11 | fn name(&self) -> Cow<'_, str> { | |
12 | let name = std::any::type_name::<Self>(); | |
13 | if let Some(tail) = name.rfind(':') { | |
14 | Cow::from(&name[tail + 1..]) | |
15 | } else { | |
16 | Cow::from(name) | |
17 | } | |
18 | } | |
19 | ||
20 | fn is_enabled(&self, _sess: &Session) -> bool { | |
21 | true | |
22 | } | |
23 | ||
24 | fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>); | |
25 | } | |
26 | ||
27 | /// An adapter for `MirLint`s that implements `MirPass`. | |
28 | #[derive(Debug, Clone)] | |
29 | pub struct Lint<T>(pub T); | |
30 | ||
31 | impl<'tcx, T> MirPass<'tcx> for Lint<T> | |
32 | where | |
33 | T: MirLint<'tcx>, | |
34 | { | |
35 | fn name(&self) -> Cow<'_, str> { | |
36 | self.0.name() | |
37 | } | |
38 | ||
39 | fn is_enabled(&self, sess: &Session) -> bool { | |
40 | self.0.is_enabled(sess) | |
41 | } | |
42 | ||
43 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | |
44 | self.0.run_lint(tcx, body) | |
45 | } | |
46 | ||
47 | fn is_mir_dump_enabled(&self) -> bool { | |
48 | false | |
49 | } | |
50 | } | |
51 | ||
52 | pub struct WithMinOptLevel<T>(pub u32, pub T); | |
53 | ||
54 | impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T> | |
55 | where | |
56 | T: MirPass<'tcx>, | |
57 | { | |
58 | fn name(&self) -> Cow<'_, str> { | |
59 | self.1.name() | |
60 | } | |
61 | ||
62 | fn is_enabled(&self, sess: &Session) -> bool { | |
63 | sess.mir_opt_level() >= self.0 as usize | |
64 | } | |
65 | ||
66 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | |
67 | self.1.run_pass(tcx, body) | |
68 | } | |
69 | ||
70 | fn phase_change(&self) -> Option<MirPhase> { | |
71 | self.1.phase_change() | |
72 | } | |
73 | } | |
74 | ||
75 | pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) { | |
76 | let start_phase = body.phase; | |
77 | let mut cnt = 0; | |
78 | ||
79 | let validate = tcx.sess.opts.debugging_opts.validate_mir; | |
80 | ||
81 | if validate { | |
82 | validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase)); | |
83 | } | |
84 | ||
85 | for pass in passes { | |
86 | if !pass.is_enabled(&tcx.sess) { | |
87 | continue; | |
88 | } | |
89 | ||
90 | let name = pass.name(); | |
91 | let dump_enabled = pass.is_mir_dump_enabled(); | |
92 | ||
93 | if dump_enabled { | |
94 | dump_mir(tcx, body, start_phase, &name, cnt, false); | |
95 | } | |
96 | ||
97 | pass.run_pass(tcx, body); | |
98 | ||
99 | if dump_enabled { | |
100 | dump_mir(tcx, body, start_phase, &name, cnt, true); | |
101 | cnt += 1; | |
102 | } | |
103 | ||
104 | if let Some(new_phase) = pass.phase_change() { | |
105 | if body.phase >= new_phase { | |
106 | panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); | |
107 | } | |
108 | ||
109 | body.phase = new_phase; | |
110 | } | |
111 | ||
112 | if validate { | |
113 | validate_body(tcx, body, format!("after pass {}", pass.name())); | |
114 | } | |
115 | } | |
116 | ||
5e7ed085 | 117 | if validate || body.phase == MirPhase::Optimized { |
a2a8927a XL |
118 | validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase)); |
119 | } | |
120 | } | |
121 | ||
122 | pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { | |
123 | validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body); | |
124 | } | |
125 | ||
126 | pub fn dump_mir<'tcx>( | |
127 | tcx: TyCtxt<'tcx>, | |
128 | body: &Body<'tcx>, | |
129 | phase: MirPhase, | |
130 | pass_name: &str, | |
131 | cnt: usize, | |
132 | is_after: bool, | |
133 | ) { | |
134 | let phase_index = phase as u32; | |
135 | ||
136 | mir::dump_mir( | |
137 | tcx, | |
138 | Some(&format_args!("{:03}-{:03}", phase_index, cnt)), | |
139 | pass_name, | |
140 | if is_after { &"after" } else { &"before" }, | |
141 | body, | |
142 | |_, _| Ok(()), | |
143 | ); | |
144 | } |