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,9 +154,23 @@ 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
161
+ #[ derive( Copy , Clone , Debug , Eq ) ]
162
+ struct VnOpaque ;
163
+ impl PartialEq for VnOpaque {
164
+ fn eq ( & self , _: & VnOpaque ) -> bool {
165
+ unreachable ! ( )
166
+ }
167
+ }
168
+ impl Hash for VnOpaque {
169
+ fn hash < T : Hasher > ( & self , _: & mut T ) {
170
+ unreachable ! ( )
171
+ }
172
+ }
173
+
158
174
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
159
175
enum AddressKind {
160
176
Ref ( BorrowKind ) ,
@@ -166,14 +182,14 @@ enum Value<'tcx> {
166
182
// Root values.
167
183
/// Used to represent values we know nothing about.
168
184
/// The `usize` is a counter incremented by `new_opaque`.
169
- Opaque ( usize ) ,
185
+ Opaque ( VnOpaque ) ,
170
186
/// Evaluated or unevaluated constant value.
171
187
Constant {
172
188
value : Const < ' tcx > ,
173
189
/// Some constants do not have a deterministic value. To avoid merging two instances of the
174
190
/// same `Const`, we assign them an additional integer index.
175
- // `disambiguator` is 0 iff the constant is deterministic.
176
- disambiguator : usize ,
191
+ // `disambiguator` is `None` iff the constant is deterministic.
192
+ disambiguator : Option < VnOpaque > ,
177
193
} ,
178
194
/// An aggregate value, either tuple/closure/struct/enum.
179
195
/// This does not contain unions, as we cannot reason with the value.
@@ -192,7 +208,7 @@ enum Value<'tcx> {
192
208
place : Place < ' tcx > ,
193
209
kind : AddressKind ,
194
210
/// Give each borrow and pointer a different provenance, so we don't merge them.
195
- provenance : usize ,
211
+ provenance : VnOpaque ,
196
212
} ,
197
213
198
214
// Extractions.
@@ -213,6 +229,106 @@ enum Value<'tcx> {
213
229
} ,
214
230
}
215
231
232
+ /// Stores and deduplicates pairs of `(Value, Ty)` into in `VnIndex` numbered values.
233
+ ///
234
+ /// This data structure is mostly a partial reimplementation of `FxIndexMap<VnIndex, (Value, Ty)>`.
235
+ /// We do not use a regular `FxIndexMap` to skip hashing values that are unique by construction,
236
+ /// like opaque values, address with provenance and non-deterministic constants.
237
+ struct ValueSet < ' tcx > {
238
+ indices : HashTable < VnIndex > ,
239
+ hashes : IndexVec < VnIndex , u64 > ,
240
+ values : IndexVec < VnIndex , Value < ' tcx > > ,
241
+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
242
+ }
243
+
244
+ impl < ' tcx > ValueSet < ' tcx > {
245
+ fn new ( num_values : usize ) -> ValueSet < ' tcx > {
246
+ ValueSet {
247
+ indices : HashTable :: with_capacity ( num_values) ,
248
+ hashes : IndexVec :: with_capacity ( num_values) ,
249
+ values : IndexVec :: with_capacity ( num_values) ,
250
+ types : IndexVec :: with_capacity ( num_values) ,
251
+ }
252
+ }
253
+
254
+ /// Insert a `(Value, Ty)` pair without hashing or deduplication.
255
+ #[ inline]
256
+ fn insert_unique (
257
+ & mut self ,
258
+ ty : Ty < ' tcx > ,
259
+ value : impl FnOnce ( VnOpaque ) -> Value < ' tcx > ,
260
+ ) -> VnIndex {
261
+ let value = value ( VnOpaque ) ;
262
+
263
+ debug_assert ! ( match value {
264
+ Value :: Opaque ( _) | Value :: Address { .. } => true ,
265
+ Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
266
+ _ => false ,
267
+ } ) ;
268
+
269
+ let index = self . hashes . push ( 0 ) ;
270
+ let _index = self . types . push ( ty) ;
271
+ debug_assert_eq ! ( index, _index) ;
272
+ let _index = self . values . push ( value) ;
273
+ debug_assert_eq ! ( index, _index) ;
274
+ index
275
+ }
276
+
277
+ /// Insert a `(Value, Ty)` pair to be deduplicated.
278
+ /// Returns `true` as second tuple field if this value did not exist previously.
279
+ #[ allow( rustc:: pass_by_value) ] // closures take `&VnIndex`
280
+ fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> ( VnIndex , bool ) {
281
+ debug_assert ! ( match value {
282
+ Value :: Opaque ( _) | Value :: Address { .. } => false ,
283
+ Value :: Constant { disambiguator, .. } => disambiguator. is_none( ) ,
284
+ _ => true ,
285
+ } ) ;
286
+
287
+ let hash: u64 = {
288
+ let mut h = FxHasher :: default ( ) ;
289
+ value. hash ( & mut h) ;
290
+ ty. hash ( & mut h) ;
291
+ h. finish ( )
292
+ } ;
293
+
294
+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
295
+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
296
+ match self . indices . entry ( hash, eq, hasher) {
297
+ Entry :: Occupied ( entry) => {
298
+ let index = * entry. get ( ) ;
299
+ ( index, false )
300
+ }
301
+ Entry :: Vacant ( entry) => {
302
+ let index = self . hashes . push ( hash) ;
303
+ entry. insert ( index) ;
304
+ let _index = self . values . push ( value) ;
305
+ debug_assert_eq ! ( index, _index) ;
306
+ let _index = self . types . push ( ty) ;
307
+ debug_assert_eq ! ( index, _index) ;
308
+ ( index, true )
309
+ }
310
+ }
311
+ }
312
+
313
+ /// Return the `Value` associated with the given `VnIndex`.
314
+ #[ inline]
315
+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
316
+ & self . values [ index]
317
+ }
318
+
319
+ /// Return the type associated with the given `VnIndex`.
320
+ #[ inline]
321
+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
322
+ self . types [ index]
323
+ }
324
+
325
+ /// Replace the value associated with `index` with an opaque value.
326
+ #[ inline]
327
+ fn forget ( & mut self , index : VnIndex ) {
328
+ self . values [ index] = Value :: Opaque ( VnOpaque ) ;
329
+ }
330
+ }
331
+
216
332
struct VnState < ' body , ' tcx > {
217
333
tcx : TyCtxt < ' tcx > ,
218
334
ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -223,11 +339,9 @@ struct VnState<'body, 'tcx> {
223
339
/// Locals that are assigned that value.
224
340
// This vector does not hold all the values of `VnIndex` that we create.
225
341
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
226
- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
342
+ values : ValueSet < ' tcx > ,
227
343
/// Values evaluated as constants if possible.
228
344
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
229
- /// Counter to generate different values.
230
- next_opaque : usize ,
231
345
/// Cache the deref values.
232
346
derefs : Vec < VnIndex > ,
233
347
ssa : & ' body SsaLocals ,
@@ -258,9 +372,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
258
372
is_coroutine : body. coroutine . is_some ( ) ,
259
373
locals : IndexVec :: from_elem ( None , local_decls) ,
260
374
rev_locals : IndexVec :: with_capacity ( num_values) ,
261
- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
375
+ values : ValueSet :: new ( num_values) ,
262
376
evaluated : IndexVec :: with_capacity ( num_values) ,
263
- next_opaque : 1 ,
264
377
derefs : Vec :: new ( ) ,
265
378
ssa,
266
379
dominators,
@@ -274,8 +387,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
274
387
275
388
#[ instrument( level = "trace" , skip( self ) , ret) ]
276
389
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) ;
390
+ let ( index, new) = self . values . insert ( ty, value) ;
279
391
if new {
280
392
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
281
393
let evaluated = self . eval_to_const ( index) ;
@@ -287,18 +399,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
287
399
index
288
400
}
289
401
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
402
/// Create a new `Value` for which we have no information at all, except that it is distinct
297
403
/// from all the others.
298
404
#[ instrument( level = "trace" , skip( self ) , ret) ]
299
405
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
300
- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
301
- self . insert ( ty, value)
406
+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
407
+ let _index = self . evaluated . push ( None ) ;
408
+ debug_assert_eq ! ( index, _index) ;
409
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
410
+ debug_assert_eq ! ( index, _index) ;
411
+ index
302
412
}
303
413
304
414
/// Create a new `Value::Address` distinct from all the others.
@@ -311,18 +421,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
311
421
}
312
422
AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
313
423
} ;
314
- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
315
- self . insert ( ty, value)
424
+ let index =
425
+ self . values . insert_unique ( ty, |provenance| Value :: Address { place, kind, provenance } ) ;
426
+ let evaluated = self . eval_to_const ( index) ;
427
+ let _index = self . evaluated . push ( evaluated) ;
428
+ debug_assert_eq ! ( index, _index) ;
429
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
430
+ debug_assert_eq ! ( index, _index) ;
431
+ index
432
+ }
433
+
434
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
435
+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
436
+ let ( index, new) = if value. is_deterministic ( ) {
437
+ // The constant is deterministic, no need to disambiguate.
438
+ let constant = Value :: Constant { value, disambiguator : None } ;
439
+ self . values . insert ( value. ty ( ) , constant)
440
+ } else {
441
+ // Multiple mentions of this constant will yield different values,
442
+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
443
+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| Value :: Constant {
444
+ value,
445
+ disambiguator : Some ( disambiguator) ,
446
+ } ) ;
447
+ ( index, true )
448
+ } ;
449
+ if new {
450
+ let evaluated = self . eval_to_const ( index) ;
451
+ let _index = self . evaluated . push ( evaluated) ;
452
+ debug_assert_eq ! ( index, _index) ;
453
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
454
+ debug_assert_eq ! ( index, _index) ;
455
+ }
456
+ index
316
457
}
317
458
318
459
#[ inline]
319
460
fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
320
- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
461
+ self . values . value ( index)
321
462
}
322
463
323
464
#[ inline]
324
465
fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
325
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
466
+ self . values . ty ( index)
326
467
}
327
468
328
469
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -333,33 +474,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
333
474
self . rev_locals [ value] . push ( local) ;
334
475
}
335
476
336
- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
337
- let disambiguator = if value. is_deterministic ( ) {
338
- // The constant is deterministic, no need to disambiguate.
339
- 0
340
- } else {
341
- // Multiple mentions of this constant will yield different values,
342
- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
343
- let disambiguator = self . next_opaque ( ) ;
344
- // `disambiguator: 0` means deterministic.
345
- debug_assert_ne ! ( disambiguator, 0 ) ;
346
- disambiguator
347
- } ;
348
- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
349
- }
350
-
351
477
fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
352
478
// Booleans are deterministic.
353
479
let value = Const :: from_bool ( self . tcx , flag) ;
354
480
debug_assert ! ( value. is_deterministic( ) ) ;
355
- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
481
+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : None } )
356
482
}
357
483
358
484
fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
359
485
// Scalars are deterministic.
360
486
let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
361
487
debug_assert ! ( value. is_deterministic( ) ) ;
362
- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
488
+ self . insert ( ty, Value :: Constant { value, disambiguator : None } )
363
489
}
364
490
365
491
fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : Vec < VnIndex > ) -> VnIndex {
@@ -374,8 +500,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
374
500
375
501
fn invalidate_derefs ( & mut self ) {
376
502
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) ;
503
+ self . values . forget ( deref) ;
379
504
}
380
505
}
381
506
@@ -1605,7 +1730,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1605
1730
// This was already constant in MIR, do not change it. If the constant is not
1606
1731
// deterministic, adding an additional mention of it in MIR will not give the same value as
1607
1732
// the former mention.
1608
- if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1733
+ if let Value :: Constant { value, disambiguator : None } = * self . get ( index) {
1609
1734
debug_assert ! ( value. is_deterministic( ) ) ;
1610
1735
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1611
1736
}
0 commit comments