]>
Commit | Line | Data |
---|---|---|
a2a8927a XL |
1 | use std::borrow::Cow; |
2 | ||
f2b60f7d | 3 | use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; |
a2a8927a XL |
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 | } | |
a2a8927a XL |
69 | } |
70 | ||
f2b60f7d FG |
71 | /// Run the sequence of passes without validating the MIR after each pass. The MIR is still |
72 | /// validated at the end. | |
73 | pub fn run_passes_no_validate<'tcx>( | |
74 | tcx: TyCtxt<'tcx>, | |
75 | body: &mut Body<'tcx>, | |
76 | passes: &[&dyn MirPass<'tcx>], | |
2b03887a | 77 | phase_change: Option<MirPhase>, |
f2b60f7d | 78 | ) { |
2b03887a | 79 | run_passes_inner(tcx, body, passes, phase_change, false); |
f2b60f7d FG |
80 | } |
81 | ||
2b03887a FG |
82 | /// The optional `phase_change` is applied after executing all the passes, if present |
83 | pub fn run_passes<'tcx>( | |
84 | tcx: TyCtxt<'tcx>, | |
85 | body: &mut Body<'tcx>, | |
86 | passes: &[&dyn MirPass<'tcx>], | |
87 | phase_change: Option<MirPhase>, | |
88 | ) { | |
89 | run_passes_inner(tcx, body, passes, phase_change, true); | |
f2b60f7d FG |
90 | } |
91 | ||
92 | fn run_passes_inner<'tcx>( | |
93 | tcx: TyCtxt<'tcx>, | |
94 | body: &mut Body<'tcx>, | |
95 | passes: &[&dyn MirPass<'tcx>], | |
2b03887a | 96 | phase_change: Option<MirPhase>, |
f2b60f7d FG |
97 | validate_each: bool, |
98 | ) { | |
f2b60f7d | 99 | let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; |
064997fb | 100 | let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; |
04454e1e | 101 | trace!(?overridden_passes); |
a2a8927a | 102 | |
a2a8927a | 103 | for pass in passes { |
a2a8927a | 104 | let name = pass.name(); |
04454e1e | 105 | |
f2b60f7d FG |
106 | let overridden = |
107 | overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| { | |
108 | trace!( | |
109 | pass = %name, | |
110 | "{} as requested by flag", | |
111 | if *polarity { "Running" } else { "Not running" }, | |
112 | ); | |
113 | *polarity | |
114 | }); | |
2b03887a FG |
115 | if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) { |
116 | continue; | |
117 | } | |
118 | ||
119 | let dump_enabled = pass.is_mir_dump_enabled(); | |
a2a8927a XL |
120 | |
121 | if dump_enabled { | |
2b03887a | 122 | dump_mir_for_pass(tcx, body, &name, false); |
f2b60f7d | 123 | } |
2b03887a FG |
124 | if validate { |
125 | validate_body(tcx, body, format!("before pass {}", name)); | |
a2a8927a | 126 | } |
a2a8927a | 127 | |
2b03887a FG |
128 | pass.run_pass(tcx, body); |
129 | ||
130 | if dump_enabled { | |
131 | dump_mir_for_pass(tcx, body, &name, true); | |
a2a8927a | 132 | } |
a2a8927a | 133 | if validate { |
f2b60f7d | 134 | validate_body(tcx, body, format!("after pass {}", name)); |
a2a8927a | 135 | } |
2b03887a FG |
136 | |
137 | body.pass_count += 1; | |
138 | } | |
139 | ||
140 | if let Some(new_phase) = phase_change { | |
141 | if body.phase >= new_phase { | |
142 | panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); | |
143 | } | |
144 | ||
145 | body.phase = new_phase; | |
146 | ||
147 | dump_mir_for_phase_change(tcx, body); | |
148 | if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { | |
149 | validate_body(tcx, body, format!("after phase change to {}", new_phase)); | |
150 | } | |
151 | ||
152 | body.pass_count = 1; | |
a2a8927a | 153 | } |
a2a8927a XL |
154 | } |
155 | ||
156 | pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) { | |
157 | validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body); | |
158 | } | |
159 | ||
2b03887a | 160 | pub fn dump_mir_for_pass<'tcx>( |
a2a8927a XL |
161 | tcx: TyCtxt<'tcx>, |
162 | body: &Body<'tcx>, | |
a2a8927a | 163 | pass_name: &str, |
a2a8927a XL |
164 | is_after: bool, |
165 | ) { | |
2b03887a | 166 | let phase_index = body.phase.phase_index(); |
a2a8927a XL |
167 | |
168 | mir::dump_mir( | |
169 | tcx, | |
2b03887a | 170 | Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)), |
a2a8927a XL |
171 | pass_name, |
172 | if is_after { &"after" } else { &"before" }, | |
173 | body, | |
174 | |_, _| Ok(()), | |
175 | ); | |
176 | } | |
2b03887a FG |
177 | |
178 | pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { | |
179 | let phase_index = body.phase.phase_index(); | |
180 | ||
181 | mir::dump_mir( | |
182 | tcx, | |
183 | Some(&format_args!("{:03}-000", phase_index)), | |
184 | &format!("{}", body.phase), | |
185 | &"after", | |
186 | body, | |
187 | |_, _| Ok(()), | |
188 | ) | |
189 | } |