@@ -5,6 +5,7 @@ use tracing::trace;
55use  crate :: patch:: MirPatch ; 
66
77pub ( super )  enum  SimplifyConstCondition  { 
8+     AfterInstSimplify , 
89    AfterConstProp , 
910    Final , 
1011} 
@@ -13,6 +14,9 @@ pub(super) enum SimplifyConstCondition {
1314impl < ' tcx >  crate :: MirPass < ' tcx >  for  SimplifyConstCondition  { 
1415    fn  name ( & self )  -> & ' static  str  { 
1516        match  self  { 
17+             SimplifyConstCondition :: AfterInstSimplify  => { 
18+                 "SimplifyConstCondition-after-inst-simplify" 
19+             } 
1620            SimplifyConstCondition :: AfterConstProp  => "SimplifyConstCondition-after-const-prop" , 
1721            SimplifyConstCondition :: Final  => "SimplifyConstCondition-final" , 
1822        } 
@@ -23,12 +27,33 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
2327        let  typing_env = body. typing_env ( tcx) ; 
2428        let  mut  patch = MirPatch :: new ( body) ; 
2529
30+         fn  try_get_const < ' tcx ,  ' a > ( 
31+             operand :  & ' a  Operand < ' tcx > , 
32+             has_place_const :  Option < ( Place < ' tcx > ,  & ' a  ConstOperand < ' tcx > ) > , 
33+         )  -> Option < & ' a  ConstOperand < ' tcx > >  { 
34+             match  operand { 
35+                 Operand :: Constant ( const_operand)  => Some ( const_operand) , 
36+                 // `has_place_const` must be the LHS of the previous statement. 
37+                 // Soundness: There is nothing can modify the place, as there are no statements between the two statements. 
38+                 Operand :: Copy ( place)  | Operand :: Move ( place) 
39+                     if  let  Some ( ( place_const,  const_operand) )  = has_place_const
40+                         && place_const == * place =>
41+                 { 
42+                     Some ( const_operand) 
43+                 } 
44+                 Operand :: Copy ( _)  | Operand :: Move ( _)  => None , 
45+             } 
46+         } 
47+ 
2648        ' blocks:  for  ( bb,  block)  in  body. basic_blocks . iter_enumerated ( )  { 
49+             let  mut  pre_place_const:  Option < ( Place < ' tcx > ,  & ConstOperand < ' tcx > ) >  = None ; 
50+ 
2751            for  ( statement_index,  stmt)  in  block. statements . iter ( ) . enumerate ( )  { 
52+                 let  has_place_const = pre_place_const. take ( ) ; 
2853                // Simplify `assume` of a known value: either a NOP or unreachable. 
2954                if  let  StatementKind :: Intrinsic ( box ref  intrinsic)  = stmt. kind 
3055                    && let  NonDivergingIntrinsic :: Assume ( discr)  = intrinsic
31-                     && let  Operand :: Constant ( c)  = discr
56+                     && let  Some ( c)  = try_get_const ( discr,  has_place_const ) 
3257                    && let  Some ( constant)  = c. const_ . try_eval_bool ( tcx,  typing_env) 
3358                { 
3459                    if  constant { 
@@ -37,28 +62,29 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
3762                        patch. patch_terminator ( bb,  TerminatorKind :: Unreachable ) ; 
3863                        continue  ' blocks; 
3964                    } 
65+                 }  else  if  let  StatementKind :: Assign ( box ( lhs,  ref  rvalue) )  = stmt. kind 
66+                     && let  Rvalue :: Use ( Operand :: Constant ( c) )  = rvalue
67+                 { 
68+                     pre_place_const = Some ( ( lhs,  c) ) ; 
4069                } 
4170            } 
4271
4372            let  terminator = block. terminator ( ) ; 
4473            let  terminator = match  terminator. kind  { 
45-                 TerminatorKind :: SwitchInt  { 
46-                     discr :  Operand :: Constant ( ref  c) ,  ref  targets,  ..
47-                 }  => { 
48-                     let  constant = c. const_ . try_eval_bits ( tcx,  typing_env) ; 
49-                     if  let  Some ( constant)  = constant { 
50-                         let  target = targets. target_for_value ( constant) ; 
51-                         TerminatorKind :: Goto  {  target } 
52-                     }  else  { 
53-                         continue ; 
54-                     } 
74+                 TerminatorKind :: SwitchInt  {  ref  discr,  ref  targets,  .. } 
75+                     if  let  Some ( c)  = try_get_const ( discr,  pre_place_const. take ( ) ) 
76+                         && let  Some ( constant)  = c. const_ . try_eval_bits ( tcx,  typing_env)  =>
77+                 { 
78+                     let  target = targets. target_for_value ( constant) ; 
79+                     TerminatorKind :: Goto  {  target } 
80+                 } 
81+                 TerminatorKind :: Assert  {  target,  ref  cond,  expected,  .. } 
82+                     if  let  Some ( c)  = try_get_const ( & cond,  pre_place_const. take ( ) ) 
83+                         && let  Some ( constant)  = c. const_ . try_eval_bool ( tcx,  typing_env) 
84+                         && constant == expected =>
85+                 { 
86+                     TerminatorKind :: Goto  {  target } 
5587                } 
56-                 TerminatorKind :: Assert  { 
57-                     target,  cond :  Operand :: Constant ( ref  c) ,  expected,  ..
58-                 }  => match  c. const_ . try_eval_bool ( tcx,  typing_env)  { 
59-                     Some ( v)  if  v == expected => TerminatorKind :: Goto  {  target } , 
60-                     _ => continue , 
61-                 } , 
6288                _ => continue , 
6389            } ; 
6490            patch. patch_terminator ( bb,  terminator) ; 
0 commit comments