@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
16
16
use rustc_middle:: mir:: * ;
17
17
use rustc_middle:: ty:: { self , List , Ty , TyCtxt } ;
18
18
use rustc_target:: abi:: VariantIdx ;
19
- use std:: iter:: { Enumerate , Peekable } ;
19
+ use std:: iter:: { once , Enumerate , Peekable } ;
20
20
use std:: slice:: Iter ;
21
21
22
22
/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
@@ -551,6 +551,12 @@ struct SimplifyBranchSameOptimization {
551
551
bb_to_opt_terminator : BasicBlock ,
552
552
}
553
553
554
+ struct SwitchTargetAndValue {
555
+ target : BasicBlock ,
556
+ // None in case of the `otherwise` case
557
+ value : Option < u128 > ,
558
+ }
559
+
554
560
struct SimplifyBranchSameOptimizationFinder < ' a , ' tcx > {
555
561
body : & ' a Body < ' tcx > ,
556
562
tcx : TyCtxt < ' tcx > ,
@@ -562,8 +568,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
562
568
. basic_blocks ( )
563
569
. iter_enumerated ( )
564
570
. filter_map ( |( bb_idx, bb) | {
565
- let ( discr_switched_on, targets) = match & bb. terminator ( ) . kind {
566
- TerminatorKind :: SwitchInt { targets, discr, .. } => ( discr, targets) ,
571
+ let ( discr_switched_on, targets_and_values) = match & bb. terminator ( ) . kind {
572
+ TerminatorKind :: SwitchInt { targets, discr, values, .. } => {
573
+ // if values.len() == targets.len() - 1, we need to include None where no value is present
574
+ // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None
575
+ let values_extended = values. iter ( ) . map ( |x|Some ( * x) ) . chain ( once ( None ) ) ;
576
+ let targets_and_values: Vec < _ > = targets. iter ( ) . zip ( values_extended)
577
+ . map ( |( target, value) | SwitchTargetAndValue { target : * target, value} )
578
+ . collect ( ) ;
579
+ assert_eq ! ( targets. len( ) , targets_and_values. len( ) ) ;
580
+ ( discr, targets_and_values) } ,
567
581
_ => return None ,
568
582
} ;
569
583
@@ -587,9 +601,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
587
601
} ,
588
602
} ;
589
603
590
- let mut iter_bbs_reachable = targets
604
+ let mut iter_bbs_reachable = targets_and_values
591
605
. iter ( )
592
- . map ( |idx | ( * idx , & self . body . basic_blocks ( ) [ * idx ] ) )
606
+ . map ( |target_and_value | ( target_and_value , & self . body . basic_blocks ( ) [ target_and_value . target ] ) )
593
607
. filter ( |( _, bb) | {
594
608
// Reaching `unreachable` is UB so assume it doesn't happen.
595
609
bb. terminator ( ) . kind != TerminatorKind :: Unreachable
@@ -603,16 +617,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
603
617
} )
604
618
. peekable ( ) ;
605
619
606
- let bb_first = iter_bbs_reachable. peek ( ) . map ( |( idx, _) | * idx) . unwrap_or ( targets [ 0 ] ) ;
620
+ let bb_first = iter_bbs_reachable. peek ( ) . map ( |( idx, _) | * idx) . unwrap_or ( & targets_and_values [ 0 ] ) ;
607
621
let mut all_successors_equivalent = StatementEquality :: TrivialEqual ;
608
622
609
623
// All successor basic blocks must be equal or contain statements that are pairwise considered equal.
610
- for ( ( bb_l_idx , bb_l) , ( bb_r_idx , bb_r) ) in iter_bbs_reachable. tuple_windows ( ) {
624
+ for ( ( target_and_value_l , bb_l) , ( target_and_value_r , bb_r) ) in iter_bbs_reachable. tuple_windows ( ) {
611
625
let trivial_checks = bb_l. is_cleanup == bb_r. is_cleanup
612
626
&& bb_l. terminator ( ) . kind == bb_r. terminator ( ) . kind ;
613
627
let statement_check = || {
614
628
bb_l. statements . iter ( ) . zip ( & bb_r. statements ) . try_fold ( StatementEquality :: TrivialEqual , |acc, ( l, r) | {
615
- let stmt_equality = self . statement_equality ( * adt_matched_on, & l, bb_l_idx , & r, bb_r_idx , self . tcx . sess . opts . debugging_opts . mir_opt_level ) ;
629
+ let stmt_equality = self . statement_equality ( * adt_matched_on, & l, target_and_value_l , & r, target_and_value_r ) ;
616
630
if matches ! ( stmt_equality, StatementEquality :: NotEqual ) {
617
631
// short circuit
618
632
None
@@ -634,7 +648,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
634
648
// statements are trivially equal, so just take first
635
649
trace ! ( "Statements are trivially equal" ) ;
636
650
Some ( SimplifyBranchSameOptimization {
637
- bb_to_goto : bb_first,
651
+ bb_to_goto : bb_first. target ,
638
652
bb_to_opt_terminator : bb_idx,
639
653
} )
640
654
}
@@ -669,10 +683,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
669
683
& self ,
670
684
adt_matched_on : Place < ' tcx > ,
671
685
x : & Statement < ' tcx > ,
672
- x_bb_idx : BasicBlock ,
686
+ x_target_and_value : & SwitchTargetAndValue ,
673
687
y : & Statement < ' tcx > ,
674
- y_bb_idx : BasicBlock ,
675
- mir_opt_level : usize ,
688
+ y_target_and_value : & SwitchTargetAndValue ,
676
689
) -> StatementEquality {
677
690
let helper = |rhs : & Rvalue < ' tcx > ,
678
691
place : & Place < ' tcx > ,
@@ -691,13 +704,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
691
704
692
705
match rhs {
693
706
Rvalue :: Use ( operand) if operand. place ( ) == Some ( adt_matched_on) => {
694
- // FIXME(76803): This logic is currently broken because it does not take into
695
- // account the current discriminant value.
696
- if mir_opt_level > 2 {
697
- StatementEquality :: ConsideredEqual ( side_to_choose)
698
- } else {
699
- StatementEquality :: NotEqual
700
- }
707
+ StatementEquality :: ConsideredEqual ( side_to_choose)
701
708
}
702
709
_ => {
703
710
trace ! (
@@ -717,16 +724,20 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
717
724
(
718
725
StatementKind :: Assign ( box ( _, rhs) ) ,
719
726
StatementKind :: SetDiscriminant { place, variant_index } ,
720
- ) => {
727
+ )
728
+ // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index
729
+ if Some ( variant_index. index ( ) as u128 ) == y_target_and_value. value => {
721
730
// choose basic block of x, as that has the assign
722
- helper ( rhs, place, variant_index, x_bb_idx )
731
+ helper ( rhs, place, variant_index, x_target_and_value . target )
723
732
}
724
733
(
725
734
StatementKind :: SetDiscriminant { place, variant_index } ,
726
735
StatementKind :: Assign ( box ( _, rhs) ) ,
727
- ) => {
736
+ )
737
+ // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index
738
+ if Some ( variant_index. index ( ) as u128 ) == x_target_and_value. value => {
728
739
// choose basic block of y, as that has the assign
729
- helper ( rhs, place, variant_index, y_bb_idx )
740
+ helper ( rhs, place, variant_index, y_target_and_value . target )
730
741
}
731
742
_ => {
732
743
trace ! ( "NO: statements `{:?}` and `{:?}` not considered equal" , x, y) ;
0 commit comments