@@ -875,6 +875,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
875
875
None
876
876
}
877
877
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
+
878
967
fn simplify_aggregate (
879
968
& mut self ,
880
969
rvalue : & mut Rvalue < ' tcx > ,
@@ -971,6 +1060,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
971
1060
}
972
1061
}
973
1062
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
+
974
1070
Some ( self . insert ( Value :: Aggregate ( ty, variant_index, fields) ) )
975
1071
}
976
1072
@@ -1485,7 +1581,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1485
1581
}
1486
1582
1487
1583
/// 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.
1489
1585
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
1490
1586
let other = self . rev_locals . get ( index) ?;
1491
1587
other
0 commit comments