@@ -86,46 +86,37 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
86
86
// Clone dominators as we need them while mutating the body.
87
87
let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
88
88
89
- let mut state = VnState :: new ( tcx, param_env, & body. local_decls ) ;
89
+ let mut state = VnState :: new ( tcx, param_env, & ssa , & dominators , & body. local_decls ) ;
90
90
for arg in body. args_iter ( ) {
91
91
if ssa. is_ssa ( arg) {
92
92
let value = state. new_opaque ( ) . unwrap ( ) ;
93
93
state. assign ( arg, value) ;
94
94
}
95
95
}
96
96
97
- for ( local, rvalue, _ ) in ssa . assignments ( body ) {
98
- let value = state. insert_rvalue ( rvalue) . or_else ( || state. new_opaque ( ) ) . unwrap ( ) ;
97
+ ssa . for_each_assignment_mut ( & mut body . basic_blocks , | local, rvalue, location| {
98
+ let value = state. simplify_rvalue ( rvalue, location ) . or_else ( || state. new_opaque ( ) ) . unwrap ( ) ;
99
99
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as
100
100
// reusable if we have an exact type match.
101
101
if state. local_decls [ local] . ty == rvalue. ty ( state. local_decls , tcx) {
102
102
state. assign ( local, value) ;
103
103
}
104
- }
104
+ } ) ;
105
105
106
106
// Stop creating opaques during replacement as it is useless.
107
107
state. next_opaque = None ;
108
108
109
- let mut any_replacement = false ;
110
- let mut replacer = Replacer {
111
- tcx,
112
- ssa,
113
- dominators,
114
- state,
115
- reused_locals : BitSet :: new_empty ( body. local_decls . len ( ) ) ,
116
- any_replacement : & mut any_replacement,
117
- } ;
118
-
119
109
let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
120
110
for bb in reverse_postorder {
121
111
let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
122
- replacer . visit_basic_block_data ( bb, data) ;
112
+ state . visit_basic_block_data ( bb, data) ;
123
113
}
114
+ let any_replacement = state. any_replacement ;
124
115
125
116
// For each local that is reused (`y` above), we remove its storage statements do avoid any
126
117
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
127
118
// statements.
128
- StorageRemover { tcx, reused_locals : replacer . reused_locals } . visit_body_preserves_cfg ( body) ;
119
+ StorageRemover { tcx, reused_locals : state . reused_locals } . visit_body_preserves_cfg ( body) ;
129
120
130
121
if any_replacement {
131
122
crate :: simplify:: remove_unused_definitions ( body) ;
@@ -189,12 +180,18 @@ struct VnState<'body, 'tcx> {
189
180
/// Counter to generate different values.
190
181
/// This is an option to stop creating opaques during replacement.
191
182
next_opaque : Option < usize > ,
183
+ ssa : & ' body SsaLocals ,
184
+ dominators : & ' body Dominators < BasicBlock > ,
185
+ reused_locals : BitSet < Local > ,
186
+ any_replacement : bool ,
192
187
}
193
188
194
189
impl < ' body , ' tcx > VnState < ' body , ' tcx > {
195
190
fn new (
196
191
tcx : TyCtxt < ' tcx > ,
197
192
param_env : ty:: ParamEnv < ' tcx > ,
193
+ ssa : & ' body SsaLocals ,
194
+ dominators : & ' body Dominators < BasicBlock > ,
198
195
local_decls : & ' body LocalDecls < ' tcx > ,
199
196
) -> Self {
200
197
VnState {
@@ -205,6 +202,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
205
202
rev_locals : FxHashMap :: default ( ) ,
206
203
values : FxIndexSet :: default ( ) ,
207
204
next_opaque : Some ( 0 ) ,
205
+ ssa,
206
+ dominators,
207
+ reused_locals : BitSet :: new_empty ( local_decls. len ( ) ) ,
208
+ any_replacement : false ,
208
209
}
209
210
}
210
211
@@ -252,10 +253,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
252
253
253
254
/// Represent the *value* which would be read from `place`.
254
255
#[ instrument( level = "trace" , skip( self ) , ret) ]
255
- fn insert_place ( & mut self , place : Place < ' tcx > ) -> Option < VnIndex > {
256
+ fn simplify_place ( & mut self , place : & mut Place < ' tcx > , location : Location ) -> Option < VnIndex > {
257
+ // Another place that holds the same value.
258
+ let mut place_ref = place. as_ref ( ) ;
256
259
let mut value = self . locals [ place. local ] ?;
257
260
258
261
for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
262
+ if let Some ( local) = self . try_as_local ( value, location) {
263
+ place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
264
+ }
265
+
259
266
let proj = match proj {
260
267
ProjectionElem :: Deref => {
261
268
let ty = Place :: ty_from (
@@ -293,31 +300,65 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
293
300
value = self . insert ( Value :: Projection ( value, proj) ) ;
294
301
}
295
302
303
+ if let Some ( local) = self . try_as_local ( value, location)
304
+ && local != place. local
305
+ {
306
+ * place = local. into ( ) ;
307
+ self . reused_locals . insert ( local) ;
308
+ self . any_replacement = true ;
309
+ } else if place_ref. local != place. local
310
+ || place_ref. projection . len ( ) < place. projection . len ( )
311
+ {
312
+ * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
313
+ self . reused_locals . insert ( place_ref. local ) ;
314
+ self . any_replacement = true ;
315
+ }
316
+
296
317
Some ( value)
297
318
}
298
319
299
320
#[ instrument( level = "trace" , skip( self ) , ret) ]
300
- fn insert_operand ( & mut self , operand : & Operand < ' tcx > ) -> Option < VnIndex > {
321
+ fn simplify_operand (
322
+ & mut self ,
323
+ operand : & mut Operand < ' tcx > ,
324
+ location : Location ,
325
+ ) -> Option < VnIndex > {
301
326
match * operand {
302
327
Operand :: Constant ( ref constant) => Some ( self . insert ( Value :: Constant ( constant. const_ ) ) ) ,
303
- Operand :: Copy ( place) | Operand :: Move ( place) => self . insert_place ( place) ,
328
+ Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
329
+ let value = self . simplify_place ( place, location) ?;
330
+ if let Some ( const_) = self . try_as_constant ( value) {
331
+ * operand = Operand :: Constant ( Box :: new ( const_) ) ;
332
+ self . any_replacement = true ;
333
+ }
334
+ Some ( value)
335
+ }
304
336
}
305
337
}
306
338
307
339
#[ instrument( level = "trace" , skip( self ) , ret) ]
308
- fn insert_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < VnIndex > {
340
+ fn simplify_rvalue (
341
+ & mut self ,
342
+ rvalue : & mut Rvalue < ' tcx > ,
343
+ location : Location ,
344
+ ) -> Option < VnIndex > {
309
345
let value = match * rvalue {
310
346
// Forward values.
311
- Rvalue :: Use ( ref operand) => return self . insert_operand ( operand) ,
312
- Rvalue :: CopyForDeref ( place) => return self . insert_operand ( & Operand :: Copy ( place) ) ,
347
+ Rvalue :: Use ( ref mut operand) => return self . simplify_operand ( operand, location) ,
348
+ Rvalue :: CopyForDeref ( place) => {
349
+ let mut operand = Operand :: Copy ( place) ;
350
+ let val = self . simplify_operand ( & mut operand, location) ;
351
+ * rvalue = Rvalue :: Use ( operand) ;
352
+ return val;
353
+ }
313
354
314
355
// Roots.
315
- Rvalue :: Repeat ( ref op, amount) => {
316
- let op = self . insert_operand ( op) ?;
356
+ Rvalue :: Repeat ( ref mut op, amount) => {
357
+ let op = self . simplify_operand ( op, location ) ?;
317
358
Value :: Repeat ( op, amount)
318
359
}
319
360
Rvalue :: NullaryOp ( op, ty) => Value :: NullaryOp ( op, ty) ,
320
- Rvalue :: Aggregate ( box ref kind, ref fields) => {
361
+ Rvalue :: Aggregate ( box ref kind, ref mut fields) => {
321
362
let variant_index = match * kind {
322
363
AggregateKind :: Array ( ..)
323
364
| AggregateKind :: Tuple
@@ -328,40 +369,40 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
328
369
AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
329
370
} ;
330
371
let fields: Option < Vec < _ > > = fields
331
- . iter ( )
332
- . map ( |op| self . insert_operand ( op) . or_else ( || self . new_opaque ( ) ) )
372
+ . iter_mut ( )
373
+ . map ( |op| self . simplify_operand ( op, location ) . or_else ( || self . new_opaque ( ) ) )
333
374
. collect ( ) ;
334
375
let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
335
376
Value :: Aggregate ( ty, variant_index, fields?)
336
377
}
337
378
Rvalue :: Ref ( .., place) | Rvalue :: AddressOf ( _, place) => return self . new_pointer ( place) ,
338
379
339
380
// Operations.
340
- Rvalue :: Len ( place) => {
341
- let place = self . insert_place ( place) ?;
381
+ Rvalue :: Len ( ref mut place) => {
382
+ let place = self . simplify_place ( place, location ) ?;
342
383
Value :: Len ( place)
343
384
}
344
- Rvalue :: Cast ( kind, ref value, to) => {
385
+ Rvalue :: Cast ( kind, ref mut value, to) => {
345
386
let from = value. ty ( self . local_decls , self . tcx ) ;
346
- let value = self . insert_operand ( value) ?;
387
+ let value = self . simplify_operand ( value, location ) ?;
347
388
Value :: Cast { kind, value, from, to }
348
389
}
349
- Rvalue :: BinaryOp ( op, box ( ref lhs, ref rhs) ) => {
350
- let lhs = self . insert_operand ( lhs) ? ;
351
- let rhs = self . insert_operand ( rhs) ? ;
352
- Value :: BinaryOp ( op, lhs, rhs)
390
+ Rvalue :: BinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
391
+ let lhs = self . simplify_operand ( lhs, location ) ;
392
+ let rhs = self . simplify_operand ( rhs, location ) ;
393
+ Value :: BinaryOp ( op, lhs? , rhs? )
353
394
}
354
- Rvalue :: CheckedBinaryOp ( op, box ( ref lhs, ref rhs) ) => {
355
- let lhs = self . insert_operand ( lhs) ? ;
356
- let rhs = self . insert_operand ( rhs) ? ;
357
- Value :: CheckedBinaryOp ( op, lhs, rhs)
395
+ Rvalue :: CheckedBinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
396
+ let lhs = self . simplify_operand ( lhs, location ) ;
397
+ let rhs = self . simplify_operand ( rhs, location ) ;
398
+ Value :: CheckedBinaryOp ( op, lhs? , rhs? )
358
399
}
359
- Rvalue :: UnaryOp ( op, ref arg) => {
360
- let arg = self . insert_operand ( arg) ?;
400
+ Rvalue :: UnaryOp ( op, ref mut arg) => {
401
+ let arg = self . simplify_operand ( arg, location ) ?;
361
402
Value :: UnaryOp ( op, arg)
362
403
}
363
- Rvalue :: Discriminant ( place) => {
364
- let place = self . insert_place ( place) ?;
404
+ Rvalue :: Discriminant ( ref mut place) => {
405
+ let place = self . simplify_place ( place, location ) ?;
365
406
Value :: Discriminant ( place)
366
407
}
367
408
@@ -373,22 +414,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373
414
}
374
415
}
375
416
376
- struct Replacer < ' a , ' tcx > {
377
- tcx : TyCtxt < ' tcx > ,
378
- ssa : SsaLocals ,
379
- dominators : Dominators < BasicBlock > ,
380
- state : VnState < ' a , ' tcx > ,
381
- /// Set of locals that are reused, and for which we should remove storage statements to avoid a
382
- /// use-after-StorageDead.
383
- reused_locals : BitSet < Local > ,
384
- any_replacement : & ' a mut bool ,
385
- }
386
-
387
- impl < ' tcx > Replacer < ' _ , ' tcx > {
417
+ impl < ' tcx > VnState < ' _ , ' tcx > {
388
418
/// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
389
419
fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
390
- if let Value :: Constant ( const_) = self . state . get ( index) {
391
- Some ( ConstOperand { span : rustc_span:: DUMMY_SP , user_ty : None , const_ : const_ . clone ( ) } )
420
+ if let Value :: Constant ( const_) = * self . get ( index) {
421
+ Some ( ConstOperand { span : rustc_span:: DUMMY_SP , user_ty : None , const_ } )
392
422
} else {
393
423
None
394
424
}
@@ -397,50 +427,37 @@ impl<'tcx> Replacer<'_, 'tcx> {
397
427
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
398
428
/// return it.
399
429
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
400
- let other = self . state . rev_locals . get ( & index) ?;
430
+ let other = self . rev_locals . get ( & index) ?;
401
431
other
402
432
. iter ( )
403
433
. copied ( )
404
- . find ( |& other| self . ssa . assignment_dominates ( & self . dominators , other, loc) )
434
+ . find ( |& other| self . ssa . assignment_dominates ( self . dominators , other, loc) )
405
435
}
406
436
}
407
437
408
- impl < ' tcx > MutVisitor < ' tcx > for Replacer < ' _ , ' tcx > {
438
+ impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' tcx > {
409
439
fn tcx ( & self ) -> TyCtxt < ' tcx > {
410
440
self . tcx
411
441
}
412
442
413
443
fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
414
- if let Some ( place) = operand. place ( )
415
- && let Some ( value) = self . state . insert_place ( place)
416
- {
417
- if let Some ( const_) = self . try_as_constant ( value) {
418
- * operand = Operand :: Constant ( Box :: new ( const_) ) ;
419
- * self . any_replacement = true ;
420
- } else if let Some ( local) = self . try_as_local ( value, location)
421
- && * operand != Operand :: Move ( local. into ( ) )
422
- {
423
- * operand = Operand :: Copy ( local. into ( ) ) ;
424
- self . reused_locals . insert ( local) ;
425
- * self . any_replacement = true ;
426
- }
427
- }
444
+ self . simplify_operand ( operand, location) ;
428
445
}
429
446
430
447
fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , location : Location ) {
431
448
self . super_statement ( stmt, location) ;
432
449
if let StatementKind :: Assign ( box ( _, ref mut rvalue) ) = stmt. kind
433
- && let Some ( value) = self . state . insert_rvalue ( rvalue)
450
+ && let Some ( value) = self . simplify_rvalue ( rvalue, location )
434
451
{
435
452
if let Some ( const_) = self . try_as_constant ( value) {
436
453
* rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
437
- * self . any_replacement = true ;
454
+ self . any_replacement = true ;
438
455
} else if let Some ( local) = self . try_as_local ( value, location)
439
456
&& * rvalue != Rvalue :: Use ( Operand :: Move ( local. into ( ) ) )
440
457
{
441
458
* rvalue = Rvalue :: Use ( Operand :: Copy ( local. into ( ) ) ) ;
442
459
self . reused_locals . insert ( local) ;
443
- * self . any_replacement = true ;
460
+ self . any_replacement = true ;
444
461
}
445
462
}
446
463
}
0 commit comments