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,9 +153,15 @@ 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
160
+ newtype_index ! {
161
+ #[ debug_format = "_o{}" ]
162
+ struct VnOpaque { }
163
+ }
164
+
157
165
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
158
166
enum AddressKind {
159
167
Ref ( BorrowKind ) ,
@@ -165,7 +173,7 @@ enum Value<'tcx> {
165
173
// Root values.
166
174
/// Used to represent values we know nothing about.
167
175
/// The `usize` is a counter incremented by `new_opaque`.
168
- Opaque ( usize ) ,
176
+ Opaque ( VnOpaque ) ,
169
177
/// Evaluated or unevaluated constant value.
170
178
Constant {
171
179
value : Const < ' tcx > ,
@@ -212,6 +220,85 @@ enum Value<'tcx> {
212
220
} ,
213
221
}
214
222
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
+ opaques : IndexVec < VnOpaque , VnIndex > ,
229
+ }
230
+
231
+ impl < ' tcx > ValueSet < ' tcx > {
232
+ fn new ( num_values : usize ) -> ValueSet < ' tcx > {
233
+ ValueSet {
234
+ indices : HashTable :: with_capacity ( num_values) ,
235
+ hashes : IndexVec :: with_capacity ( num_values) ,
236
+ values : IndexVec :: with_capacity ( num_values) ,
237
+ types : IndexVec :: with_capacity ( num_values) ,
238
+ opaques : IndexVec :: with_capacity ( num_values) ,
239
+ }
240
+ }
241
+
242
+ #[ allow( rustc:: pass_by_value) ]
243
+ fn insert ( & mut self , value : Value < ' tcx > , ty : Ty < ' tcx > ) -> ( VnIndex , bool ) {
244
+ if let Value :: Opaque ( opaque) = value {
245
+ return ( self . opaques [ opaque] , false ) ;
246
+ }
247
+
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
+ #[ inline]
275
+ fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
276
+ let index = self . hashes . push ( 0 ) ;
277
+ let _index = self . types . push ( ty) ;
278
+ debug_assert_eq ! ( index, _index) ;
279
+ let opaque = self . opaques . push ( index) ;
280
+ let _index = self . values . push ( Value :: Opaque ( opaque) ) ;
281
+ debug_assert_eq ! ( index, _index) ;
282
+ index
283
+ }
284
+
285
+ #[ inline]
286
+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
287
+ & self . values [ index]
288
+ }
289
+
290
+ #[ inline]
291
+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
292
+ self . types [ index]
293
+ }
294
+
295
+ #[ inline]
296
+ fn forget ( & mut self , index : VnIndex ) {
297
+ let opaque = self . opaques . push ( index) ;
298
+ self . values [ index] = Value :: Opaque ( opaque) ;
299
+ }
300
+ }
301
+
215
302
struct VnState < ' body , ' tcx > {
216
303
tcx : TyCtxt < ' tcx > ,
217
304
ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -222,11 +309,11 @@ struct VnState<'body, 'tcx> {
222
309
/// Locals that are assigned that value.
223
310
// This vector does not hold all the values of `VnIndex` that we create.
224
311
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225
- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
312
+ values : ValueSet < ' tcx > ,
226
313
/// Values evaluated as constants if possible.
227
314
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228
315
/// Counter to generate different values.
229
- next_opaque : usize ,
316
+ next_disambiguator : usize ,
230
317
/// Cache the deref values.
231
318
derefs : Vec < VnIndex > ,
232
319
ssa : & ' body SsaLocals ,
@@ -257,9 +344,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257
344
is_coroutine : body. coroutine . is_some ( ) ,
258
345
locals : IndexVec :: from_elem ( None , local_decls) ,
259
346
rev_locals : IndexVec :: with_capacity ( num_values) ,
260
- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
347
+ values : ValueSet :: new ( num_values) ,
261
348
evaluated : IndexVec :: with_capacity ( num_values) ,
262
- next_opaque : 1 ,
349
+ next_disambiguator : 1 ,
263
350
derefs : Vec :: new ( ) ,
264
351
ssa,
265
352
dominators,
@@ -273,8 +360,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273
360
274
361
#[ instrument( level = "trace" , skip( self ) , ret) ]
275
362
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) ;
363
+ let ( index, new) = self . values . insert ( value, ty) ;
278
364
if new {
279
365
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
280
366
let evaluated = self . eval_to_const ( index) ;
@@ -286,18 +372,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286
372
index
287
373
}
288
374
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
375
/// Create a new `Value` for which we have no information at all, except that it is distinct
296
376
/// from all the others.
297
377
#[ instrument( level = "trace" , skip( self ) , ret) ]
298
378
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
299
- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
300
- self . insert ( ty, value)
379
+ let index = self . values . new_opaque ( ty) ;
380
+ let _index = self . evaluated . push ( None ) ;
381
+ debug_assert_eq ! ( index, _index) ;
382
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
383
+ debug_assert_eq ! ( index, _index) ;
384
+ index
385
+ }
386
+
387
+ #[ inline]
388
+ fn next_disambiguator ( & mut self ) -> usize {
389
+ let next_disambiguator = self . next_disambiguator ;
390
+ self . next_disambiguator += 1 ;
391
+ next_disambiguator
301
392
}
302
393
303
394
/// Create a new `Value::Address` distinct from all the others.
@@ -310,18 +401,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310
401
}
311
402
AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
312
403
} ;
313
- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
404
+ let value = Value :: Address { place, kind, provenance : self . next_disambiguator ( ) } ;
314
405
self . insert ( ty, value)
315
406
}
316
407
317
408
#[ inline]
318
409
fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319
- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
410
+ self . values . value ( index)
320
411
}
321
412
322
413
#[ inline]
323
414
fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
324
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
415
+ self . values . ty ( index)
325
416
}
326
417
327
418
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -339,7 +430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339
430
} else {
340
431
// Multiple mentions of this constant will yield different values,
341
432
// so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342
- let disambiguator = self . next_opaque ( ) ;
433
+ let disambiguator = self . next_disambiguator ( ) ;
343
434
// `disambiguator: 0` means deterministic.
344
435
debug_assert_ne ! ( disambiguator, 0 ) ;
345
436
disambiguator
@@ -373,8 +464,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373
464
374
465
fn invalidate_derefs ( & mut self ) {
375
466
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) ;
467
+ self . values . forget ( deref) ;
378
468
}
379
469
}
380
470
0 commit comments