@@ -126,7 +126,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
126126 // Clone dominators as we need them while mutating the body.
127127 let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
128128
129- let mut state = VnState :: new ( tcx, param_env, & ssa, & dominators, & body. local_decls ) ;
129+ let mut state = VnState :: new ( tcx, body , param_env, & ssa, & dominators, & body. local_decls ) ;
130130 ssa. for_each_assignment_mut (
131131 body. basic_blocks . as_mut_preserves_cfg ( ) ,
132132 |local, value, location| {
@@ -202,6 +202,7 @@ enum Value<'tcx> {
202202 value : Const < ' tcx > ,
203203 /// Some constants do not have a deterministic value. To avoid merging two instances of the
204204 /// same `Const`, we assign them an additional integer index.
205+ // `disambiguator` is 0 iff the constant is deterministic.
205206 disambiguator : usize ,
206207 } ,
207208 /// An aggregate value, either tuple/closure/struct/enum.
@@ -264,21 +265,29 @@ struct VnState<'body, 'tcx> {
264265impl < ' body , ' tcx > VnState < ' body , ' tcx > {
265266 fn new (
266267 tcx : TyCtxt < ' tcx > ,
268+ body : & Body < ' tcx > ,
267269 param_env : ty:: ParamEnv < ' tcx > ,
268270 ssa : & ' body SsaLocals ,
269271 dominators : & ' body Dominators < BasicBlock > ,
270272 local_decls : & ' body LocalDecls < ' tcx > ,
271273 ) -> Self {
274+ // Compute a rough estimate of the number of values in the body from the number of
275+ // statements. This is meant to reduce the number of allocations, but it's all right if
276+ // we miss the exact amount. We estimate based on 2 values per statement (one in LHS and
277+ // one in RHS) and 4 values per terminator (for call operands).
278+ let num_values =
279+ 2 * body. basic_blocks . iter ( ) . map ( |bbdata| bbdata. statements . len ( ) ) . sum :: < usize > ( )
280+ + 4 * body. basic_blocks . len ( ) ;
272281 VnState {
273282 tcx,
274283 ecx : InterpCx :: new ( tcx, DUMMY_SP , param_env, DummyMachine ) ,
275284 param_env,
276285 local_decls,
277286 locals : IndexVec :: from_elem ( None , local_decls) ,
278- rev_locals : IndexVec :: default ( ) ,
279- values : FxIndexSet :: default ( ) ,
280- evaluated : IndexVec :: new ( ) ,
281- next_opaque : Some ( 0 ) ,
287+ rev_locals : IndexVec :: with_capacity ( num_values ) ,
288+ values : FxIndexSet :: with_capacity_and_hasher ( num_values , Default :: default ( ) ) ,
289+ evaluated : IndexVec :: with_capacity ( num_values ) ,
290+ next_opaque : Some ( 1 ) ,
282291 feature_unsized_locals : tcx. features ( ) . unsized_locals ,
283292 ssa,
284293 dominators,
@@ -291,9 +300,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
291300 let ( index, new) = self . values . insert_full ( value) ;
292301 let index = VnIndex :: from_usize ( index) ;
293302 if new {
303+ // Grow `evaluated` and `rev_locals` here to amortize the allocations.
294304 let evaluated = self . eval_to_const ( index) ;
295305 let _index = self . evaluated . push ( evaluated) ;
296306 debug_assert_eq ! ( index, _index) ;
307+ // No need to push to `rev_locals` if we finished listing assignments.
308+ if self . next_opaque . is_some ( ) {
309+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
310+ debug_assert_eq ! ( index, _index) ;
311+ }
297312 }
298313 index
299314 }
@@ -330,7 +345,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
330345 let is_sized = !self . feature_unsized_locals
331346 || self . local_decls [ local] . ty . is_sized ( self . tcx , self . param_env ) ;
332347 if is_sized {
333- self . rev_locals . ensure_contains_elem ( value, SmallVec :: new ) . push ( local) ;
348+ self . rev_locals [ value] . push ( local) ;
334349 }
335350 }
336351
@@ -344,19 +359,25 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
344359 let next_opaque = self . next_opaque . as_mut ( ) ?;
345360 let disambiguator = * next_opaque;
346361 * next_opaque += 1 ;
362+ // `disambiguator: 0` means deterministic.
363+ debug_assert_ne ! ( disambiguator, 0 ) ;
347364 disambiguator
348365 } ;
349366 Some ( self . insert ( Value :: Constant { value, disambiguator } ) )
350367 }
351368
352369 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
353370 // Booleans are deterministic.
354- self . insert ( Value :: Constant { value : Const :: from_bool ( self . tcx , flag) , disambiguator : 0 } )
371+ let value = Const :: from_bool ( self . tcx , flag) ;
372+ debug_assert ! ( value. is_deterministic( ) ) ;
373+ self . insert ( Value :: Constant { value, disambiguator : 0 } )
355374 }
356375
357376 fn insert_scalar ( & mut self , scalar : Scalar , ty : Ty < ' tcx > ) -> VnIndex {
358- self . insert_constant ( Const :: from_scalar ( self . tcx , scalar, ty) )
359- . expect ( "scalars are deterministic" )
377+ // Scalars are deterministic.
378+ let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
379+ debug_assert ! ( value. is_deterministic( ) ) ;
380+ self . insert ( Value :: Constant { value, disambiguator : 0 } )
360381 }
361382
362383 fn insert_tuple ( & mut self , values : Vec < VnIndex > ) -> VnIndex {
@@ -669,7 +690,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
669690 fn simplify_place_projection ( & mut self , place : & mut Place < ' tcx > , location : Location ) {
670691 // If the projection is indirect, we treat the local as a value, so can replace it with
671692 // another local.
672- if place. is_indirect ( )
693+ if place. is_indirect_first_projection ( )
673694 && let Some ( base) = self . locals [ place. local ]
674695 && let Some ( new_local) = self . try_as_local ( base, location)
675696 && place. local != new_local
@@ -771,10 +792,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
771792 location : Location ,
772793 ) -> Option < VnIndex > {
773794 match * operand {
774- Operand :: Constant ( ref mut constant) => {
775- let const_ = constant. const_ . normalize ( self . tcx , self . param_env ) ;
776- self . insert_constant ( const_)
777- }
795+ Operand :: Constant ( ref constant) => self . insert_constant ( constant. const_ ) ,
778796 Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
779797 let value = self . simplify_place_value ( place, location) ?;
780798 if let Some ( const_) = self . try_as_constant ( value) {
@@ -1369,8 +1387,13 @@ fn op_to_prop_const<'tcx>(
13691387 // If this constant has scalar ABI, return it as a `ConstValue::Scalar`.
13701388 if let Abi :: Scalar ( abi:: Scalar :: Initialized { .. } ) = op. layout . abi
13711389 && let Ok ( scalar) = ecx. read_scalar ( op)
1372- && scalar. try_to_scalar_int ( ) . is_ok ( )
13731390 {
1391+ if !scalar. try_to_scalar_int ( ) . is_ok ( ) {
1392+ // Check that we do not leak a pointer.
1393+ // Those pointers may lose part of their identity in codegen.
1394+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1395+ return None ;
1396+ }
13741397 return Some ( ConstValue :: Scalar ( scalar) ) ;
13751398 }
13761399
@@ -1434,12 +1457,11 @@ impl<'tcx> VnState<'_, 'tcx> {
14341457
14351458 /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
14361459 fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
1437- // This was already constant in MIR, do not change it.
1438- if let Value :: Constant { value, disambiguator : _ } = * self . get ( index)
1439- // If the constant is not deterministic, adding an additional mention of it in MIR will
1440- // not give the same value as the former mention.
1441- && value. is_deterministic ( )
1442- {
1460+ // This was already constant in MIR, do not change it. If the constant is not
1461+ // deterministic, adding an additional mention of it in MIR will not give the same value as
1462+ // the former mention.
1463+ if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1464+ debug_assert ! ( value. is_deterministic( ) ) ;
14431465 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
14441466 }
14451467
0 commit comments