@@ -263,33 +263,49 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
263
263
}
264
264
}
265
265
266
+ /// Check if the cast constant using `IntToInt` is equal to the target constant.
267
+ fn can_cast (
268
+ from_val : impl Into < u128 > ,
269
+ from_size : Size ,
270
+ target_scalar : ScalarInt ,
271
+ target_is_signed : bool ,
272
+ ) -> bool {
273
+ let from_scalar = ScalarInt :: try_from_uint ( from_val. into ( ) , from_size) . unwrap ( ) ;
274
+ let to_size = target_scalar. size ( ) ;
275
+ let cast_scalar = if target_is_signed {
276
+ ScalarInt :: try_from_int ( from_scalar. to_int ( from_size) , to_size) . unwrap ( )
277
+ } else {
278
+ ScalarInt :: try_from_uint ( from_scalar. to_uint ( from_size) , to_size) . unwrap ( )
279
+ } ;
280
+ cast_scalar == target_scalar
281
+ }
282
+
266
283
#[ derive( Default ) ]
267
284
struct SimplifyToExp {
268
- transfrom_types : Vec < TransfromType > ,
285
+ transfrom_kinds : Vec < TransfromKind > ,
269
286
}
270
287
271
288
#[ derive( Clone , Copy ) ]
272
- enum CompareType < ' tcx , ' a > {
289
+ enum ExpectedTransformKind < ' tcx , ' a > {
273
290
/// Identical statements.
274
291
Same ( & ' a StatementKind < ' tcx > ) ,
275
292
/// Assignment statements have the same value.
276
- Eq ( & ' a Place < ' tcx > , Ty < ' tcx > , ScalarInt ) ,
293
+ SameByEq { place : & ' a Place < ' tcx > , ty : Ty < ' tcx > , scalar : ScalarInt } ,
277
294
/// Enum variant comparison type.
278
- Discr { place : & ' a Place < ' tcx > , ty : Ty < ' tcx > , is_signed : bool } ,
295
+ Cast { place : & ' a Place < ' tcx > , ty : Ty < ' tcx > } ,
279
296
}
280
297
281
- enum TransfromType {
298
+ enum TransfromKind {
282
299
Same ,
283
- Eq ,
284
- Discr ,
300
+ Cast ,
285
301
}
286
302
287
- impl From < CompareType < ' _ , ' _ > > for TransfromType {
288
- fn from ( compare_type : CompareType < ' _ , ' _ > ) -> Self {
303
+ impl From < ExpectedTransformKind < ' _ , ' _ > > for TransfromKind {
304
+ fn from ( compare_type : ExpectedTransformKind < ' _ , ' _ > ) -> Self {
289
305
match compare_type {
290
- CompareType :: Same ( _) => TransfromType :: Same ,
291
- CompareType :: Eq ( _ , _ , _ ) => TransfromType :: Eq ,
292
- CompareType :: Discr { .. } => TransfromType :: Discr ,
306
+ ExpectedTransformKind :: Same ( _) => TransfromKind :: Same ,
307
+ ExpectedTransformKind :: SameByEq { .. } => TransfromKind :: Same ,
308
+ ExpectedTransformKind :: Cast { .. } => TransfromKind :: Cast ,
293
309
}
294
310
}
295
311
}
@@ -353,7 +369,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
353
369
return None ;
354
370
}
355
371
let mut target_iter = targets. iter ( ) ;
356
- let ( first_val , first_target) = target_iter. next ( ) . unwrap ( ) ;
372
+ let ( first_case_val , first_target) = target_iter. next ( ) . unwrap ( ) ;
357
373
let first_terminator_kind = & bbs[ first_target] . terminator ( ) . kind ;
358
374
// Check that destinations are identical, and if not, then don't optimize this block
359
375
if !targets
@@ -365,22 +381,18 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
365
381
366
382
let discr_size = tcx. layout_of ( param_env. and ( discr_ty) ) . unwrap ( ) . size ;
367
383
let first_stmts = & bbs[ first_target] . statements ;
368
- let ( second_val , second_target) = target_iter. next ( ) . unwrap ( ) ;
384
+ let ( second_case_val , second_target) = target_iter. next ( ) . unwrap ( ) ;
369
385
let second_stmts = & bbs[ second_target] . statements ;
370
386
if first_stmts. len ( ) != second_stmts. len ( ) {
371
387
return None ;
372
388
}
373
389
374
- fn int_equal ( l : ScalarInt , r : impl Into < u128 > , size : Size ) -> bool {
375
- l. to_bits_unchecked ( ) == ScalarInt :: try_from_uint ( r, size) . unwrap ( ) . to_bits_unchecked ( )
376
- }
377
-
378
390
// We first compare the two branches, and then the other branches need to fulfill the same conditions.
379
- let mut compare_types = Vec :: new ( ) ;
391
+ let mut expected_transform_kinds = Vec :: new ( ) ;
380
392
for ( f, s) in iter:: zip ( first_stmts, second_stmts) {
381
393
let compare_type = match ( & f. kind , & s. kind ) {
382
394
// If two statements are exactly the same, we can optimize.
383
- ( f_s, s_s) if f_s == s_s => CompareType :: Same ( f_s) ,
395
+ ( f_s, s_s) if f_s == s_s => ExpectedTransformKind :: Same ( f_s) ,
384
396
385
397
// If two statements are assignments with the match values to the same place, we can optimize.
386
398
(
@@ -394,22 +406,27 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
394
406
f_c. const_ . try_eval_scalar_int ( tcx, param_env) ,
395
407
s_c. const_ . try_eval_scalar_int ( tcx, param_env) ,
396
408
) {
397
- ( Some ( f) , Some ( s) ) if f == s => CompareType :: Eq ( lhs_f, f_c. const_ . ty ( ) , f) ,
398
- // Enum variants can also be simplified to an assignment statement if their values are equal.
399
- // We need to consider both unsigned and signed scenarios here.
409
+ ( Some ( f) , Some ( s) ) if f == s => ExpectedTransformKind :: SameByEq {
410
+ place : lhs_f,
411
+ ty : f_c. const_ . ty ( ) ,
412
+ scalar : f,
413
+ } ,
414
+ // Enum variants can also be simplified to an assignment statement,
415
+ // if we can use `IntToInt` cast to get an equal value.
400
416
( Some ( f) , Some ( s) )
401
- if ( ( f_c. const_ . ty ( ) . is_signed ( ) || discr_ty. is_signed ( ) )
402
- && int_equal ( f, first_val, discr_size)
403
- && int_equal ( s, second_val, discr_size) )
404
- || ( Some ( f) == ScalarInt :: try_from_uint ( first_val, f. size ( ) )
405
- && Some ( s)
406
- == ScalarInt :: try_from_uint ( second_val, s. size ( ) ) ) =>
417
+ if ( can_cast (
418
+ first_case_val,
419
+ discr_size,
420
+ f,
421
+ f_c. const_ . ty ( ) . is_signed ( ) ,
422
+ ) && can_cast (
423
+ second_case_val,
424
+ discr_size,
425
+ s,
426
+ s_c. const_ . ty ( ) . is_signed ( ) ,
427
+ ) ) =>
407
428
{
408
- CompareType :: Discr {
409
- place : lhs_f,
410
- ty : f_c. const_ . ty ( ) ,
411
- is_signed : f_c. const_ . ty ( ) . is_signed ( ) || discr_ty. is_signed ( ) ,
412
- }
429
+ ExpectedTransformKind :: Cast { place : lhs_f, ty : f_c. const_ . ty ( ) }
413
430
}
414
431
_ => {
415
432
return None ;
@@ -420,47 +437,36 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
420
437
// Otherwise we cannot optimize. Try another block.
421
438
_ => return None ,
422
439
} ;
423
- compare_types . push ( compare_type) ;
440
+ expected_transform_kinds . push ( compare_type) ;
424
441
}
425
442
426
443
// All remaining BBs need to fulfill the same pattern as the two BBs from the previous step.
427
444
for ( other_val, other_target) in target_iter {
428
445
let other_stmts = & bbs[ other_target] . statements ;
429
- if compare_types . len ( ) != other_stmts. len ( ) {
446
+ if expected_transform_kinds . len ( ) != other_stmts. len ( ) {
430
447
return None ;
431
448
}
432
- for ( f, s) in iter:: zip ( & compare_types , other_stmts) {
449
+ for ( f, s) in iter:: zip ( & expected_transform_kinds , other_stmts) {
433
450
match ( * f, & s. kind ) {
434
- ( CompareType :: Same ( f_s) , s_s) if f_s == s_s => { }
451
+ ( ExpectedTransformKind :: Same ( f_s) , s_s) if f_s == s_s => { }
435
452
(
436
- CompareType :: Eq ( lhs_f, f_ty, val ) ,
453
+ ExpectedTransformKind :: SameByEq { place : lhs_f, ty : f_ty, scalar } ,
437
454
StatementKind :: Assign ( box ( lhs_s, Rvalue :: Use ( Operand :: Constant ( s_c) ) ) ) ,
438
455
) if lhs_f == lhs_s
439
456
&& s_c. const_ . ty ( ) == f_ty
440
- && s_c. const_ . try_eval_scalar_int ( tcx, param_env) == Some ( val ) => { }
457
+ && s_c. const_ . try_eval_scalar_int ( tcx, param_env) == Some ( scalar ) => { }
441
458
(
442
- CompareType :: Discr { place : lhs_f, ty : f_ty, is_signed } ,
459
+ ExpectedTransformKind :: Cast { place : lhs_f, ty : f_ty } ,
443
460
StatementKind :: Assign ( box ( lhs_s, Rvalue :: Use ( Operand :: Constant ( s_c) ) ) ) ,
444
- ) if lhs_f == lhs_s && s_c. const_ . ty ( ) == f_ty => {
445
- let Some ( f) = s_c. const_ . try_eval_scalar_int ( tcx, param_env) else {
446
- return None ;
447
- } ;
448
- if is_signed
449
- && s_c. const_ . ty ( ) . is_signed ( )
450
- && int_equal ( f, other_val, discr_size)
451
- {
452
- continue ;
453
- }
454
- if Some ( f) == ScalarInt :: try_from_uint ( other_val, f. size ( ) ) {
455
- continue ;
456
- }
457
- return None ;
458
- }
461
+ ) if let Some ( f) = s_c. const_ . try_eval_scalar_int ( tcx, param_env)
462
+ && lhs_f == lhs_s
463
+ && s_c. const_ . ty ( ) == f_ty
464
+ && can_cast ( other_val, discr_size, f, f_ty. is_signed ( ) ) => { }
459
465
_ => return None ,
460
466
}
461
467
}
462
468
}
463
- self . transfrom_types = compare_types . into_iter ( ) . map ( |c| c. into ( ) ) . collect ( ) ;
469
+ self . transfrom_kinds = expected_transform_kinds . into_iter ( ) . map ( |c| c. into ( ) ) . collect ( ) ;
464
470
Some ( ( ) )
465
471
}
466
472
@@ -478,13 +484,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
478
484
let ( _, first) = targets. iter ( ) . next ( ) . unwrap ( ) ;
479
485
let first = & bbs[ first] ;
480
486
481
- for ( t, s) in iter:: zip ( & self . transfrom_types , & first. statements ) {
487
+ for ( t, s) in iter:: zip ( & self . transfrom_kinds , & first. statements ) {
482
488
match ( t, & s. kind ) {
483
- ( TransfromType :: Same , _ ) | ( TransfromType :: Eq , _) => {
489
+ ( TransfromKind :: Same , _) => {
484
490
patch. add_statement ( parent_end, s. kind . clone ( ) ) ;
485
491
}
486
492
(
487
- TransfromType :: Discr ,
493
+ TransfromKind :: Cast ,
488
494
StatementKind :: Assign ( box ( lhs, Rvalue :: Use ( Operand :: Constant ( f_c) ) ) ) ,
489
495
) => {
490
496
let operand = Operand :: Copy ( Place :: from ( discr_local) ) ;
0 commit comments