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,6 +154,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
152154}
153155
154156newtype_index ! {
157+ #[ debug_format = "_v{}" ]
155158 struct VnIndex { }
156159}
157160
@@ -213,6 +216,89 @@ enum Value<'tcx> {
213216 } ,
214217}
215218
219+ /// Stores and deduplicates pairs of `(Value, Ty)` into in `VnIndex` numbered values.
220+ ///
221+ /// This data structure is mostly a partial reimplementation of `FxIndexMap<VnIndex, (Value, Ty)>`.
222+ /// We do not use a regular `FxIndexMap` to skip hashing values that are unique by construction,
223+ /// like opaque values, address with provenance and non-deterministic constants.
224+ struct ValueSet < ' tcx > {
225+ indices : HashTable < VnIndex > ,
226+ hashes : IndexVec < VnIndex , u64 > ,
227+ values : IndexVec < VnIndex , Value < ' tcx > > ,
228+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
229+ /// Counter to generate different values.
230+ next_opaque : usize ,
231+ }
232+
233+ impl < ' tcx > ValueSet < ' tcx > {
234+ fn new ( num_values : usize ) -> ValueSet < ' tcx > {
235+ ValueSet {
236+ indices : HashTable :: with_capacity ( num_values) ,
237+ hashes : IndexVec :: with_capacity ( num_values) ,
238+ values : IndexVec :: with_capacity ( num_values) ,
239+ types : IndexVec :: with_capacity ( num_values) ,
240+ next_opaque : 1 ,
241+ }
242+ }
243+
244+ /// Insert a `(Value, Ty)` pair to be deduplicated.
245+ /// Returns `true` as second tuple field if this value did not exist previously.
246+ #[ allow( rustc:: pass_by_value) ] // closures take `&VnIndex`
247+ fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> ( VnIndex , bool ) {
248+ let hash: u64 = {
249+ let mut h = FxHasher :: default ( ) ;
250+ value. hash ( & mut h) ;
251+ ty. hash ( & mut h) ;
252+ h. finish ( )
253+ } ;
254+
255+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
256+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
257+ match self . indices . entry ( hash, eq, hasher) {
258+ Entry :: Occupied ( entry) => {
259+ let index = * entry. get ( ) ;
260+ ( index, false )
261+ }
262+ Entry :: Vacant ( entry) => {
263+ let index = self . hashes . push ( hash) ;
264+ entry. insert ( index) ;
265+ let _index = self . values . push ( value) ;
266+ debug_assert_eq ! ( index, _index) ;
267+ let _index = self . types . push ( ty) ;
268+ debug_assert_eq ! ( index, _index) ;
269+ ( index, true )
270+ }
271+ }
272+ }
273+
274+ /// Increment the opaque index counter return a new unique value.
275+ #[ inline]
276+ fn next_opaque ( & mut self ) -> usize {
277+ let next_opaque = self . next_opaque ;
278+ self . next_opaque += 1 ;
279+ next_opaque
280+ }
281+
282+ /// Return the `Value` associated with the given `VnIndex`.
283+ #[ inline]
284+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
285+ & self . values [ index]
286+ }
287+
288+ /// Return the type associated with the given `VnIndex`.
289+ #[ inline]
290+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
291+ self . types [ index]
292+ }
293+
294+ /// Replace the value associated with `index` with an opaque value.
295+ #[ inline]
296+ fn forget ( & mut self , index : VnIndex ) {
297+ let opaque = self . next_opaque ( ) ;
298+ self . values [ index] = Value :: Opaque ( opaque) ;
299+ }
300+ }
301+
216302struct VnState < ' body , ' tcx > {
217303 tcx : TyCtxt < ' tcx > ,
218304 ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -223,11 +309,9 @@ struct VnState<'body, 'tcx> {
223309 /// Locals that are assigned that value.
224310 // This vector does not hold all the values of `VnIndex` that we create.
225311 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
226- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
312+ values : ValueSet < ' tcx > ,
227313 /// Values evaluated as constants if possible.
228314 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
229- /// Counter to generate different values.
230- next_opaque : usize ,
231315 /// Cache the deref values.
232316 derefs : Vec < VnIndex > ,
233317 ssa : & ' body SsaLocals ,
@@ -258,9 +342,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
258342 is_coroutine : body. coroutine . is_some ( ) ,
259343 locals : IndexVec :: from_elem ( None , local_decls) ,
260344 rev_locals : IndexVec :: with_capacity ( num_values) ,
261- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
345+ values : ValueSet :: new ( num_values) ,
262346 evaluated : IndexVec :: with_capacity ( num_values) ,
263- next_opaque : 1 ,
264347 derefs : Vec :: new ( ) ,
265348 ssa,
266349 dominators,
@@ -274,8 +357,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
274357
275358 #[ instrument( level = "trace" , skip( self ) , ret) ]
276359 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) ;
360+ let ( index, new) = self . values . insert ( ty, value) ;
279361 if new {
280362 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
281363 let evaluated = self . eval_to_const ( index) ;
@@ -287,17 +369,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
287369 index
288370 }
289371
290- fn next_opaque ( & mut self ) -> usize {
291- let next_opaque = self . next_opaque ;
292- self . next_opaque += 1 ;
293- next_opaque
294- }
295-
296372 /// Create a new `Value` for which we have no information at all, except that it is distinct
297373 /// from all the others.
298374 #[ instrument( level = "trace" , skip( self ) , ret) ]
299375 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
300- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
376+ let value = Value :: Opaque ( self . values . next_opaque ( ) ) ;
301377 self . insert ( ty, value)
302378 }
303379
@@ -311,18 +387,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
311387 }
312388 AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
313389 } ;
314- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
390+ let value = Value :: Address { place, kind, provenance : self . values . next_opaque ( ) } ;
315391 self . insert ( ty, value)
316392 }
317393
318394 #[ inline]
319395 fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
320- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
396+ self . values . value ( index)
321397 }
322398
323399 #[ inline]
324400 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
325- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
401+ self . values . ty ( index)
326402 }
327403
328404 /// Record that `local` is assigned `value`. `local` must be SSA.
@@ -340,7 +416,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
340416 } else {
341417 // Multiple mentions of this constant will yield different values,
342418 // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
343- let disambiguator = self . next_opaque ( ) ;
419+ let disambiguator = self . values . next_opaque ( ) ;
344420 // `disambiguator: 0` means deterministic.
345421 debug_assert_ne ! ( disambiguator, 0 ) ;
346422 disambiguator
@@ -374,8 +450,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
374450
375451 fn invalidate_derefs ( & mut self ) {
376452 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) ;
453+ self . values . forget ( deref) ;
379454 }
380455 }
381456
0 commit comments