85
85
//! that contain `AllocId`s.
86
86
87
87
use std:: borrow:: Cow ;
88
+ use std:: hash:: { Hash , Hasher } ;
88
89
89
90
use either:: Either ;
91
+ use hashbrown:: hash_table:: { Entry , HashTable } ;
90
92
use rustc_abi:: { self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx } ;
91
93
use rustc_const_eval:: const_eval:: DummyMachine ;
92
94
use rustc_const_eval:: interpret:: {
93
95
ImmTy , Immediate , InterpCx , MemPlaceMeta , MemoryKind , OpTy , Projectable , Scalar ,
94
96
intern_const_alloc_for_constprop,
95
97
} ;
96
- use rustc_data_structures:: fx:: { FxIndexSet , MutableValues } ;
98
+ use rustc_data_structures:: fx:: FxHasher ;
97
99
use rustc_data_structures:: graph:: dominators:: Dominators ;
98
100
use rustc_hir:: def:: DefKind ;
99
101
use rustc_index:: bit_set:: DenseBitSet ;
@@ -151,6 +153,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
151
153
}
152
154
153
155
newtype_index ! {
156
+ #[ debug_format = "_v{}" ]
154
157
struct VnIndex { }
155
158
}
156
159
@@ -212,6 +215,89 @@ enum Value<'tcx> {
212
215
} ,
213
216
}
214
217
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
+
215
301
struct VnState < ' body , ' tcx > {
216
302
tcx : TyCtxt < ' tcx > ,
217
303
ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -222,11 +308,9 @@ struct VnState<'body, 'tcx> {
222
308
/// Locals that are assigned that value.
223
309
// This vector does not hold all the values of `VnIndex` that we create.
224
310
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225
- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
311
+ values : ValueSet < ' tcx > ,
226
312
/// Values evaluated as constants if possible.
227
313
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228
- /// Counter to generate different values.
229
- next_opaque : usize ,
230
314
/// Cache the deref values.
231
315
derefs : Vec < VnIndex > ,
232
316
ssa : & ' body SsaLocals ,
@@ -257,9 +341,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257
341
is_coroutine : body. coroutine . is_some ( ) ,
258
342
locals : IndexVec :: from_elem ( None , local_decls) ,
259
343
rev_locals : IndexVec :: with_capacity ( num_values) ,
260
- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
344
+ values : ValueSet :: new ( num_values) ,
261
345
evaluated : IndexVec :: with_capacity ( num_values) ,
262
- next_opaque : 1 ,
263
346
derefs : Vec :: new ( ) ,
264
347
ssa,
265
348
dominators,
@@ -273,8 +356,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273
356
274
357
#[ instrument( level = "trace" , skip( self ) , ret) ]
275
358
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) ;
278
360
if new {
279
361
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
280
362
let evaluated = self . eval_to_const ( index) ;
@@ -286,17 +368,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286
368
index
287
369
}
288
370
289
- fn next_opaque ( & mut self ) -> usize {
290
- let next_opaque = self . next_opaque ;
291
- self . next_opaque += 1 ;
292
- next_opaque
293
- }
294
-
295
371
/// Create a new `Value` for which we have no information at all, except that it is distinct
296
372
/// from all the others.
297
373
#[ instrument( level = "trace" , skip( self ) , ret) ]
298
374
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 ( ) ) ;
300
376
self . insert ( ty, value)
301
377
}
302
378
@@ -310,18 +386,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310
386
}
311
387
AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
312
388
} ;
313
- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
389
+ let value = Value :: Address { place, kind, provenance : self . values . next_opaque ( ) } ;
314
390
self . insert ( ty, value)
315
391
}
316
392
317
393
#[ inline]
318
394
fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319
- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
395
+ self . values . value ( index)
320
396
}
321
397
322
398
#[ inline]
323
399
fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
324
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
400
+ self . values . ty ( index)
325
401
}
326
402
327
403
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -339,7 +415,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339
415
} else {
340
416
// Multiple mentions of this constant will yield different values,
341
417
// 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 ( ) ;
343
419
// `disambiguator: 0` means deterministic.
344
420
debug_assert_ne ! ( disambiguator, 0 ) ;
345
421
disambiguator
@@ -373,8 +449,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373
449
374
450
fn invalidate_derefs ( & mut self ) {
375
451
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) ;
378
453
}
379
454
}
380
455
0 commit comments