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_arena:: DroplessArena ;
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:: { FxHashMap , FxIndexSet , MutableValues } ;
99+ use rustc_data_structures:: fx:: { FxHashMap , FxHasher } ;
98100use rustc_data_structures:: graph:: dominators:: Dominators ;
99101use rustc_hir:: def:: DefKind ;
100102use rustc_index:: bit_set:: DenseBitSet ;
@@ -149,9 +151,17 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
149151}
150152
151153newtype_index ! {
154+ #[ debug_format = "_v{}" ]
152155 struct VnIndex { }
153156}
154157
158+ newtype_index ! {
159+ #[ debug_format = "_o{}" ]
160+ struct VnOpaque { }
161+ }
162+
163+ const DETERMINISTIC : VnOpaque = VnOpaque :: MAX ;
164+
155165#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
156166enum AddressKind {
157167 Ref ( BorrowKind ) ,
@@ -171,14 +181,14 @@ enum Value<'a, 'tcx> {
171181 // Root values.
172182 /// Used to represent values we know nothing about.
173183 /// The `usize` is a counter incremented by `new_opaque`.
174- Opaque ( usize ) ,
184+ Opaque ( VnOpaque ) ,
175185 /// Evaluated or unevaluated constant value.
176186 Constant {
177187 value : Const < ' tcx > ,
178188 /// Some constants do not have a deterministic value. To avoid merging two instances of the
179189 /// same `Const`, we assign them an additional integer index.
180- // `disambiguator` is 0 iff the constant is deterministic.
181- disambiguator : usize ,
190+ // `disambiguator` is `DETERMINISTIC` iff the constant is deterministic.
191+ disambiguator : VnOpaque ,
182192 } ,
183193 /// An aggregate value, either tuple/closure/struct/enum.
184194 /// This does not contain unions, as we cannot reason with the value.
@@ -200,7 +210,7 @@ enum Value<'a, 'tcx> {
200210 projection : & ' a [ ProjectionElem < VnIndex , Ty < ' tcx > > ] ,
201211 kind : AddressKind ,
202212 /// Give each borrow and pointer a different provenance, so we don't merge them.
203- provenance : usize ,
213+ provenance : VnOpaque ,
204214 } ,
205215
206216 // Extractions.
@@ -221,6 +231,85 @@ enum Value<'a, 'tcx> {
221231 } ,
222232}
223233
234+ struct ValueSet < ' a , ' tcx > {
235+ indices : HashTable < VnIndex > ,
236+ hashes : IndexVec < VnIndex , u64 > ,
237+ values : IndexVec < VnIndex , Value < ' a , ' tcx > > ,
238+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
239+ opaques : IndexVec < VnOpaque , VnIndex > ,
240+ }
241+
242+ impl < ' a , ' tcx > ValueSet < ' a , ' tcx > {
243+ fn new ( num_values : usize ) -> ValueSet < ' a , ' tcx > {
244+ ValueSet {
245+ indices : HashTable :: with_capacity ( num_values) ,
246+ hashes : IndexVec :: with_capacity ( num_values) ,
247+ values : IndexVec :: with_capacity ( num_values) ,
248+ types : IndexVec :: with_capacity ( num_values) ,
249+ opaques : IndexVec :: with_capacity ( num_values) ,
250+ }
251+ }
252+
253+ #[ inline]
254+ fn insert_unique (
255+ & mut self ,
256+ ty : Ty < ' tcx > ,
257+ value : impl FnOnce ( VnOpaque ) -> Value < ' a , ' tcx > ,
258+ ) -> VnIndex {
259+ let index = self . hashes . push ( 0 ) ;
260+ let _index = self . types . push ( ty) ;
261+ debug_assert_eq ! ( index, _index) ;
262+ let opaque = self . opaques . push ( index) ;
263+ let _index = self . values . push ( value ( opaque) ) ;
264+ debug_assert_eq ! ( index, _index) ;
265+ index
266+ }
267+
268+ #[ allow( rustc:: pass_by_value) ]
269+ fn insert ( & mut self , value : Value < ' a , ' tcx > , ty : Ty < ' tcx > ) -> ( VnIndex , bool ) {
270+ let hash: u64 = {
271+ let mut h = FxHasher :: default ( ) ;
272+ value. hash ( & mut h) ;
273+ ty. hash ( & mut h) ;
274+ h. finish ( )
275+ } ;
276+
277+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
278+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
279+ match self . indices . entry ( hash, eq, hasher) {
280+ Entry :: Occupied ( entry) => {
281+ let index = * entry. get ( ) ;
282+ ( index, false )
283+ }
284+ Entry :: Vacant ( entry) => {
285+ let index = self . hashes . push ( hash) ;
286+ entry. insert ( index) ;
287+ let _index = self . values . push ( value) ;
288+ debug_assert_eq ! ( index, _index) ;
289+ let _index = self . types . push ( ty) ;
290+ debug_assert_eq ! ( index, _index) ;
291+ ( index, true )
292+ }
293+ }
294+ }
295+
296+ #[ inline]
297+ fn value ( & self , index : VnIndex ) -> Value < ' a , ' tcx > {
298+ self . values [ index]
299+ }
300+
301+ #[ inline]
302+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
303+ self . types [ index]
304+ }
305+
306+ #[ inline]
307+ fn forget ( & mut self , index : VnIndex ) {
308+ let opaque = self . opaques . push ( index) ;
309+ self . values [ index] = Value :: Opaque ( opaque) ;
310+ }
311+ }
312+
224313struct VnState < ' body , ' a , ' tcx > {
225314 tcx : TyCtxt < ' tcx > ,
226315 ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -233,11 +322,9 @@ struct VnState<'body, 'a, 'tcx> {
233322 rev_locals_ssa : IndexVec < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
234323 // This vector holds the locals that are not SSA.
235324 rev_locals_non_ssa : FxHashMap < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
236- values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
325+ values : ValueSet < ' a , ' tcx > ,
237326 /// Values evaluated as constants if possible.
238327 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
239- /// Counter to generate different values.
240- next_opaque : usize ,
241328 /// Cache the deref values.
242329 derefs : Vec < VnIndex > ,
243330 ssa : & ' body SsaLocals ,
@@ -271,9 +358,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
271358 locals : IndexVec :: with_capacity ( body. local_decls . len ( ) ) ,
272359 rev_locals_ssa : IndexVec :: with_capacity ( num_values) ,
273360 rev_locals_non_ssa : FxHashMap :: default ( ) ,
274- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
361+ values : ValueSet :: new ( num_values) ,
275362 evaluated : IndexVec :: with_capacity ( num_values) ,
276- next_opaque : 1 ,
277363 derefs : Vec :: new ( ) ,
278364 ssa,
279365 dominators,
@@ -299,10 +385,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
299385
300386 #[ instrument( level = "trace" , skip( self ) , ret) ]
301387 fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' a , ' tcx > ) -> VnIndex {
302- let ( index, new) = self . values . insert_full ( ( value, ty) ) ;
303- let index = VnIndex :: from_usize ( index) ;
388+ let ( index, new) = self . values . insert ( value, ty) ;
304389 if new {
305- // Grow `evaluated` and `rev_locals ` here to amortize the allocations.
390+ // Grow `evaluated` and `rev_locals_ssa ` here to amortize the allocations.
306391 let evaluated = self . eval_to_const ( index) ;
307392 let _index = self . evaluated . push ( evaluated) ;
308393 debug_assert_eq ! ( index, _index) ;
@@ -312,18 +397,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
312397 index
313398 }
314399
315- fn next_opaque ( & mut self ) -> usize {
316- let next_opaque = self . next_opaque ;
317- self . next_opaque += 1 ;
318- next_opaque
319- }
320-
321400 /// Create a new `Value` for which we have no information at all, except that it is distinct
322401 /// from all the others.
323402 #[ instrument( level = "trace" , skip( self ) , ret) ]
324403 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
325- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
326- self . insert ( ty, value)
404+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
405+ let _index = self . evaluated . push ( None ) ;
406+ debug_assert_eq ! ( index, _index) ;
407+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
408+ debug_assert_eq ! ( index, _index) ;
409+ index
327410 }
328411
329412 /// Create a new `Value::Address` distinct from all the others.
@@ -352,25 +435,57 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
352435 AddressBase :: Local ( place. local )
353436 } ;
354437 // Do not try evaluating inside `Index`, this has been done by `simplify_place_value`.
355- let projection = self
356- . arena
357- . try_alloc_from_iter (
358- projection
359- . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ,
360- )
361- . ok ( ) ?;
362- let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
363- Some ( self . insert ( ty, value) )
438+ let projection = projection
439+ . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ;
440+ let projection = self . arena . try_alloc_from_iter ( projection) . ok ( ) ?;
441+
442+ let index = self . values . insert_unique ( ty, |provenance| Value :: Address {
443+ base,
444+ projection,
445+ kind,
446+ provenance,
447+ } ) ;
448+ let evaluated = self . eval_to_const ( index) ;
449+ let _index = self . evaluated . push ( evaluated) ;
450+ debug_assert_eq ! ( index, _index) ;
451+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
452+ debug_assert_eq ! ( index, _index) ;
453+ Some ( index)
454+ }
455+
456+ #[ instrument( level = "trace" , skip( self ) , ret) ]
457+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
458+ let ( index, new) = if value. is_deterministic ( ) {
459+ // The constant is deterministic, no need to disambiguate.
460+ let constant = Value :: Constant { value, disambiguator : DETERMINISTIC } ;
461+ self . values . insert ( constant, value. ty ( ) )
462+ } else {
463+ // Multiple mentions of this constant will yield different values,
464+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
465+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| {
466+ debug_assert_ne ! ( disambiguator, DETERMINISTIC ) ;
467+ Value :: Constant { value, disambiguator }
468+ } ) ;
469+ ( index, true )
470+ } ;
471+ if new {
472+ let evaluated = self . eval_to_const ( index) ;
473+ let _index = self . evaluated . push ( evaluated) ;
474+ debug_assert_eq ! ( index, _index) ;
475+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
476+ debug_assert_eq ! ( index, _index) ;
477+ }
478+ index
364479 }
365480
366481 #[ inline]
367482 fn get ( & self , index : VnIndex ) -> Value < ' a , ' tcx > {
368- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
483+ self . values . value ( index)
369484 }
370485
371486 #[ inline]
372487 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
373- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
488+ self . values . ty ( index)
374489 }
375490
376491 /// Record that `local` is assigned `value`.
@@ -406,33 +521,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
406521 }
407522 }
408523
409- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
410- let disambiguator = if value. is_deterministic ( ) {
411- // The constant is deterministic, no need to disambiguate.
412- 0
413- } else {
414- // Multiple mentions of this constant will yield different values,
415- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
416- let disambiguator = self . next_opaque ( ) ;
417- // `disambiguator: 0` means deterministic.
418- debug_assert_ne ! ( disambiguator, 0 ) ;
419- disambiguator
420- } ;
421- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
422- }
423-
424524 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
425525 // Booleans are deterministic.
426526 let value = Const :: from_bool ( self . tcx , flag) ;
427527 debug_assert ! ( value. is_deterministic( ) ) ;
428- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
528+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : DETERMINISTIC } )
429529 }
430530
431531 fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
432532 // Scalars are deterministic.
433533 let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
434534 debug_assert ! ( value. is_deterministic( ) ) ;
435- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
535+ self . insert ( ty, Value :: Constant { value, disambiguator : DETERMINISTIC } )
436536 }
437537
438538 fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : & [ VnIndex ] ) -> VnIndex {
@@ -447,8 +547,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
447547
448548 fn invalidate_derefs ( & mut self ) {
449549 for deref in std:: mem:: take ( & mut self . derefs ) {
450- let opaque = self . next_opaque ( ) ;
451- self . values . get_index_mut2 ( deref. index ( ) ) . unwrap ( ) . 0 = Value :: Opaque ( opaque) ;
550+ self . values . forget ( deref) ;
452551 }
453552 }
454553
@@ -1714,7 +1813,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17141813 // This was already constant in MIR, do not change it. If the constant is not
17151814 // deterministic, adding an additional mention of it in MIR will not give the same value as
17161815 // the former mention.
1717- if let Value :: Constant { value, disambiguator : 0 } = self . get ( index) {
1816+ if let Value :: Constant { value, disambiguator : DETERMINISTIC } = self . get ( index) {
17181817 debug_assert ! ( value. is_deterministic( ) ) ;
17191818 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
17201819 }
0 commit comments