@@ -128,7 +128,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
128
128
// Clone dominators as we need them while mutating the body.
129
129
let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
130
130
131
- let mut state = VnState :: new ( tcx, param_env, & ssa, & dominators, & body. local_decls ) ;
131
+ let mut state = VnState :: new ( tcx, body , param_env, & ssa, & dominators, & body. local_decls ) ;
132
132
ssa. for_each_assignment_mut (
133
133
body. basic_blocks . as_mut_preserves_cfg ( ) ,
134
134
|local, value, location| {
@@ -204,6 +204,7 @@ enum Value<'tcx> {
204
204
value : Const < ' tcx > ,
205
205
/// Some constants do not have a deterministic value. To avoid merging two instances of the
206
206
/// same `Const`, we assign them an additional integer index.
207
+ // `disambiguator` is 0 iff the constant is deterministic.
207
208
disambiguator : usize ,
208
209
} ,
209
210
/// An aggregate value, either tuple/closure/struct/enum.
@@ -266,21 +267,29 @@ struct VnState<'body, 'tcx> {
266
267
impl < ' body , ' tcx > VnState < ' body , ' tcx > {
267
268
fn new (
268
269
tcx : TyCtxt < ' tcx > ,
270
+ body : & Body < ' tcx > ,
269
271
param_env : ty:: ParamEnv < ' tcx > ,
270
272
ssa : & ' body SsaLocals ,
271
273
dominators : & ' body Dominators < BasicBlock > ,
272
274
local_decls : & ' body LocalDecls < ' tcx > ,
273
275
) -> Self {
276
+ // Compute a rough estimate of the number of values in the body from the number of
277
+ // statements. This is meant to reduce the number of allocations, but it's all right if
278
+ // we miss the exact amount. We estimate based on 2 values per statement (one in LHS and
279
+ // one in RHS) and 4 values per terminator (for call operands).
280
+ let num_values =
281
+ 2 * body. basic_blocks . iter ( ) . map ( |bbdata| bbdata. statements . len ( ) ) . sum :: < usize > ( )
282
+ + 4 * body. basic_blocks . len ( ) ;
274
283
VnState {
275
284
tcx,
276
285
ecx : InterpCx :: new ( tcx, DUMMY_SP , param_env, DummyMachine ) ,
277
286
param_env,
278
287
local_decls,
279
288
locals : IndexVec :: from_elem ( None , local_decls) ,
280
- rev_locals : IndexVec :: default ( ) ,
281
- values : FxIndexSet :: default ( ) ,
282
- evaluated : IndexVec :: new ( ) ,
283
- next_opaque : Some ( 0 ) ,
289
+ rev_locals : IndexVec :: with_capacity ( num_values ) ,
290
+ values : FxIndexSet :: with_capacity_and_hasher ( num_values , Default :: default ( ) ) ,
291
+ evaluated : IndexVec :: with_capacity ( num_values ) ,
292
+ next_opaque : Some ( 1 ) ,
284
293
feature_unsized_locals : tcx. features ( ) . unsized_locals ,
285
294
ssa,
286
295
dominators,
@@ -293,9 +302,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
293
302
let ( index, new) = self . values . insert_full ( value) ;
294
303
let index = VnIndex :: from_usize ( index) ;
295
304
if new {
305
+ // Grow `evaluated` and `rev_locals` here to amortize the allocations.
296
306
let evaluated = self . eval_to_const ( index) ;
297
307
let _index = self . evaluated . push ( evaluated) ;
298
308
debug_assert_eq ! ( index, _index) ;
309
+ // No need to push to `rev_locals` if we finished listing assignments.
310
+ if self . next_opaque . is_some ( ) {
311
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
312
+ debug_assert_eq ! ( index, _index) ;
313
+ }
299
314
}
300
315
index
301
316
}
@@ -332,7 +347,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
332
347
let is_sized = !self . feature_unsized_locals
333
348
|| self . local_decls [ local] . ty . is_sized ( self . tcx , self . param_env ) ;
334
349
if is_sized {
335
- self . rev_locals . ensure_contains_elem ( value, SmallVec :: new ) . push ( local) ;
350
+ self . rev_locals [ value] . push ( local) ;
336
351
}
337
352
}
338
353
@@ -346,19 +361,25 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
346
361
let next_opaque = self . next_opaque . as_mut ( ) ?;
347
362
let disambiguator = * next_opaque;
348
363
* next_opaque += 1 ;
364
+ // `disambiguator: 0` means deterministic.
365
+ debug_assert_ne ! ( disambiguator, 0 ) ;
349
366
disambiguator
350
367
} ;
351
368
Some ( self . insert ( Value :: Constant { value, disambiguator } ) )
352
369
}
353
370
354
371
fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
355
372
// Booleans are deterministic.
356
- self . insert ( Value :: Constant { value : Const :: from_bool ( self . tcx , flag) , disambiguator : 0 } )
373
+ let value = Const :: from_bool ( self . tcx , flag) ;
374
+ debug_assert ! ( value. is_deterministic( ) ) ;
375
+ self . insert ( Value :: Constant { value, disambiguator : 0 } )
357
376
}
358
377
359
378
fn insert_scalar ( & mut self , scalar : Scalar , ty : Ty < ' tcx > ) -> VnIndex {
360
- self . insert_constant ( Const :: from_scalar ( self . tcx , scalar, ty) )
361
- . expect ( "scalars are deterministic" )
379
+ // Scalars are deterministic.
380
+ let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
381
+ debug_assert ! ( value. is_deterministic( ) ) ;
382
+ self . insert ( Value :: Constant { value, disambiguator : 0 } )
362
383
}
363
384
364
385
fn insert_tuple ( & mut self , values : Vec < VnIndex > ) -> VnIndex {
@@ -671,7 +692,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
671
692
fn simplify_place_projection ( & mut self , place : & mut Place < ' tcx > , location : Location ) {
672
693
// If the projection is indirect, we treat the local as a value, so can replace it with
673
694
// another local.
674
- if place. is_indirect ( )
695
+ if place. is_indirect_first_projection ( )
675
696
&& let Some ( base) = self . locals [ place. local ]
676
697
&& let Some ( new_local) = self . try_as_local ( base, location)
677
698
&& place. local != new_local
@@ -773,10 +794,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
773
794
location : Location ,
774
795
) -> Option < VnIndex > {
775
796
match * operand {
776
- Operand :: Constant ( ref mut constant) => {
777
- let const_ = constant. const_ . normalize ( self . tcx , self . param_env ) ;
778
- self . insert_constant ( const_)
779
- }
797
+ Operand :: Constant ( ref constant) => self . insert_constant ( constant. const_ ) ,
780
798
Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
781
799
let value = self . simplify_place_value ( place, location) ?;
782
800
if let Some ( const_) = self . try_as_constant ( value) {
@@ -1371,8 +1389,13 @@ fn op_to_prop_const<'tcx>(
1371
1389
// If this constant has scalar ABI, return it as a `ConstValue::Scalar`.
1372
1390
if let Abi :: Scalar ( abi:: Scalar :: Initialized { .. } ) = op. layout . abi
1373
1391
&& let Ok ( scalar) = ecx. read_scalar ( op)
1374
- && scalar. try_to_scalar_int ( ) . is_ok ( )
1375
1392
{
1393
+ if !scalar. try_to_scalar_int ( ) . is_ok ( ) {
1394
+ // Check that we do not leak a pointer.
1395
+ // Those pointers may lose part of their identity in codegen.
1396
+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1397
+ return None ;
1398
+ }
1376
1399
return Some ( ConstValue :: Scalar ( scalar) ) ;
1377
1400
}
1378
1401
@@ -1436,12 +1459,11 @@ impl<'tcx> VnState<'_, 'tcx> {
1436
1459
1437
1460
/// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
1438
1461
fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
1439
- // This was already constant in MIR, do not change it.
1440
- if let Value :: Constant { value, disambiguator : _ } = * self . get ( index)
1441
- // If the constant is not deterministic, adding an additional mention of it in MIR will
1442
- // not give the same value as the former mention.
1443
- && value. is_deterministic ( )
1444
- {
1462
+ // This was already constant in MIR, do not change it. If the constant is not
1463
+ // deterministic, adding an additional mention of it in MIR will not give the same value as
1464
+ // the former mention.
1465
+ if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1466
+ debug_assert ! ( value. is_deterministic( ) ) ;
1445
1467
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1446
1468
}
1447
1469
0 commit comments