@@ -159,27 +159,12 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
159159 ( None , Operand :: Copy ( opt_data. child_place ) )
160160 } ;
161161
162- // create temp to store inequality comparison between the two discriminants, `_t` in
163- // example above
164- let nequal = BinOp :: Ne ;
165- let comp_res_type = nequal. ty ( tcx, parent_ty, opt_data. child_ty ) ;
166- let comp_temp = patch. new_temp ( comp_res_type, opt_data. child_source . span ) ;
167- patch. add_statement ( parent_end, StatementKind :: StorageLive ( comp_temp) ) ;
168-
169- // create inequality comparison between the two discriminants
170- let comp_rvalue =
171- Rvalue :: BinaryOp ( nequal, Box :: new ( ( parent_op. clone ( ) , second_operand) ) ) ;
172- patch. add_statement (
173- parent_end,
174- StatementKind :: Assign ( Box :: new ( ( Place :: from ( comp_temp) , comp_rvalue) ) ) ,
175- ) ;
176-
177162 let eq_new_targets = parent_targets. iter ( ) . map ( |( value, child) | {
178163 let TerminatorKind :: SwitchInt { targets, .. } = & bbs[ child] . terminator ( ) . kind
179164 else {
180165 unreachable ! ( )
181166 } ;
182- ( value, targets. target_for_value ( value ) )
167+ ( value, targets. all_targets ( ) [ 0 ] )
183168 } ) ;
184169 let eq_targets = SwitchTargets :: new ( eq_new_targets, opt_data. destination ) ;
185170
@@ -188,36 +173,77 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
188173 source_info : bbs[ parent] . terminator ( ) . source_info ,
189174 kind : TerminatorKind :: SwitchInt {
190175 // switch on the first discriminant, so we can mark the second one as dead
191- discr : parent_op,
176+ discr : parent_op. clone ( ) ,
192177 targets : eq_targets,
193178 } ,
194179 } ) ) ;
195180
196181 let eq_bb = patch. new_block ( eq_switch) ;
197182
198- // Jump to it on the basis of the inequality comparison
199- let true_case = opt_data. destination ;
200- let false_case = eq_bb;
201- patch. patch_terminator (
202- parent,
203- TerminatorKind :: if_ ( Operand :: Move ( Place :: from ( comp_temp) ) , true_case, false_case) ,
204- ) ;
183+ if let Some ( same_target_value) = opt_data. same_target_value {
184+ let t = TerminatorKind :: SwitchInt {
185+ discr : second_operand,
186+ targets : SwitchTargets :: static_if (
187+ same_target_value,
188+ eq_bb,
189+ opt_data. destination ,
190+ ) ,
191+ } ;
192+ patch. patch_terminator ( parent, t) ;
193+
194+ if let Some ( second_discriminant_temp) = second_discriminant_temp {
195+ // Generate a StorageDead for second_discriminant_temp in each of the targets, since we moved it into
196+ // the switch
197+ for bb in [ eq_bb, opt_data. destination ] . iter ( ) {
198+ patch. add_statement (
199+ Location { block : * bb, statement_index : 0 } ,
200+ StatementKind :: StorageDead ( second_discriminant_temp) ,
201+ ) ;
202+ }
203+ }
204+ } else {
205+ // create temp to store inequality comparison between the two discriminants, `_t` in
206+ // example above
207+ let nequal = BinOp :: Ne ;
208+ let comp_res_type = nequal. ty ( tcx, parent_ty, opt_data. child_ty ) ;
209+ let comp_temp = patch. new_temp ( comp_res_type, opt_data. child_source . span ) ;
210+ patch. add_statement ( parent_end, StatementKind :: StorageLive ( comp_temp) ) ;
205211
206- if let Some ( second_discriminant_temp ) = second_discriminant_temp {
207- // generate StorageDead for the second_discriminant_temp not in use anymore
212+ // create inequality comparison between the two discriminants
213+ let comp_rvalue = Rvalue :: BinaryOp ( nequal , Box :: new ( ( parent_op , second_operand ) ) ) ;
208214 patch. add_statement (
209215 parent_end,
210- StatementKind :: StorageDead ( second_discriminant_temp ) ,
216+ StatementKind :: Assign ( Box :: new ( ( Place :: from ( comp_temp ) , comp_rvalue ) ) ) ,
211217 ) ;
212- }
213218
214- // Generate a StorageDead for comp_temp in each of the targets, since we moved it into
215- // the switch
216- for bb in [ false_case, true_case] . iter ( ) {
217- patch. add_statement (
218- Location { block : * bb, statement_index : 0 } ,
219- StatementKind :: StorageDead ( comp_temp) ,
219+ // Jump to it on the basis of the inequality comparison
220+ let true_case = opt_data. destination ;
221+ let false_case = eq_bb;
222+ patch. patch_terminator (
223+ parent,
224+ TerminatorKind :: if_ (
225+ Operand :: Move ( Place :: from ( comp_temp) ) ,
226+ true_case,
227+ false_case,
228+ ) ,
220229 ) ;
230+
231+ // Generate a StorageDead for comp_temp in each of the targets, since we moved it into
232+ // the switch
233+ for bb in [ false_case, true_case] . iter ( ) {
234+ patch. add_statement (
235+ Location { block : * bb, statement_index : 0 } ,
236+ StatementKind :: StorageDead ( comp_temp) ,
237+ ) ;
238+ }
239+
240+ if let Some ( second_discriminant_temp) = second_discriminant_temp {
241+ // generate StorageDead for the second_discriminant_temp not in use anymore
242+ patch. add_statement (
243+ parent_end,
244+ StatementKind :: StorageDead ( second_discriminant_temp) ,
245+ ) ;
246+ }
221247 }
222248
223249 patch. apply ( body) ;
@@ -286,6 +312,7 @@ struct OptimizationData<'tcx> {
286312 child_ty : Ty < ' tcx > ,
287313 child_source : SourceInfo ,
288314 hoist_discriminant : bool ,
315+ same_target_value : Option < u128 > ,
289316}
290317
291318fn evaluate_candidate < ' tcx > (
@@ -375,16 +402,38 @@ fn evaluate_candidate<'tcx>(
375402 targets. otherwise ( )
376403 } ;
377404
405+ let TerminatorKind :: SwitchInt { targets : child_targets, .. } = & bbs[ child] . terminator ( ) . kind
406+ else {
407+ return None ;
408+ } ;
378409 // Verify that the optimization is legal for each branch
379- for ( value, child) in targets. iter ( ) {
410+ let Some ( ( may_same_target_value, _) ) = child_targets. iter ( ) . next ( ) else {
411+ return None ;
412+ } ;
413+ let mut same_target_value = Some ( may_same_target_value) ;
414+ for ( _, child) in targets. iter ( ) {
380415 if !verify_candidate_branch (
381416 & bbs[ child] ,
382- value ,
417+ may_same_target_value ,
383418 child_place,
384419 destination,
385420 hoist_discriminant,
386421 ) {
387- return None ;
422+ same_target_value = None ;
423+ break ;
424+ }
425+ }
426+ if same_target_value. is_none ( ) {
427+ for ( value, child) in targets. iter ( ) {
428+ if !verify_candidate_branch (
429+ & bbs[ child] ,
430+ value,
431+ child_place,
432+ destination,
433+ hoist_discriminant,
434+ ) {
435+ return None ;
436+ }
388437 }
389438 }
390439 Some ( OptimizationData {
@@ -393,6 +442,7 @@ fn evaluate_candidate<'tcx>(
393442 child_ty,
394443 child_source : child_terminator. source_info ,
395444 hoist_discriminant,
445+ same_target_value,
396446 } )
397447}
398448
0 commit comments