@@ -159,27 +159,12 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
159
159
( None , Operand :: Copy ( opt_data. child_place ) )
160
160
} ;
161
161
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
-
177
162
let eq_new_targets = parent_targets. iter ( ) . map ( |( value, child) | {
178
163
let TerminatorKind :: SwitchInt { targets, .. } = & bbs[ child] . terminator ( ) . kind
179
164
else {
180
165
unreachable ! ( )
181
166
} ;
182
- ( value, targets. target_for_value ( value ) )
167
+ ( value, targets. all_targets ( ) [ 0 ] )
183
168
} ) ;
184
169
let eq_targets = SwitchTargets :: new ( eq_new_targets, opt_data. destination ) ;
185
170
@@ -188,36 +173,77 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
188
173
source_info : bbs[ parent] . terminator ( ) . source_info ,
189
174
kind : TerminatorKind :: SwitchInt {
190
175
// switch on the first discriminant, so we can mark the second one as dead
191
- discr : parent_op,
176
+ discr : parent_op. clone ( ) ,
192
177
targets : eq_targets,
193
178
} ,
194
179
} ) ) ;
195
180
196
181
let eq_bb = patch. new_block ( eq_switch) ;
197
182
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) ) ;
205
211
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 ) ) ) ;
208
214
patch. add_statement (
209
215
parent_end,
210
- StatementKind :: StorageDead ( second_discriminant_temp ) ,
216
+ StatementKind :: Assign ( Box :: new ( ( Place :: from ( comp_temp ) , comp_rvalue ) ) ) ,
211
217
) ;
212
- }
213
218
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
+ ) ,
220
229
) ;
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
+ }
221
247
}
222
248
223
249
patch. apply ( body) ;
@@ -286,6 +312,7 @@ struct OptimizationData<'tcx> {
286
312
child_ty : Ty < ' tcx > ,
287
313
child_source : SourceInfo ,
288
314
hoist_discriminant : bool ,
315
+ same_target_value : Option < u128 > ,
289
316
}
290
317
291
318
fn evaluate_candidate < ' tcx > (
@@ -375,16 +402,38 @@ fn evaluate_candidate<'tcx>(
375
402
targets. otherwise ( )
376
403
} ;
377
404
405
+ let TerminatorKind :: SwitchInt { targets : child_targets, .. } = & bbs[ child] . terminator ( ) . kind
406
+ else {
407
+ return None ;
408
+ } ;
378
409
// 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 ( ) {
380
415
if !verify_candidate_branch (
381
416
& bbs[ child] ,
382
- value ,
417
+ may_same_target_value ,
383
418
child_place,
384
419
destination,
385
420
hoist_discriminant,
386
421
) {
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
+ }
388
437
}
389
438
}
390
439
Some ( OptimizationData {
@@ -393,6 +442,7 @@ fn evaluate_candidate<'tcx>(
393
442
child_ty,
394
443
child_source : child_terminator. source_info ,
395
444
hoist_discriminant,
445
+ same_target_value,
396
446
} )
397
447
}
398
448
0 commit comments