@@ -875,6 +875,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
875875 None
876876 }
877877
878+ fn try_as_place_elem (
879+ & mut self ,
880+ proj : ProjectionElem < VnIndex , Ty < ' tcx > > ,
881+ loc : Location ,
882+ ) -> Option < PlaceElem < ' tcx > > {
883+ Some ( match proj {
884+ ProjectionElem :: Deref => ProjectionElem :: Deref ,
885+ ProjectionElem :: Field ( idx, ty) => ProjectionElem :: Field ( idx, ty) ,
886+ ProjectionElem :: Index ( idx) => {
887+ let Some ( local) = self . try_as_local ( idx, loc) else {
888+ return None ;
889+ } ;
890+ self . reused_locals . insert ( local) ;
891+ ProjectionElem :: Index ( local)
892+ }
893+ ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
894+ ProjectionElem :: ConstantIndex { offset, min_length, from_end }
895+ }
896+ ProjectionElem :: Subslice { from, to, from_end } => {
897+ ProjectionElem :: Subslice { from, to, from_end }
898+ }
899+ ProjectionElem :: Downcast ( symbol, idx) => ProjectionElem :: Downcast ( symbol, idx) ,
900+ ProjectionElem :: OpaqueCast ( idx) => ProjectionElem :: OpaqueCast ( idx) ,
901+ ProjectionElem :: Subtype ( idx) => ProjectionElem :: Subtype ( idx) ,
902+ } )
903+ }
904+
905+ fn simplify_aggregate_to_copy (
906+ & mut self ,
907+ rvalue : & mut Rvalue < ' tcx > ,
908+ location : Location ,
909+ fields : & [ VnIndex ] ,
910+ variant_index : VariantIdx ,
911+ ) -> Option < VnIndex > {
912+ let Some ( & first_field) = fields. first ( ) else {
913+ return None ;
914+ } ;
915+ let Value :: Projection ( copy_from_value, _) = * self . get ( first_field) else {
916+ return None ;
917+ } ;
918+ // All fields must correspond one-to-one and come from the same aggregate value.
919+ if fields. iter ( ) . enumerate ( ) . any ( |( index, & v) | {
920+ if let Value :: Projection ( pointer, ProjectionElem :: Field ( from_index, _) ) = * self . get ( v)
921+ && copy_from_value == pointer
922+ && from_index. index ( ) == index
923+ {
924+ return false ;
925+ }
926+ true
927+ } ) {
928+ return None ;
929+ }
930+
931+ let mut copy_from_local_value = copy_from_value;
932+ if let Value :: Projection ( pointer, proj) = * self . get ( copy_from_value)
933+ && let ProjectionElem :: Downcast ( _, read_variant) = proj
934+ {
935+ if variant_index == read_variant {
936+ // When copying a variant, there is no need to downcast.
937+ copy_from_local_value = pointer;
938+ } else {
939+ // The copied variant must be identical.
940+ return None ;
941+ }
942+ }
943+
944+ let tcx = self . tcx ;
945+ let mut projection = SmallVec :: < [ PlaceElem < ' tcx > ; 1 ] > :: new ( ) ;
946+ loop {
947+ if let Some ( local) = self . try_as_local ( copy_from_local_value, location) {
948+ projection. reverse ( ) ;
949+ let place = Place { local, projection : tcx. mk_place_elems ( projection. as_slice ( ) ) } ;
950+ if rvalue. ty ( self . local_decls , tcx) == place. ty ( self . local_decls , tcx) . ty {
951+ self . reused_locals . insert ( local) ;
952+ * rvalue = Rvalue :: Use ( Operand :: Copy ( place) ) ;
953+ return Some ( copy_from_value) ;
954+ }
955+ return None ;
956+ } else if let Value :: Projection ( pointer, proj) = * self . get ( copy_from_local_value)
957+ && let Some ( proj) = self . try_as_place_elem ( proj, location)
958+ {
959+ projection. push ( proj) ;
960+ copy_from_local_value = pointer;
961+ } else {
962+ return None ;
963+ }
964+ }
965+ }
966+
878967 fn simplify_aggregate (
879968 & mut self ,
880969 rvalue : & mut Rvalue < ' tcx > ,
@@ -971,6 +1060,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9711060 }
9721061 }
9731062
1063+ if let AggregateTy :: Def ( _, _) = ty
1064+ && let Some ( value) =
1065+ self . simplify_aggregate_to_copy ( rvalue, location, & fields, variant_index)
1066+ {
1067+ return Some ( value) ;
1068+ }
1069+
9741070 Some ( self . insert ( Value :: Aggregate ( ty, variant_index, fields) ) )
9751071 }
9761072
@@ -1485,7 +1581,7 @@ impl<'tcx> VnState<'_, 'tcx> {
14851581 }
14861582
14871583 /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
1488- /// return it.
1584+ /// return it. If you used this local, add it to `reused_locals` to remove storage statements.
14891585 fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
14901586 let other = self . rev_locals . get ( index) ?;
14911587 other
0 commit comments