8585//! that contain `AllocId`s.
8686
8787use std:: borrow:: Cow ;
88+ use std:: hash:: { Hash , Hasher } ;
8889
8990use either:: Either ;
91+ use hashbrown:: hash_table:: { Entry , HashTable } ;
9092use itertools:: Itertools as _;
9193use rustc_abi:: { self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx } ;
9294use rustc_const_eval:: const_eval:: DummyMachine ;
9395use rustc_const_eval:: interpret:: {
9496 ImmTy , Immediate , InterpCx , MemPlaceMeta , MemoryKind , OpTy , Projectable , Scalar ,
9597 intern_const_alloc_for_constprop,
9698} ;
97- use rustc_data_structures:: fx:: { FxIndexSet , MutableValues } ;
99+ use rustc_data_structures:: fx:: FxHasher ;
98100use rustc_data_structures:: graph:: dominators:: Dominators ;
99101use rustc_hir:: def:: DefKind ;
100102use rustc_index:: bit_set:: DenseBitSet ;
@@ -152,9 +154,23 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
152154}
153155
154156newtype_index ! {
157+ #[ debug_format = "_v{}" ]
155158 struct VnIndex { }
156159}
157160
161+ #[ derive( Copy , Clone , Debug , Eq ) ]
162+ struct VnOpaque ;
163+ impl PartialEq for VnOpaque {
164+ fn eq ( & self , _: & VnOpaque ) -> bool {
165+ unreachable ! ( )
166+ }
167+ }
168+ impl Hash for VnOpaque {
169+ fn hash < T : Hasher > ( & self , _: & mut T ) {
170+ unreachable ! ( )
171+ }
172+ }
173+
158174#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
159175enum AddressKind {
160176 Ref ( BorrowKind ) ,
@@ -166,14 +182,14 @@ enum Value<'tcx> {
166182 // Root values.
167183 /// Used to represent values we know nothing about.
168184 /// The `usize` is a counter incremented by `new_opaque`.
169- Opaque ( usize ) ,
185+ Opaque ( VnOpaque ) ,
170186 /// Evaluated or unevaluated constant value.
171187 Constant {
172188 value : Const < ' tcx > ,
173189 /// Some constants do not have a deterministic value. To avoid merging two instances of the
174190 /// same `Const`, we assign them an additional integer index.
175- // `disambiguator` is 0 iff the constant is deterministic.
176- disambiguator : usize ,
191+ // `disambiguator` is `None` iff the constant is deterministic.
192+ disambiguator : Option < VnOpaque > ,
177193 } ,
178194 /// An aggregate value, either tuple/closure/struct/enum.
179195 /// This does not contain unions, as we cannot reason with the value.
@@ -192,7 +208,7 @@ enum Value<'tcx> {
192208 place : Place < ' tcx > ,
193209 kind : AddressKind ,
194210 /// Give each borrow and pointer a different provenance, so we don't merge them.
195- provenance : usize ,
211+ provenance : VnOpaque ,
196212 } ,
197213
198214 // Extractions.
@@ -213,6 +229,106 @@ enum Value<'tcx> {
213229 } ,
214230}
215231
232+ /// Stores and deduplicates pairs of `(Value, Ty)` into in `VnIndex` numbered values.
233+ ///
234+ /// This data structure is mostly a partial reimplementation of `FxIndexMap<VnIndex, (Value, Ty)>`.
235+ /// We do not use a regular `FxIndexMap` to skip hashing values that are unique by construction,
236+ /// like opaque values, address with provenance and non-deterministic constants.
237+ struct ValueSet < ' tcx > {
238+ indices : HashTable < VnIndex > ,
239+ hashes : IndexVec < VnIndex , u64 > ,
240+ values : IndexVec < VnIndex , Value < ' tcx > > ,
241+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
242+ }
243+
244+ impl < ' tcx > ValueSet < ' tcx > {
245+ fn new ( num_values : usize ) -> ValueSet < ' tcx > {
246+ ValueSet {
247+ indices : HashTable :: with_capacity ( num_values) ,
248+ hashes : IndexVec :: with_capacity ( num_values) ,
249+ values : IndexVec :: with_capacity ( num_values) ,
250+ types : IndexVec :: with_capacity ( num_values) ,
251+ }
252+ }
253+
254+ /// Insert a `(Value, Ty)` pair without hashing or deduplication.
255+ #[ inline]
256+ fn insert_unique (
257+ & mut self ,
258+ ty : Ty < ' tcx > ,
259+ value : impl FnOnce ( VnOpaque ) -> Value < ' tcx > ,
260+ ) -> VnIndex {
261+ let value = value ( VnOpaque ) ;
262+
263+ debug_assert ! ( match value {
264+ Value :: Opaque ( _) | Value :: Address { .. } => true ,
265+ Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
266+ _ => false ,
267+ } ) ;
268+
269+ let index = self . hashes . push ( 0 ) ;
270+ let _index = self . types . push ( ty) ;
271+ debug_assert_eq ! ( index, _index) ;
272+ let _index = self . values . push ( value) ;
273+ debug_assert_eq ! ( index, _index) ;
274+ index
275+ }
276+
277+ /// Insert a `(Value, Ty)` pair to be deduplicated.
278+ /// Returns `true` as second tuple field if this value did not exist previously.
279+ #[ allow( rustc:: pass_by_value) ] // closures take `&VnIndex`
280+ fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> ( VnIndex , bool ) {
281+ debug_assert ! ( match value {
282+ Value :: Opaque ( _) | Value :: Address { .. } => false ,
283+ Value :: Constant { disambiguator, .. } => disambiguator. is_none( ) ,
284+ _ => true ,
285+ } ) ;
286+
287+ let hash: u64 = {
288+ let mut h = FxHasher :: default ( ) ;
289+ value. hash ( & mut h) ;
290+ ty. hash ( & mut h) ;
291+ h. finish ( )
292+ } ;
293+
294+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
295+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
296+ match self . indices . entry ( hash, eq, hasher) {
297+ Entry :: Occupied ( entry) => {
298+ let index = * entry. get ( ) ;
299+ ( index, false )
300+ }
301+ Entry :: Vacant ( entry) => {
302+ let index = self . hashes . push ( hash) ;
303+ entry. insert ( index) ;
304+ let _index = self . values . push ( value) ;
305+ debug_assert_eq ! ( index, _index) ;
306+ let _index = self . types . push ( ty) ;
307+ debug_assert_eq ! ( index, _index) ;
308+ ( index, true )
309+ }
310+ }
311+ }
312+
313+ /// Return the `Value` associated with the given `VnIndex`.
314+ #[ inline]
315+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
316+ & self . values [ index]
317+ }
318+
319+ /// Return the type associated with the given `VnIndex`.
320+ #[ inline]
321+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
322+ self . types [ index]
323+ }
324+
325+ /// Replace the value associated with `index` with an opaque value.
326+ #[ inline]
327+ fn forget ( & mut self , index : VnIndex ) {
328+ self . values [ index] = Value :: Opaque ( VnOpaque ) ;
329+ }
330+ }
331+
216332struct VnState < ' body , ' tcx > {
217333 tcx : TyCtxt < ' tcx > ,
218334 ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -223,11 +339,9 @@ struct VnState<'body, 'tcx> {
223339 /// Locals that are assigned that value.
224340 // This vector does not hold all the values of `VnIndex` that we create.
225341 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
226- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
342+ values : ValueSet < ' tcx > ,
227343 /// Values evaluated as constants if possible.
228344 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
229- /// Counter to generate different values.
230- next_opaque : usize ,
231345 /// Cache the deref values.
232346 derefs : Vec < VnIndex > ,
233347 ssa : & ' body SsaLocals ,
@@ -258,9 +372,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
258372 is_coroutine : body. coroutine . is_some ( ) ,
259373 locals : IndexVec :: from_elem ( None , local_decls) ,
260374 rev_locals : IndexVec :: with_capacity ( num_values) ,
261- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
375+ values : ValueSet :: new ( num_values) ,
262376 evaluated : IndexVec :: with_capacity ( num_values) ,
263- next_opaque : 1 ,
264377 derefs : Vec :: new ( ) ,
265378 ssa,
266379 dominators,
@@ -274,8 +387,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
274387
275388 #[ instrument( level = "trace" , skip( self ) , ret) ]
276389 fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> VnIndex {
277- let ( index, new) = self . values . insert_full ( ( value, ty) ) ;
278- let index = VnIndex :: from_usize ( index) ;
390+ let ( index, new) = self . values . insert ( ty, value) ;
279391 if new {
280392 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
281393 let evaluated = self . eval_to_const ( index) ;
@@ -287,18 +399,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
287399 index
288400 }
289401
290- fn next_opaque ( & mut self ) -> usize {
291- let next_opaque = self . next_opaque ;
292- self . next_opaque += 1 ;
293- next_opaque
294- }
295-
296402 /// Create a new `Value` for which we have no information at all, except that it is distinct
297403 /// from all the others.
298404 #[ instrument( level = "trace" , skip( self ) , ret) ]
299405 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
300- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
301- self . insert ( ty, value)
406+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
407+ let _index = self . evaluated . push ( None ) ;
408+ debug_assert_eq ! ( index, _index) ;
409+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
410+ debug_assert_eq ! ( index, _index) ;
411+ index
302412 }
303413
304414 /// Create a new `Value::Address` distinct from all the others.
@@ -311,18 +421,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
311421 }
312422 AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
313423 } ;
314- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
315- self . insert ( ty, value)
424+ let index =
425+ self . values . insert_unique ( ty, |provenance| Value :: Address { place, kind, provenance } ) ;
426+ let evaluated = self . eval_to_const ( index) ;
427+ let _index = self . evaluated . push ( evaluated) ;
428+ debug_assert_eq ! ( index, _index) ;
429+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
430+ debug_assert_eq ! ( index, _index) ;
431+ index
432+ }
433+
434+ #[ instrument( level = "trace" , skip( self ) , ret) ]
435+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
436+ let ( index, new) = if value. is_deterministic ( ) {
437+ // The constant is deterministic, no need to disambiguate.
438+ let constant = Value :: Constant { value, disambiguator : None } ;
439+ self . values . insert ( value. ty ( ) , constant)
440+ } else {
441+ // Multiple mentions of this constant will yield different values,
442+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
443+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| Value :: Constant {
444+ value,
445+ disambiguator : Some ( disambiguator) ,
446+ } ) ;
447+ ( index, true )
448+ } ;
449+ if new {
450+ let evaluated = self . eval_to_const ( index) ;
451+ let _index = self . evaluated . push ( evaluated) ;
452+ debug_assert_eq ! ( index, _index) ;
453+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
454+ debug_assert_eq ! ( index, _index) ;
455+ }
456+ index
316457 }
317458
318459 #[ inline]
319460 fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
320- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
461+ self . values . value ( index)
321462 }
322463
323464 #[ inline]
324465 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
325- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
466+ self . values . ty ( index)
326467 }
327468
328469 /// Record that `local` is assigned `value`. `local` must be SSA.
@@ -333,33 +474,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
333474 self . rev_locals [ value] . push ( local) ;
334475 }
335476
336- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
337- let disambiguator = if value. is_deterministic ( ) {
338- // The constant is deterministic, no need to disambiguate.
339- 0
340- } else {
341- // Multiple mentions of this constant will yield different values,
342- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
343- let disambiguator = self . next_opaque ( ) ;
344- // `disambiguator: 0` means deterministic.
345- debug_assert_ne ! ( disambiguator, 0 ) ;
346- disambiguator
347- } ;
348- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
349- }
350-
351477 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
352478 // Booleans are deterministic.
353479 let value = Const :: from_bool ( self . tcx , flag) ;
354480 debug_assert ! ( value. is_deterministic( ) ) ;
355- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
481+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : None } )
356482 }
357483
358484 fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
359485 // Scalars are deterministic.
360486 let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
361487 debug_assert ! ( value. is_deterministic( ) ) ;
362- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
488+ self . insert ( ty, Value :: Constant { value, disambiguator : None } )
363489 }
364490
365491 fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : Vec < VnIndex > ) -> VnIndex {
@@ -374,8 +500,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
374500
375501 fn invalidate_derefs ( & mut self ) {
376502 for deref in std:: mem:: take ( & mut self . derefs ) {
377- let opaque = self . next_opaque ( ) ;
378- self . values . get_index_mut2 ( deref. index ( ) ) . unwrap ( ) . 0 = Value :: Opaque ( opaque) ;
503+ self . values . forget ( deref) ;
379504 }
380505 }
381506
@@ -1605,7 +1730,7 @@ impl<'tcx> VnState<'_, 'tcx> {
16051730 // This was already constant in MIR, do not change it. If the constant is not
16061731 // deterministic, adding an additional mention of it in MIR will not give the same value as
16071732 // the former mention.
1608- if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1733+ if let Value :: Constant { value, disambiguator : None } = * self . get ( index) {
16091734 debug_assert ! ( value. is_deterministic( ) ) ;
16101735 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
16111736 }
0 commit comments