@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
1616use rustc_middle:: mir:: * ;
1717use rustc_middle:: ty:: { self , List , Ty , TyCtxt } ;
1818use rustc_target:: abi:: VariantIdx ;
19- use std:: iter:: { Enumerate , Peekable } ;
19+ use std:: iter:: { once , Enumerate , Peekable } ;
2020use std:: slice:: Iter ;
2121
2222/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
@@ -551,6 +551,12 @@ struct SimplifyBranchSameOptimization {
551551 bb_to_opt_terminator : BasicBlock ,
552552}
553553
554+ struct SwitchTargetAndValue {
555+ target : BasicBlock ,
556+ // None in case of the `otherwise` case
557+ value : Option < u128 > ,
558+ }
559+
554560struct SimplifyBranchSameOptimizationFinder < ' a , ' tcx > {
555561 body : & ' a Body < ' tcx > ,
556562 tcx : TyCtxt < ' tcx > ,
@@ -562,8 +568,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
562568 . basic_blocks ( )
563569 . iter_enumerated ( )
564570 . 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) } ,
567581 _ => return None ,
568582 } ;
569583
@@ -587,9 +601,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
587601 } ,
588602 } ;
589603
590- let mut iter_bbs_reachable = targets
604+ let mut iter_bbs_reachable = targets_and_values
591605 . 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 ] ) )
593607 . filter ( |( _, bb) | {
594608 // Reaching `unreachable` is UB so assume it doesn't happen.
595609 bb. terminator ( ) . kind != TerminatorKind :: Unreachable
@@ -603,16 +617,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
603617 } )
604618 . peekable ( ) ;
605619
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 ] ) ;
607621 let mut all_successors_equivalent = StatementEquality :: TrivialEqual ;
608622
609623 // 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 ( ) {
611625 let trivial_checks = bb_l. is_cleanup == bb_r. is_cleanup
612626 && bb_l. terminator ( ) . kind == bb_r. terminator ( ) . kind ;
613627 let statement_check = || {
614628 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 ) ;
616630 if matches ! ( stmt_equality, StatementEquality :: NotEqual ) {
617631 // short circuit
618632 None
@@ -634,7 +648,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
634648 // statements are trivially equal, so just take first
635649 trace ! ( "Statements are trivially equal" ) ;
636650 Some ( SimplifyBranchSameOptimization {
637- bb_to_goto : bb_first,
651+ bb_to_goto : bb_first. target ,
638652 bb_to_opt_terminator : bb_idx,
639653 } )
640654 }
@@ -669,10 +683,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
669683 & self ,
670684 adt_matched_on : Place < ' tcx > ,
671685 x : & Statement < ' tcx > ,
672- x_bb_idx : BasicBlock ,
686+ x_target_and_value : & SwitchTargetAndValue ,
673687 y : & Statement < ' tcx > ,
674- y_bb_idx : BasicBlock ,
675- mir_opt_level : usize ,
688+ y_target_and_value : & SwitchTargetAndValue ,
676689 ) -> StatementEquality {
677690 let helper = |rhs : & Rvalue < ' tcx > ,
678691 place : & Place < ' tcx > ,
@@ -691,13 +704,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
691704
692705 match rhs {
693706 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)
701708 }
702709 _ => {
703710 trace ! (
@@ -717,16 +724,20 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
717724 (
718725 StatementKind :: Assign ( box ( _, rhs) ) ,
719726 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 => {
721730 // 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 )
723732 }
724733 (
725734 StatementKind :: SetDiscriminant { place, variant_index } ,
726735 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 => {
728739 // 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 )
730741 }
731742 _ => {
732743 trace ! ( "NO: statements `{:?}` and `{:?}` not considered equal" , x, y) ;
0 commit comments