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