@@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
345345 Some ( self . insert ( Value :: Constant { value, disambiguator } ) )
346346 }
347347
348+ fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
349+ // Booleans are deterministic.
350+ self . insert ( Value :: Constant { value : Const :: from_bool ( self . tcx , flag) , disambiguator : 0 } )
351+ }
352+
348353 fn insert_scalar ( & mut self , scalar : Scalar , ty : Ty < ' tcx > ) -> VnIndex {
349354 self . insert_constant ( Const :: from_scalar ( self . tcx , scalar, ty) )
350355 . expect ( "scalars are deterministic" )
351356 }
352357
358+ fn insert_tuple ( & mut self , values : Vec < VnIndex > ) -> VnIndex {
359+ self . insert ( Value :: Aggregate ( AggregateTy :: Tuple , VariantIdx :: from_u32 ( 0 ) , values) )
360+ }
361+
353362 #[ instrument( level = "trace" , skip( self ) , ret) ]
354363 fn eval_to_const ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
355364 use Value :: * ;
@@ -785,14 +794,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
785794 Value :: Cast { kind, value, from, to }
786795 }
787796 Rvalue :: BinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
797+ let ty = lhs. ty ( self . local_decls , self . tcx ) ;
788798 let lhs = self . simplify_operand ( lhs, location) ;
789799 let rhs = self . simplify_operand ( rhs, location) ;
790- Value :: BinaryOp ( op, lhs?, rhs?)
800+ let lhs = lhs?;
801+ let rhs = rhs?;
802+ if let Some ( value) = self . simplify_binary ( op, false , ty, lhs, rhs) {
803+ return Some ( value) ;
804+ }
805+ Value :: BinaryOp ( op, lhs, rhs)
791806 }
792807 Rvalue :: CheckedBinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
808+ let ty = lhs. ty ( self . local_decls , self . tcx ) ;
793809 let lhs = self . simplify_operand ( lhs, location) ;
794810 let rhs = self . simplify_operand ( rhs, location) ;
795- Value :: CheckedBinaryOp ( op, lhs?, rhs?)
811+ let lhs = lhs?;
812+ let rhs = rhs?;
813+ if let Some ( value) = self . simplify_binary ( op, true , ty, lhs, rhs) {
814+ return Some ( value) ;
815+ }
816+ Value :: CheckedBinaryOp ( op, lhs, rhs)
796817 }
797818 Rvalue :: UnaryOp ( op, ref mut arg) => {
798819 let arg = self . simplify_operand ( arg, location) ?;
@@ -894,6 +915,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
894915
895916 Some ( self . insert ( Value :: Aggregate ( ty, variant_index, fields) ) )
896917 }
918+
919+ #[ instrument( level = "trace" , skip( self ) , ret) ]
920+ fn simplify_binary (
921+ & mut self ,
922+ op : BinOp ,
923+ checked : bool ,
924+ lhs_ty : Ty < ' tcx > ,
925+ lhs : VnIndex ,
926+ rhs : VnIndex ,
927+ ) -> Option < VnIndex > {
928+ // Floats are weird enough that none of the logic below applies.
929+ let reasonable_ty =
930+ lhs_ty. is_integral ( ) || lhs_ty. is_bool ( ) || lhs_ty. is_char ( ) || lhs_ty. is_any_ptr ( ) ;
931+ if !reasonable_ty {
932+ return None ;
933+ }
934+
935+ let layout = self . ecx . layout_of ( lhs_ty) . ok ( ) ?;
936+
937+ let as_bits = |value| {
938+ let constant = self . evaluated [ value] . as_ref ( ) ?;
939+ let scalar = self . ecx . read_scalar ( constant) . ok ( ) ?;
940+ scalar. to_bits ( constant. layout . size ) . ok ( )
941+ } ;
942+
943+ // Represent the values as `Ok(bits)` or `Err(VnIndex)`.
944+ let a = as_bits ( lhs) . ok_or ( lhs) ;
945+ let b = as_bits ( rhs) . ok_or ( rhs) ;
946+ let result = match ( op, a, b) {
947+ // Neutral elements.
948+ ( BinOp :: Add | BinOp :: BitOr | BinOp :: BitXor , Ok ( 0 ) , Err ( p) )
949+ | (
950+ BinOp :: Add
951+ | BinOp :: BitOr
952+ | BinOp :: BitXor
953+ | BinOp :: Sub
954+ | BinOp :: Offset
955+ | BinOp :: Shl
956+ | BinOp :: Shr ,
957+ Err ( p) ,
958+ Ok ( 0 ) ,
959+ )
960+ | ( BinOp :: Mul , Ok ( 1 ) , Err ( p) )
961+ | ( BinOp :: Mul | BinOp :: Div , Err ( p) , Ok ( 1 ) ) => p,
962+ ( BinOp :: BitAnd , Err ( p) , Ok ( ones) ) | ( BinOp :: BitAnd , Ok ( ones) , Err ( p) )
963+ if ones == layout. size . truncate ( u128:: MAX )
964+ || ( layout. ty . is_bool ( ) && ones == 1 ) =>
965+ {
966+ p
967+ }
968+ // Absorbing elements.
969+ ( BinOp :: Mul | BinOp :: BitAnd , _, Ok ( 0 ) )
970+ | ( BinOp :: Rem , _, Ok ( 1 ) )
971+ | (
972+ BinOp :: Mul | BinOp :: Div | BinOp :: Rem | BinOp :: BitAnd | BinOp :: Shl | BinOp :: Shr ,
973+ Ok ( 0 ) ,
974+ _,
975+ ) => self . insert_scalar ( Scalar :: from_uint ( 0u128 , layout. size ) , lhs_ty) ,
976+ ( BinOp :: BitOr , _, Ok ( ones) ) | ( BinOp :: BitOr , Ok ( ones) , _)
977+ if ones == layout. size . truncate ( u128:: MAX )
978+ || ( layout. ty . is_bool ( ) && ones == 1 ) =>
979+ {
980+ self . insert_scalar ( Scalar :: from_uint ( ones, layout. size ) , lhs_ty)
981+ }
982+ // Sub/Xor with itself.
983+ ( BinOp :: Sub | BinOp :: BitXor , a, b) if a == b => {
984+ self . insert_scalar ( Scalar :: from_uint ( 0u128 , layout. size ) , lhs_ty)
985+ }
986+ // Comparison.
987+ ( BinOp :: Eq , a, b) if ( a. is_ok ( ) && b. is_ok ( ) ) || a == b => self . insert_bool ( a == b) ,
988+ ( BinOp :: Ne , a, b) if ( a. is_ok ( ) && b. is_ok ( ) ) || a == b => self . insert_bool ( a != b) ,
989+ _ => return None ,
990+ } ;
991+
992+ if checked {
993+ let false_val = self . insert_bool ( false ) ;
994+ Some ( self . insert_tuple ( vec ! [ result, false_val] ) )
995+ } else {
996+ Some ( result)
997+ }
998+ }
897999}
8981000
8991001fn op_to_prop_const < ' tcx > (
0 commit comments