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,9 +153,17 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
151153}
152154
153155newtype_index ! {
156+ #[ debug_format = "_v{}" ]
154157 struct VnIndex { }
155158}
156159
160+ newtype_index ! {
161+ #[ debug_format = "_o{}" ]
162+ struct VnOpaque { }
163+ }
164+
165+ const DETERMINISTIC : VnOpaque = VnOpaque :: MAX ;
166+
157167#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
158168enum AddressKind {
159169 Ref ( BorrowKind ) ,
@@ -165,14 +175,14 @@ enum Value<'tcx> {
165175 // Root values.
166176 /// Used to represent values we know nothing about.
167177 /// The `usize` is a counter incremented by `new_opaque`.
168- Opaque ( usize ) ,
178+ Opaque ( VnOpaque ) ,
169179 /// Evaluated or unevaluated constant value.
170180 Constant {
171181 value : Const < ' tcx > ,
172182 /// Some constants do not have a deterministic value. To avoid merging two instances of the
173183 /// same `Const`, we assign them an additional integer index.
174- // `disambiguator` is 0 iff the constant is deterministic.
175- disambiguator : usize ,
184+ // `disambiguator` is `DETERMINISTIC` iff the constant is deterministic.
185+ disambiguator : VnOpaque ,
176186 } ,
177187 /// An aggregate value, either tuple/closure/struct/enum.
178188 /// This does not contain unions, as we cannot reason with the value.
@@ -191,7 +201,7 @@ enum Value<'tcx> {
191201 place : Place < ' tcx > ,
192202 kind : AddressKind ,
193203 /// Give each borrow and pointer a different provenance, so we don't merge them.
194- provenance : usize ,
204+ provenance : VnOpaque ,
195205 } ,
196206
197207 // Extractions.
@@ -212,6 +222,85 @@ enum Value<'tcx> {
212222 } ,
213223}
214224
225+ struct ValueSet < ' tcx > {
226+ indices : HashTable < VnIndex > ,
227+ hashes : IndexVec < VnIndex , u64 > ,
228+ values : IndexVec < VnIndex , Value < ' tcx > > ,
229+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
230+ opaques : IndexVec < VnOpaque , VnIndex > ,
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+ opaques : IndexVec :: with_capacity ( num_values) ,
241+ }
242+ }
243+
244+ #[ inline]
245+ fn insert_unique (
246+ & mut self ,
247+ ty : Ty < ' tcx > ,
248+ value : impl FnOnce ( VnOpaque ) -> Value < ' tcx > ,
249+ ) -> VnIndex {
250+ let index = self . hashes . push ( 0 ) ;
251+ let _index = self . types . push ( ty) ;
252+ debug_assert_eq ! ( index, _index) ;
253+ let opaque = self . opaques . push ( index) ;
254+ let _index = self . values . push ( value ( opaque) ) ;
255+ debug_assert_eq ! ( index, _index) ;
256+ index
257+ }
258+
259+ #[ allow( rustc:: pass_by_value) ]
260+ fn insert ( & mut self , value : Value < ' tcx > , ty : Ty < ' tcx > ) -> ( VnIndex , bool ) {
261+ let hash: u64 = {
262+ let mut h = FxHasher :: default ( ) ;
263+ value. hash ( & mut h) ;
264+ ty. hash ( & mut h) ;
265+ h. finish ( )
266+ } ;
267+
268+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
269+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
270+ match self . indices . entry ( hash, eq, hasher) {
271+ Entry :: Occupied ( entry) => {
272+ let index = * entry. get ( ) ;
273+ ( index, false )
274+ }
275+ Entry :: Vacant ( entry) => {
276+ let index = self . hashes . push ( hash) ;
277+ entry. insert ( index) ;
278+ let _index = self . values . push ( value) ;
279+ debug_assert_eq ! ( index, _index) ;
280+ let _index = self . types . push ( ty) ;
281+ debug_assert_eq ! ( index, _index) ;
282+ ( index, true )
283+ }
284+ }
285+ }
286+
287+ #[ inline]
288+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
289+ & self . values [ index]
290+ }
291+
292+ #[ inline]
293+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
294+ self . types [ index]
295+ }
296+
297+ #[ inline]
298+ fn forget ( & mut self , index : VnIndex ) {
299+ let opaque = self . opaques . push ( index) ;
300+ self . values [ index] = Value :: Opaque ( opaque) ;
301+ }
302+ }
303+
215304struct VnState < ' body , ' tcx > {
216305 tcx : TyCtxt < ' tcx > ,
217306 ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -222,11 +311,9 @@ struct VnState<'body, 'tcx> {
222311 /// Locals that are assigned that value.
223312 // This vector does not hold all the values of `VnIndex` that we create.
224313 rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
314+ values : ValueSet < ' tcx > ,
226315 /// Values evaluated as constants if possible.
227316 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228- /// Counter to generate different values.
229- next_opaque : usize ,
230317 /// Cache the deref values.
231318 derefs : Vec < VnIndex > ,
232319 ssa : & ' body SsaLocals ,
@@ -257,9 +344,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257344 is_coroutine : body. coroutine . is_some ( ) ,
258345 locals : IndexVec :: from_elem ( None , local_decls) ,
259346 rev_locals : IndexVec :: with_capacity ( num_values) ,
260- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
347+ values : ValueSet :: new ( num_values) ,
261348 evaluated : IndexVec :: with_capacity ( num_values) ,
262- next_opaque : 1 ,
263349 derefs : Vec :: new ( ) ,
264350 ssa,
265351 dominators,
@@ -273,8 +359,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273359
274360 #[ instrument( level = "trace" , skip( self ) , ret) ]
275361 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) ;
362+ let ( index, new) = self . values . insert ( value, ty) ;
278363 if new {
279364 // Grow `evaluated` and `rev_locals` here to amortize the allocations.
280365 let evaluated = self . eval_to_const ( index) ;
@@ -286,18 +371,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286371 index
287372 }
288373
289- fn next_opaque ( & mut self ) -> usize {
290- let next_opaque = self . next_opaque ;
291- self . next_opaque += 1 ;
292- next_opaque
293- }
294-
295374 /// Create a new `Value` for which we have no information at all, except that it is distinct
296375 /// from all the others.
297376 #[ instrument( level = "trace" , skip( self ) , ret) ]
298377 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
299- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
300- self . insert ( ty, value)
378+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
379+ let _index = self . evaluated . push ( None ) ;
380+ debug_assert_eq ! ( index, _index) ;
381+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
382+ debug_assert_eq ! ( index, _index) ;
383+ index
301384 }
302385
303386 /// Create a new `Value::Address` distinct from all the others.
@@ -310,18 +393,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310393 }
311394 AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
312395 } ;
313- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
314- self . insert ( ty, value)
396+ let index =
397+ self . values . insert_unique ( ty, |provenance| Value :: Address { place, kind, provenance } ) ;
398+ let evaluated = self . eval_to_const ( index) ;
399+ let _index = self . evaluated . push ( evaluated) ;
400+ debug_assert_eq ! ( index, _index) ;
401+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
402+ debug_assert_eq ! ( index, _index) ;
403+ index
404+ }
405+
406+ #[ instrument( level = "trace" , skip( self ) , ret) ]
407+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
408+ let ( index, new) = if value. is_deterministic ( ) {
409+ // The constant is deterministic, no need to disambiguate.
410+ let constant = Value :: Constant { value, disambiguator : DETERMINISTIC } ;
411+ self . values . insert ( constant, value. ty ( ) )
412+ } else {
413+ // Multiple mentions of this constant will yield different values,
414+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
415+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| {
416+ debug_assert_ne ! ( disambiguator, DETERMINISTIC ) ;
417+ Value :: Constant { value, disambiguator }
418+ } ) ;
419+ ( index, true )
420+ } ;
421+ if new {
422+ let evaluated = self . eval_to_const ( index) ;
423+ let _index = self . evaluated . push ( evaluated) ;
424+ debug_assert_eq ! ( index, _index) ;
425+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
426+ debug_assert_eq ! ( index, _index) ;
427+ }
428+ index
315429 }
316430
317431 #[ inline]
318432 fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
433+ self . values . value ( index)
320434 }
321435
322436 #[ inline]
323437 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
324- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
438+ self . values . ty ( index)
325439 }
326440
327441 /// Record that `local` is assigned `value`. `local` must be SSA.
@@ -332,33 +446,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
332446 self . rev_locals [ value] . push ( local) ;
333447 }
334448
335- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
336- let disambiguator = if value. is_deterministic ( ) {
337- // The constant is deterministic, no need to disambiguate.
338- 0
339- } else {
340- // Multiple mentions of this constant will yield different values,
341- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342- let disambiguator = self . next_opaque ( ) ;
343- // `disambiguator: 0` means deterministic.
344- debug_assert_ne ! ( disambiguator, 0 ) ;
345- disambiguator
346- } ;
347- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
348- }
349-
350449 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
351450 // Booleans are deterministic.
352451 let value = Const :: from_bool ( self . tcx , flag) ;
353452 debug_assert ! ( value. is_deterministic( ) ) ;
354- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
453+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : DETERMINISTIC } )
355454 }
356455
357456 fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
358457 // Scalars are deterministic.
359458 let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
360459 debug_assert ! ( value. is_deterministic( ) ) ;
361- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
460+ self . insert ( ty, Value :: Constant { value, disambiguator : DETERMINISTIC } )
362461 }
363462
364463 fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : Vec < VnIndex > ) -> VnIndex {
@@ -373,8 +472,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373472
374473 fn invalidate_derefs ( & mut self ) {
375474 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) ;
475+ self . values . forget ( deref) ;
378476 }
379477 }
380478
@@ -1615,7 +1713,7 @@ impl<'tcx> VnState<'_, 'tcx> {
16151713 // This was already constant in MIR, do not change it. If the constant is not
16161714 // deterministic, adding an additional mention of it in MIR will not give the same value as
16171715 // the former mention.
1618- if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1716+ if let Value :: Constant { value, disambiguator : DETERMINISTIC } = * self . get ( index) {
16191717 debug_assert ! ( value. is_deterministic( ) ) ;
16201718 return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
16211719 }
0 commit comments