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