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 rustc_abi:: { self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx } ;
9193use rustc_const_eval:: const_eval:: DummyMachine ;
9294use rustc_const_eval:: interpret:: {
9395 ImmTy , Immediate , InterpCx , MemPlaceMeta , MemoryKind , OpTy , Projectable , Scalar ,
9496 intern_const_alloc_for_constprop,
9597} ;
96- use rustc_data_structures:: fx:: { FxIndexSet , MutableValues } ;
98+ use rustc_data_structures:: fx:: FxHasher ;
9799use rustc_data_structures:: graph:: dominators:: Dominators ;
98100use rustc_hir:: def:: DefKind ;
99101use rustc_index:: bit_set:: DenseBitSet ;
@@ -151,6 +153,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
151153}
152154
153155newtype_index ! {
156+ #[ debug_format = "_v{}" ]
154157 struct VnIndex { }
155158}
156159
@@ -212,6 +215,89 @@ enum Value<'tcx> {
212215 } ,
213216}
214217
218+ /// Stores and deduplicates pairs of `(Value, Ty)` into in `VnIndex` numbered values.
219+ ///
220+ /// This data structure is mostly a partial reimplementation of `FxIndexMap<VnIndex, (Value, Ty)>`.
221+ /// We do not use a regular `FxIndexMap` to skip hashing values that are unique by construction,
222+ /// like opaque values, address with provenance and non-deterministic constants.
223+ struct ValueSet < ' tcx > {
224+ indices : HashTable < VnIndex > ,
225+ hashes : IndexVec < VnIndex , u64 > ,
226+ values : IndexVec < VnIndex , Value < ' tcx > > ,
227+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
228+ /// Counter to generate different values.
229+ next_opaque : usize ,
230+ }
231+
232+ impl < ' tcx > ValueSet < ' tcx > {
233+ fn new ( num_values : usize ) -> ValueSet < ' tcx > {
234+ ValueSet {
235+ indices : HashTable :: with_capacity ( num_values) ,
236+ hashes : IndexVec :: with_capacity ( num_values) ,
237+ values : IndexVec :: with_capacity ( num_values) ,
238+ types : IndexVec :: with_capacity ( num_values) ,
239+ next_opaque : 1 ,
240+ }
241+ }
242+
243+ /// Insert a `(Value, Ty)` pair to be deduplicated.
244+ /// Returns `true` as second tuple field if this value did not exist previously.
245+ #[ allow( rustc:: pass_by_value) ] // closures take `&VnIndex`
246+ fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> ( VnIndex , bool ) {
247+ let hash: u64 = {
248+ let mut h = FxHasher :: default ( ) ;
249+ value. hash ( & mut h) ;
250+ ty. hash ( & mut h) ;
251+ h. finish ( )
252+ } ;
253+
254+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
255+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
256+ match self . indices . entry ( hash, eq, hasher) {
257+ Entry :: Occupied ( entry) => {
258+ let index = * entry. get ( ) ;
259+ ( index, false )
260+ }
261+ Entry :: Vacant ( entry) => {
262+ let index = self . hashes . push ( hash) ;
263+ entry. insert ( index) ;
264+ let _index = self . values . push ( value) ;
265+ debug_assert_eq ! ( index, _index) ;
266+ let _index = self . types . push ( ty) ;
267+ debug_assert_eq ! ( index, _index) ;
268+ ( index, true )
269+ }
270+ }
271+ }
272+
273+ /// Increment the opaque index counter return a new unique value.
274+ #[ inline]
275+ fn next_opaque ( & mut self ) -> usize {
276+ let next_opaque = self . next_opaque ;
277+ self . next_opaque += 1 ;
278+ next_opaque
279+ }
280+
281+ /// Return the `Value` associated with the given `VnIndex`.
282+ #[ inline]
283+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
284+ & self . values [ index]
285+ }
286+
287+ /// Return the type associated with the given `VnIndex`.
288+ #[ inline]
289+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
290+ self . types [ index]
291+ }
292+
293+ /// Replace the value associated with `index` with an opaque value.
294+ #[ inline]
295+ fn forget ( & mut self , index : VnIndex ) {
296+ let opaque = self . next_opaque ( ) ;
297+ self . values [ index] = Value :: Opaque ( opaque) ;
298+ }
299+ }
300+
215301struct VnState < ' body , ' tcx > {
216302 tcx : TyCtxt < ' tcx > ,
217303 ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -222,11 +308,9 @@ struct VnState<'body, 'tcx> {
222308 /// Locals that are assigned that value.
223309 // This vector does not hold all the values of `VnIndex` that we create.
224310 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
311+ values : ValueSet < ' tcx > ,
226312 /// Values evaluated as constants if possible.
227313 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228- /// Counter to generate different values.
229- next_opaque : usize ,
230314 /// Cache the deref values.
231315 derefs : Vec < VnIndex > ,
232316 ssa : & ' body SsaLocals ,
@@ -257,9 +341,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257341 is_coroutine : body. coroutine . is_some ( ) ,
258342 locals : IndexVec :: from_elem ( None , local_decls) ,
259343 rev_locals : IndexVec :: with_capacity ( num_values) ,
260- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
344+ values : ValueSet :: new ( num_values) ,
261345 evaluated : IndexVec :: with_capacity ( num_values) ,
262- next_opaque : 1 ,
263346 derefs : Vec :: new ( ) ,
264347 ssa,
265348 dominators,
@@ -273,8 +356,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273356
274357 #[ instrument( level = "trace" , skip( self ) , ret) ]
275358 fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> VnIndex {
276- let ( index, new) = self . values . insert_full ( ( value, ty) ) ;
277- let index = VnIndex :: from_usize ( index) ;
359+ let ( index, new) = self . values . insert ( ty, value) ;
278360 if new {
279361 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
280362 let evaluated = self . eval_to_const ( index) ;
@@ -286,17 +368,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286368 index
287369 }
288370
289- fn next_opaque ( & mut self ) -> usize {
290- let next_opaque = self . next_opaque ;
291- self . next_opaque += 1 ;
292- next_opaque
293- }
294-
295371 /// Create a new `Value` for which we have no information at all, except that it is distinct
296372 /// from all the others.
297373 #[ instrument( level = "trace" , skip( self ) , ret) ]
298374 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
299- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
375+ let value = Value :: Opaque ( self . values . next_opaque ( ) ) ;
300376 self . insert ( ty, value)
301377 }
302378
@@ -310,18 +386,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310386 }
311387 AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
312388 } ;
313- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
389+ let value = Value :: Address { place, kind, provenance : self . values . next_opaque ( ) } ;
314390 self . insert ( ty, value)
315391 }
316392
317393 #[ inline]
318394 fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
395+ self . values . value ( index)
320396 }
321397
322398 #[ inline]
323399 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
324- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
400+ self . values . ty ( index)
325401 }
326402
327403 /// Record that `local` is assigned `value`. `local` must be SSA.
@@ -339,7 +415,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339415 } else {
340416 // Multiple mentions of this constant will yield different values,
341417 // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342- let disambiguator = self . next_opaque ( ) ;
418+ let disambiguator = self . values . next_opaque ( ) ;
343419 // `disambiguator: 0` means deterministic.
344420 debug_assert_ne ! ( disambiguator, 0 ) ;
345421 disambiguator
@@ -373,8 +449,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373449
374450 fn invalidate_derefs ( & mut self ) {
375451 for deref in std:: mem:: take ( & mut self . derefs ) {
376- let opaque = self . next_opaque ( ) ;
377- self . values . get_index_mut2 ( deref. index ( ) ) . unwrap ( ) . 0 = Value :: Opaque ( opaque) ;
452+ self . values . forget ( deref) ;
378453 }
379454 }
380455
0 commit comments