@@ -11,8 +11,13 @@ use rustc_middle::ty::query::Providers;
11
11
use rustc_middle:: ty:: steal:: Steal ;
12
12
use rustc_middle:: ty:: { self , TyCtxt , TypeFoldable } ;
13
13
use rustc_span:: { Span , Symbol } ;
14
- use std:: borrow:: Cow ;
15
14
15
+ #[ macro_use]
16
+ mod pass;
17
+
18
+ pub use self :: pass:: { MirPass , OptLevel , PassManager } ;
19
+
20
+ // Passes
16
21
pub mod add_call_guards;
17
22
pub mod add_moves_for_packed_drops;
18
23
pub mod add_retag;
@@ -134,82 +139,6 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> {
134
139
set
135
140
}
136
141
137
- /// Generates a default name for the pass based on the name of the
138
- /// type `T`.
139
- pub fn default_name < T : ?Sized > ( ) -> Cow < ' static , str > {
140
- let name = :: std:: any:: type_name :: < T > ( ) ;
141
- if let Some ( tail) = name. rfind ( ':' ) { Cow :: from ( & name[ tail + 1 ..] ) } else { Cow :: from ( name) }
142
- }
143
-
144
- /// A streamlined trait that you can implement to create a pass; the
145
- /// pass will be named after the type, and it will consist of a main
146
- /// loop that goes over each available MIR and applies `run_pass`.
147
- pub trait MirPass < ' tcx > {
148
- fn name ( & self ) -> Cow < ' _ , str > {
149
- default_name :: < Self > ( )
150
- }
151
-
152
- fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) ;
153
- }
154
-
155
- pub fn run_passes (
156
- tcx : TyCtxt < ' tcx > ,
157
- body : & mut Body < ' tcx > ,
158
- mir_phase : MirPhase ,
159
- passes : & [ & [ & dyn MirPass < ' tcx > ] ] ,
160
- ) {
161
- let phase_index = mir_phase. phase_index ( ) ;
162
- let validate = tcx. sess . opts . debugging_opts . validate_mir ;
163
-
164
- if body. phase >= mir_phase {
165
- return ;
166
- }
167
-
168
- if validate {
169
- validate:: Validator { when : format ! ( "input to phase {:?}" , mir_phase) , mir_phase }
170
- . run_pass ( tcx, body) ;
171
- }
172
-
173
- let mut index = 0 ;
174
- let mut run_pass = |pass : & dyn MirPass < ' tcx > | {
175
- let run_hooks = |body : & _ , index, is_after| {
176
- dump_mir:: on_mir_pass (
177
- tcx,
178
- & format_args ! ( "{:03}-{:03}" , phase_index, index) ,
179
- & pass. name ( ) ,
180
- body,
181
- is_after,
182
- ) ;
183
- } ;
184
- run_hooks ( body, index, false ) ;
185
- pass. run_pass ( tcx, body) ;
186
- run_hooks ( body, index, true ) ;
187
-
188
- if validate {
189
- validate:: Validator {
190
- when : format ! ( "after {} in phase {:?}" , pass. name( ) , mir_phase) ,
191
- mir_phase,
192
- }
193
- . run_pass ( tcx, body) ;
194
- }
195
-
196
- index += 1 ;
197
- } ;
198
-
199
- for pass_group in passes {
200
- for pass in * pass_group {
201
- run_pass ( * pass) ;
202
- }
203
- }
204
-
205
- body. phase = mir_phase;
206
-
207
- if mir_phase == MirPhase :: Optimization {
208
- validate:: Validator { when : format ! ( "end of phase {:?}" , mir_phase) , mir_phase }
209
- . run_pass ( tcx, body) ;
210
- }
211
- }
212
-
213
142
fn mir_const_qualif ( tcx : TyCtxt < ' _ > , def : ty:: WithOptConstParam < LocalDefId > ) -> ConstQualifs {
214
143
let const_kind = tcx. hir ( ) . body_const_context ( def. did ) ;
215
144
@@ -259,19 +188,15 @@ fn mir_const<'tcx>(
259
188
260
189
util:: dump_mir ( tcx, None , "mir_map" , & 0 , & body, |_, _| Ok ( ( ) ) ) ;
261
190
262
- run_passes (
263
- tcx,
264
- & mut body,
265
- MirPhase :: Const ,
266
- & [ & [
267
- // MIR-level lints.
268
- & check_packed_ref:: CheckPackedRef ,
269
- & check_const_item_mutation:: CheckConstItemMutation ,
270
- // What we need to do constant evaluation.
271
- & simplify:: SimplifyCfg :: new ( "initial" ) ,
272
- & rustc_peek:: SanityCheck ,
273
- ] ] ,
274
- ) ;
191
+ run_passes ! ( PassManager :: new( tcx, & mut body, MirPhase :: Const ) => [
192
+ // MIR-level lints.
193
+ check_packed_ref:: CheckPackedRef ,
194
+ check_const_item_mutation:: CheckConstItemMutation ,
195
+ // What we need to do constant evaluation.
196
+ simplify:: SimplifyCfg :: new( "initial" ) ,
197
+ rustc_peek:: SanityCheck ,
198
+ ] ) ;
199
+
275
200
tcx. alloc_steal_mir ( body)
276
201
}
277
202
@@ -301,20 +226,19 @@ fn mir_promoted(
301
226
}
302
227
body. required_consts = required_consts;
303
228
229
+ let mut promotion_passes = PassManager :: new ( tcx, & mut body, MirPhase :: ConstPromotion ) ;
230
+
304
231
let promote_pass = promote_consts:: PromoteTemps :: default ( ) ;
305
- let promote: & [ & dyn MirPass < ' tcx > ] = & [
306
- // What we need to run borrowck etc.
307
- & promote_pass,
308
- & simplify:: SimplifyCfg :: new ( "promote-consts" ) ,
309
- ] ;
310
-
311
- let opt_coverage: & [ & dyn MirPass < ' tcx > ] = if tcx. sess . opts . debugging_opts . instrument_coverage {
312
- & [ & instrument_coverage:: InstrumentCoverage ]
313
- } else {
314
- & [ ]
315
- } ;
232
+ run_passes ! ( promotion_passes => [
233
+ promote_pass,
234
+ simplify:: SimplifyCfg :: new( "promote-consts" ) ,
235
+ ] ) ;
236
+
237
+ if tcx. sess . opts . debugging_opts . instrument_coverage {
238
+ run_passes ! ( promotion_passes => [ instrument_coverage:: InstrumentCoverage ] ) ;
239
+ }
316
240
317
- run_passes ( tcx , & mut body , MirPhase :: ConstPromotion , & [ promote , opt_coverage ] ) ;
241
+ drop ( promotion_passes ) ;
318
242
319
243
let promoted = promote_pass. promoted_fragments . into_inner ( ) ;
320
244
( tcx. alloc_steal_mir ( body) , tcx. alloc_steal_promoted ( promoted) )
@@ -348,30 +272,28 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
348
272
fn run_post_borrowck_cleanup_passes < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
349
273
debug ! ( "post_borrowck_cleanup({:?})" , body. source. def_id( ) ) ;
350
274
351
- let post_borrowck_cleanup : & [ & dyn MirPass < ' tcx > ] = & [
275
+ run_passes ! ( PassManager :: new ( tcx , body , MirPhase :: DropLowering ) => [
352
276
// Remove all things only needed by analysis
353
- & no_landing_pads:: NoLandingPads :: new ( tcx) ,
354
- & simplify_branches:: SimplifyBranches :: new ( "initial" ) ,
355
- & remove_noop_landing_pads:: RemoveNoopLandingPads ,
356
- & cleanup_post_borrowck:: CleanupNonCodegenStatements ,
357
- & simplify:: SimplifyCfg :: new ( "early-opt" ) ,
277
+ no_landing_pads:: NoLandingPads :: new( tcx) ,
278
+ simplify_branches:: SimplifyBranches :: new( "initial" ) ,
279
+ remove_noop_landing_pads:: RemoveNoopLandingPads ,
280
+ cleanup_post_borrowck:: CleanupNonCodegenStatements ,
281
+ simplify:: SimplifyCfg :: new( "early-opt" ) ,
358
282
// These next passes must be executed together
359
- & add_call_guards:: CriticalCallEdges ,
360
- & elaborate_drops:: ElaborateDrops ,
361
- & no_landing_pads:: NoLandingPads :: new ( tcx) ,
283
+ add_call_guards:: CriticalCallEdges ,
284
+ elaborate_drops:: ElaborateDrops ,
285
+ no_landing_pads:: NoLandingPads :: new( tcx) ,
362
286
// AddMovesForPackedDrops needs to run after drop
363
287
// elaboration.
364
- & add_moves_for_packed_drops:: AddMovesForPackedDrops ,
288
+ add_moves_for_packed_drops:: AddMovesForPackedDrops ,
365
289
// `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
366
290
// but before optimizations begin.
367
- & add_retag:: AddRetag ,
368
- & simplify:: SimplifyCfg :: new ( "elaborate-drops" ) ,
291
+ add_retag:: AddRetag ,
292
+ simplify:: SimplifyCfg :: new( "elaborate-drops" ) ,
369
293
// `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
370
294
// and it can help optimizations.
371
- & deaggregator:: Deaggregator ,
372
- ] ;
373
-
374
- run_passes ( tcx, body, MirPhase :: DropLowering , & [ post_borrowck_cleanup] ) ;
295
+ deaggregator:: Deaggregator ,
296
+ ] ) ;
375
297
}
376
298
377
299
fn run_optimization_passes < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
@@ -380,80 +302,54 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
380
302
// Lowering generator control-flow and variables has to happen before we do anything else
381
303
// to them. We run some optimizations before that, because they may be harder to do on the state
382
304
// machine than on MIR with async primitives.
383
- let optimizations_with_generators: & [ & dyn MirPass < ' tcx > ] = & [
384
- & unreachable_prop:: UnreachablePropagation ,
385
- & uninhabited_enum_branching:: UninhabitedEnumBranching ,
386
- & simplify:: SimplifyCfg :: new ( "after-uninhabited-enum-branching" ) ,
387
- & inline:: Inline ,
388
- & generator:: StateTransform ,
389
- ] ;
390
-
391
- // Even if we don't do optimizations, we still have to lower generators for codegen.
392
- let no_optimizations_with_generators: & [ & dyn MirPass < ' tcx > ] = & [ & generator:: StateTransform ] ;
393
-
394
- // The main optimizations that we do on MIR.
395
- let optimizations: & [ & dyn MirPass < ' tcx > ] = & [
396
- & remove_unneeded_drops:: RemoveUnneededDrops ,
397
- & match_branches:: MatchBranchSimplification ,
398
- // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
399
- & multiple_return_terminators:: MultipleReturnTerminators ,
400
- & instcombine:: InstCombine ,
401
- & const_prop:: ConstProp ,
402
- & simplify_branches:: SimplifyBranches :: new ( "after-const-prop" ) ,
403
- & early_otherwise_branch:: EarlyOtherwiseBranch ,
404
- & simplify_comparison_integral:: SimplifyComparisonIntegral ,
405
- & simplify_try:: SimplifyArmIdentity ,
406
- & simplify_try:: SimplifyBranchSame ,
407
- & dest_prop:: DestinationPropagation ,
408
- & copy_prop:: CopyPropagation ,
409
- & simplify_branches:: SimplifyBranches :: new ( "after-copy-prop" ) ,
410
- & remove_noop_landing_pads:: RemoveNoopLandingPads ,
411
- & simplify:: SimplifyCfg :: new ( "final" ) ,
412
- & nrvo:: RenameReturnPlace ,
413
- & simplify:: SimplifyLocals ,
414
- & multiple_return_terminators:: MultipleReturnTerminators ,
415
- ] ;
416
-
417
- // Optimizations to run even if mir optimizations have been disabled.
418
- let no_optimizations: & [ & dyn MirPass < ' tcx > ] = & [
419
- // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
420
- & const_prop:: ConstProp ,
421
- ] ;
305
+ run_passes ! ( PassManager :: new( tcx, body, MirPhase :: GeneratorLowering ) => [
306
+ unreachable_prop:: UnreachablePropagation ,
307
+ uninhabited_enum_branching:: UninhabitedEnumBranching ,
308
+ simplify:: SimplifyCfg :: new( "after-uninhabited-enum-branching" ) ,
309
+ inline:: Inline ,
310
+ generator:: StateTransform ,
311
+ ] ) ;
312
+
313
+ let mut optimizations = PassManager :: new ( tcx, body, MirPhase :: Optimization ) ;
314
+
315
+ // FIXME(ecstaticmorse): We shouldn't branch on `mir_opt_level` here, but instead rely on the
316
+ // `LEVEL` of each `MirPass` to determine whether it runs. However, this would run some
317
+ // "cleanup" passes as well as `RemoveNoopLandingPads` when we didn't before.
318
+ if mir_opt_level > 0 {
319
+ run_passes ! ( optimizations => [
320
+ remove_unneeded_drops:: RemoveUnneededDrops ,
321
+ match_branches:: MatchBranchSimplification ,
322
+ // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
323
+ multiple_return_terminators:: MultipleReturnTerminators ,
324
+ instcombine:: InstCombine ,
325
+ const_prop:: ConstProp ,
326
+ simplify_branches:: SimplifyBranches :: new( "after-const-prop" ) ,
327
+ early_otherwise_branch:: EarlyOtherwiseBranch ,
328
+ simplify_comparison_integral:: SimplifyComparisonIntegral ,
329
+ simplify_try:: SimplifyArmIdentity ,
330
+ simplify_try:: SimplifyBranchSame ,
331
+ dest_prop:: DestinationPropagation ,
332
+ copy_prop:: CopyPropagation ,
333
+ simplify_branches:: SimplifyBranches :: new( "after-copy-prop" ) ,
334
+ remove_noop_landing_pads:: RemoveNoopLandingPads ,
335
+ simplify:: SimplifyCfg :: new( "final" ) ,
336
+ nrvo:: RenameReturnPlace ,
337
+ simplify:: SimplifyLocals ,
338
+ multiple_return_terminators:: MultipleReturnTerminators ,
339
+ ] ) ;
340
+ } else {
341
+ run_passes ! ( optimizations => [
342
+ // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
343
+ const_prop:: ConstProp ,
344
+ ] ) ;
345
+ }
422
346
423
347
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
424
- let pre_codegen_cleanup : & [ & dyn MirPass < ' tcx > ] = & [
425
- & add_call_guards:: CriticalCallEdges ,
348
+ run_passes ! ( optimizations => [
349
+ add_call_guards:: CriticalCallEdges ,
426
350
// Dump the end result for testing and debugging purposes.
427
- & dump_mir:: Marker ( "PreCodegen" ) ,
428
- ] ;
429
-
430
- // End of pass declarations, now actually run the passes.
431
- // Generator Lowering
432
- #[ rustfmt:: skip]
433
- run_passes (
434
- tcx,
435
- body,
436
- MirPhase :: GeneratorLowering ,
437
- & [
438
- if mir_opt_level > 0 {
439
- optimizations_with_generators
440
- } else {
441
- no_optimizations_with_generators
442
- }
443
- ] ,
444
- ) ;
445
-
446
- // Main optimization passes
447
- #[ rustfmt:: skip]
448
- run_passes (
449
- tcx,
450
- body,
451
- MirPhase :: Optimization ,
452
- & [
453
- if mir_opt_level > 0 { optimizations } else { no_optimizations } ,
454
- pre_codegen_cleanup,
455
- ] ,
456
- ) ;
351
+ dump_mir:: Marker ( "PreCodegen" ) ,
352
+ ] ) ;
457
353
}
458
354
459
355
fn optimized_mir < ' tcx > ( tcx : TyCtxt < ' tcx > , did : DefId ) -> & ' tcx Body < ' tcx > {
0 commit comments