@@ -98,7 +98,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
98
98
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
99
99
trace ! ( "running EarlyOtherwiseBranch on {:?}" , body. source) ;
100
100
101
- let mut should_cleanup = false ;
101
+ let mut should_apply_patch = false ;
102
+ let mut patch = MirPatch :: new ( body) ;
102
103
103
104
// Also consider newly generated bbs in the same pass
104
105
for i in 0 ..body. basic_blocks . len ( ) {
@@ -112,7 +113,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
112
113
113
114
trace ! ( "SUCCESS: found optimization possibility to apply: {:?}" , & opt_data) ;
114
115
115
- should_cleanup = true ;
116
+ should_apply_patch = true ;
116
117
117
118
let TerminatorKind :: SwitchInt { discr : parent_op, targets : parent_targets } =
118
119
& bbs[ parent] . terminator ( ) . kind
@@ -129,8 +130,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
129
130
let statements_before = bbs[ parent] . statements . len ( ) ;
130
131
let parent_end = Location { block : parent, statement_index : statements_before } ;
131
132
132
- let mut patch = MirPatch :: new ( body) ;
133
-
134
133
let ( second_discriminant_temp, second_operand) = if opt_data. hoist_discriminant {
135
134
// create temp to store second discriminant in, `_s` in example above
136
135
let second_discriminant_temp =
@@ -242,13 +241,12 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
242
241
) ;
243
242
}
244
243
}
245
-
246
- patch. apply ( body) ;
247
244
}
248
245
249
246
// Since this optimization adds new basic blocks and invalidates others,
250
247
// clean up the cfg to make it nicer for other passes
251
- if should_cleanup {
248
+ if should_apply_patch {
249
+ patch. apply ( body) ;
252
250
simplify_cfg ( body) ;
253
251
}
254
252
}
@@ -275,19 +273,15 @@ fn evaluate_candidate<'tcx>(
275
273
return None ;
276
274
} ;
277
275
let parent_ty = parent_discr. ty ( body. local_decls ( ) , tcx) ;
278
- let ( _, child) = targets. iter ( ) . next ( ) ?;
279
- let child_terminator = & bbs[ child] . terminator ( ) ;
280
- let TerminatorKind :: SwitchInt { targets : child_targets, discr : child_discr } =
281
- & child_terminator. kind
276
+ let mut targets_iter = targets. iter ( ) ;
277
+ let ( _, first_child) = targets_iter. next ( ) ?;
278
+ let first_child_terminator = & bbs[ first_child] . terminator ( ) ;
279
+ let TerminatorKind :: SwitchInt { targets : first_child_targets, discr : first_child_discr } =
280
+ & first_child_terminator. kind
282
281
else {
283
282
return None ;
284
283
} ;
285
- let child_ty = child_discr. ty ( body. local_decls ( ) , tcx) ;
286
- if bbs[ child] . statements . len ( ) > 1 {
287
- return None ;
288
- }
289
- let hoist_discriminant = bbs[ child] . statements . len ( ) == 1 ;
290
- let child_place = if hoist_discriminant {
284
+ let hoist_discriminant = if bbs[ first_child] . statements . len ( ) == 1 {
291
285
if !bbs[ targets. otherwise ( ) ] . is_empty_unreachable ( ) {
292
286
// Someone could write code like this:
293
287
// ```rust
@@ -320,7 +314,44 @@ fn evaluate_candidate<'tcx>(
320
314
// So we need the `otherwise` branch has no statements and an unreachable terminator.
321
315
return None ;
322
316
}
323
- let Some ( StatementKind :: Assign ( boxed) ) = & bbs[ child] . statements . first ( ) . map ( |x| & x. kind )
317
+ true
318
+ } else if bbs[ first_child] . statements . is_empty ( ) {
319
+ false
320
+ } else {
321
+ return None ;
322
+ } ;
323
+ let destination = if hoist_discriminant || bbs[ targets. otherwise ( ) ] . is_empty_unreachable ( ) {
324
+ first_child_targets. otherwise ( )
325
+ } else {
326
+ if first_child_targets. otherwise ( ) != targets. otherwise ( ) {
327
+ return None ;
328
+ }
329
+ targets. otherwise ( )
330
+ } ;
331
+ while let Some ( ( _, child) ) = targets_iter. next ( ) {
332
+ let child_branch = & bbs[ child] ;
333
+ // In order for the optimization to be correct, the branch must...
334
+ // ...have exactly one or empty statement
335
+ if ( hoist_discriminant && child_branch. statements . len ( ) != 1 )
336
+ || ( !hoist_discriminant && !child_branch. statements . is_empty ( ) )
337
+ {
338
+ return None ;
339
+ }
340
+ // ...terminate on a `SwitchInt` that invalidates that local
341
+ let TerminatorKind :: SwitchInt { targets : child_targets, .. } =
342
+ & child_branch. terminator ( ) . kind
343
+ else {
344
+ return None ;
345
+ } ;
346
+ if child_targets. otherwise ( ) != destination {
347
+ return None ;
348
+ }
349
+ // Make sure there are only two branches.
350
+ }
351
+ let child_ty = first_child_discr. ty ( body. local_decls ( ) , tcx) ;
352
+ let child_place = if hoist_discriminant {
353
+ let Some ( StatementKind :: Assign ( boxed) ) =
354
+ & bbs[ first_child] . statements . first ( ) . map ( |x| & x. kind )
324
355
else {
325
356
return None ;
326
357
} ;
@@ -329,26 +360,17 @@ fn evaluate_candidate<'tcx>(
329
360
} ;
330
361
* child_place
331
362
} else {
332
- let TerminatorKind :: SwitchInt { discr, .. } = & bbs[ child ] . terminator ( ) . kind else {
363
+ let TerminatorKind :: SwitchInt { discr, .. } = & bbs[ first_child ] . terminator ( ) . kind else {
333
364
return None ;
334
365
} ;
335
366
let Operand :: Copy ( child_place) = discr else {
336
367
return None ;
337
368
} ;
338
369
* child_place
339
370
} ;
340
- let destination = if hoist_discriminant || bbs[ targets. otherwise ( ) ] . is_empty_unreachable ( ) {
341
- child_targets. otherwise ( )
342
- } else {
343
- targets. otherwise ( )
344
- } ;
345
371
346
- let TerminatorKind :: SwitchInt { targets : child_targets, .. } = & bbs[ child] . terminator ( ) . kind
347
- else {
348
- return None ;
349
- } ;
350
372
// Verify that the optimization is legal for each branch
351
- let Some ( ( may_same_target_value, _) ) = child_targets . iter ( ) . next ( ) else {
373
+ let Some ( ( may_same_target_value, _) ) = first_child_targets . iter ( ) . next ( ) else {
352
374
return None ;
353
375
} ;
354
376
let mut same_target_value = Some ( may_same_target_value) ;
@@ -357,7 +379,6 @@ fn evaluate_candidate<'tcx>(
357
379
& bbs[ child] ,
358
380
may_same_target_value,
359
381
child_place,
360
- destination,
361
382
hoist_discriminant,
362
383
) {
363
384
same_target_value = None ;
@@ -369,13 +390,7 @@ fn evaluate_candidate<'tcx>(
369
390
return None ;
370
391
}
371
392
for ( value, child) in targets. iter ( ) {
372
- if !verify_candidate_branch (
373
- & bbs[ child] ,
374
- value,
375
- child_place,
376
- destination,
377
- hoist_discriminant,
378
- ) {
393
+ if !verify_candidate_branch ( & bbs[ child] , value, child_place, hoist_discriminant) {
379
394
return None ;
380
395
}
381
396
}
@@ -384,7 +399,7 @@ fn evaluate_candidate<'tcx>(
384
399
destination,
385
400
child_place,
386
401
child_ty,
387
- child_source : child_terminator . source_info ,
402
+ child_source : first_child_terminator . source_info ,
388
403
hoist_discriminant,
389
404
same_target_value,
390
405
} )
@@ -394,20 +409,11 @@ fn verify_candidate_branch<'tcx>(
394
409
branch : & BasicBlockData < ' tcx > ,
395
410
value : u128 ,
396
411
place : Place < ' tcx > ,
397
- destination : BasicBlock ,
398
412
hoist_discriminant : bool ,
399
413
) -> bool {
400
- // In order for the optimization to be correct, the branch must...
401
- // ...have exactly one statement
402
- if ( hoist_discriminant && branch. statements . len ( ) != 1 )
403
- || ( !hoist_discriminant && !branch. statements . is_empty ( ) )
404
- {
405
- return false ;
406
- }
407
- // ...terminate on a `SwitchInt` that invalidates that local
408
414
let TerminatorKind :: SwitchInt { discr : switch_op, targets, .. } = & branch. terminator ( ) . kind
409
415
else {
410
- return false ;
416
+ unreachable ! ( )
411
417
} ;
412
418
if hoist_discriminant {
413
419
// ...assign the discriminant of `place` in that statement
@@ -428,10 +434,6 @@ fn verify_candidate_branch<'tcx>(
428
434
return false ;
429
435
}
430
436
}
431
- // ...fall through to `destination` if the switch misses
432
- if destination != targets. otherwise ( ) {
433
- return false ;
434
- }
435
437
// ...have a branch for value `value`
436
438
let mut iter = targets. iter ( ) ;
437
439
let Some ( ( target_value, _) ) = iter. next ( ) else {
0 commit comments