@@ -876,6 +876,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
876
876
None
877
877
}
878
878
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
+
879
968
fn simplify_aggregate (
880
969
& mut self ,
881
970
rvalue : & mut Rvalue < ' tcx > ,
@@ -972,6 +1061,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
972
1061
}
973
1062
}
974
1063
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
+
975
1071
Some ( self . insert ( Value :: Aggregate ( ty, variant_index, fields) ) )
976
1072
}
977
1073
@@ -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