@@ -4,7 +4,7 @@ use crate::MirPass;
4
4
use rustc_hir:: Mutability ;
5
5
use rustc_middle:: mir:: {
6
6
BinOp , Body , Constant , LocalDecls , Operand , Place , ProjectionElem , Rvalue , SourceInfo ,
7
- StatementKind , UnOp ,
7
+ Statement , StatementKind , Terminator , TerminatorKind , UnOp ,
8
8
} ;
9
9
use rustc_middle:: ty:: { self , TyCtxt } ;
10
10
@@ -29,6 +29,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
29
29
_ => { }
30
30
}
31
31
}
32
+
33
+ ctx. combine_primitive_clone (
34
+ & mut block. terminator . as_mut ( ) . unwrap ( ) ,
35
+ & mut block. statements ,
36
+ ) ;
32
37
}
33
38
}
34
39
}
@@ -130,4 +135,70 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
130
135
}
131
136
}
132
137
}
138
+
139
+ fn combine_primitive_clone (
140
+ & self ,
141
+ terminator : & mut Terminator < ' tcx > ,
142
+ statements : & mut Vec < Statement < ' tcx > > ,
143
+ ) {
144
+ let TerminatorKind :: Call { func, args, destination, .. } = & mut terminator. kind
145
+ else { return } ;
146
+
147
+ // It's definitely not a clone if there are multiple arguments
148
+ if args. len ( ) != 1 {
149
+ return ;
150
+ }
151
+
152
+ let Some ( ( destination_place, destination_block) ) = * destination
153
+ else { return } ;
154
+
155
+ // Only bother looking more if it's easy to know what we're calling
156
+ let Some ( ( fn_def_id, fn_substs) ) = func. const_fn_def ( )
157
+ else { return } ;
158
+
159
+ // Clone needs one subst, so we can cheaply rule out other stuff
160
+ if fn_substs. len ( ) != 1 {
161
+ return ;
162
+ }
163
+
164
+ // These types are easily available from locals, so check that before
165
+ // doing DefId lookups to figure out what we're actually calling.
166
+ let arg_ty = args[ 0 ] . ty ( self . local_decls , self . tcx ) ;
167
+
168
+ let ty:: Ref ( _region, inner_ty, Mutability :: Not ) = * arg_ty. kind ( )
169
+ else { return } ;
170
+
171
+ if !inner_ty. is_trivially_pure_clone_copy ( ) {
172
+ return ;
173
+ }
174
+
175
+ let trait_def_id = self . tcx . trait_of_item ( fn_def_id) ;
176
+ if trait_def_id. is_none ( ) || trait_def_id != self . tcx . lang_items ( ) . clone_trait ( ) {
177
+ return ;
178
+ }
179
+
180
+ if !self . tcx . consider_optimizing ( || {
181
+ format ! (
182
+ "InstCombine - Call: {:?} SourceInfo: {:?}" ,
183
+ ( fn_def_id, fn_substs) ,
184
+ terminator. source_info
185
+ )
186
+ } ) {
187
+ return ;
188
+ }
189
+
190
+ let Some ( arg_place) = args. pop ( ) . unwrap ( ) . place ( )
191
+ else { return } ;
192
+
193
+ statements. push ( Statement {
194
+ source_info : terminator. source_info ,
195
+ kind : StatementKind :: Assign ( box (
196
+ destination_place,
197
+ Rvalue :: Use ( Operand :: Copy (
198
+ arg_place. project_deeper ( & [ ProjectionElem :: Deref ] , self . tcx ) ,
199
+ ) ) ,
200
+ ) ) ,
201
+ } ) ;
202
+ terminator. kind = TerminatorKind :: Goto { target : destination_block } ;
203
+ }
133
204
}
0 commit comments