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_arena:: DroplessArena ;
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:: { FxHashMap , FxIndexSet , MutableValues } ;
99
+ use rustc_data_structures:: fx:: { FxHashMap , 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 ;
@@ -149,9 +151,17 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
149
151
}
150
152
151
153
newtype_index ! {
154
+ #[ debug_format = "_v{}" ]
152
155
struct VnIndex { }
153
156
}
154
157
158
+ newtype_index ! {
159
+ #[ debug_format = "_o{}" ]
160
+ struct VnOpaque { }
161
+ }
162
+
163
+ const DETERMINISTIC : VnOpaque = VnOpaque :: MAX ;
164
+
155
165
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
156
166
enum AddressKind {
157
167
Ref ( BorrowKind ) ,
@@ -171,14 +181,14 @@ enum Value<'a, 'tcx> {
171
181
// Root values.
172
182
/// Used to represent values we know nothing about.
173
183
/// The `usize` is a counter incremented by `new_opaque`.
174
- Opaque ( usize ) ,
184
+ Opaque ( VnOpaque ) ,
175
185
/// Evaluated or unevaluated constant value.
176
186
Constant {
177
187
value : Const < ' tcx > ,
178
188
/// Some constants do not have a deterministic value. To avoid merging two instances of the
179
189
/// same `Const`, we assign them an additional integer index.
180
- // `disambiguator` is 0 iff the constant is deterministic.
181
- disambiguator : usize ,
190
+ // `disambiguator` is `DETERMINISTIC` iff the constant is deterministic.
191
+ disambiguator : VnOpaque ,
182
192
} ,
183
193
/// An aggregate value, either tuple/closure/struct/enum.
184
194
/// This does not contain unions, as we cannot reason with the value.
@@ -200,7 +210,7 @@ enum Value<'a, 'tcx> {
200
210
projection : & ' a [ ProjectionElem < VnIndex , Ty < ' tcx > > ] ,
201
211
kind : AddressKind ,
202
212
/// Give each borrow and pointer a different provenance, so we don't merge them.
203
- provenance : usize ,
213
+ provenance : VnOpaque ,
204
214
} ,
205
215
206
216
// Extractions.
@@ -221,6 +231,85 @@ enum Value<'a, 'tcx> {
221
231
} ,
222
232
}
223
233
234
+ struct ValueSet < ' a , ' tcx > {
235
+ indices : HashTable < VnIndex > ,
236
+ hashes : IndexVec < VnIndex , u64 > ,
237
+ values : IndexVec < VnIndex , Value < ' a , ' tcx > > ,
238
+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
239
+ opaques : IndexVec < VnOpaque , VnIndex > ,
240
+ }
241
+
242
+ impl < ' a , ' tcx > ValueSet < ' a , ' tcx > {
243
+ fn new ( num_values : usize ) -> ValueSet < ' a , ' tcx > {
244
+ ValueSet {
245
+ indices : HashTable :: with_capacity ( num_values) ,
246
+ hashes : IndexVec :: with_capacity ( num_values) ,
247
+ values : IndexVec :: with_capacity ( num_values) ,
248
+ types : IndexVec :: with_capacity ( num_values) ,
249
+ opaques : IndexVec :: with_capacity ( num_values) ,
250
+ }
251
+ }
252
+
253
+ #[ inline]
254
+ fn insert_unique (
255
+ & mut self ,
256
+ ty : Ty < ' tcx > ,
257
+ value : impl FnOnce ( VnOpaque ) -> Value < ' a , ' tcx > ,
258
+ ) -> VnIndex {
259
+ let index = self . hashes . push ( 0 ) ;
260
+ let _index = self . types . push ( ty) ;
261
+ debug_assert_eq ! ( index, _index) ;
262
+ let opaque = self . opaques . push ( index) ;
263
+ let _index = self . values . push ( value ( opaque) ) ;
264
+ debug_assert_eq ! ( index, _index) ;
265
+ index
266
+ }
267
+
268
+ #[ allow( rustc:: pass_by_value) ]
269
+ fn insert ( & mut self , value : Value < ' a , ' tcx > , ty : Ty < ' tcx > ) -> ( VnIndex , bool ) {
270
+ let hash: u64 = {
271
+ let mut h = FxHasher :: default ( ) ;
272
+ value. hash ( & mut h) ;
273
+ ty. hash ( & mut h) ;
274
+ h. finish ( )
275
+ } ;
276
+
277
+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
278
+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
279
+ match self . indices . entry ( hash, eq, hasher) {
280
+ Entry :: Occupied ( entry) => {
281
+ let index = * entry. get ( ) ;
282
+ ( index, false )
283
+ }
284
+ Entry :: Vacant ( entry) => {
285
+ let index = self . hashes . push ( hash) ;
286
+ entry. insert ( index) ;
287
+ let _index = self . values . push ( value) ;
288
+ debug_assert_eq ! ( index, _index) ;
289
+ let _index = self . types . push ( ty) ;
290
+ debug_assert_eq ! ( index, _index) ;
291
+ ( index, true )
292
+ }
293
+ }
294
+ }
295
+
296
+ #[ inline]
297
+ fn value ( & self , index : VnIndex ) -> Value < ' a , ' tcx > {
298
+ self . values [ index]
299
+ }
300
+
301
+ #[ inline]
302
+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
303
+ self . types [ index]
304
+ }
305
+
306
+ #[ inline]
307
+ fn forget ( & mut self , index : VnIndex ) {
308
+ let opaque = self . opaques . push ( index) ;
309
+ self . values [ index] = Value :: Opaque ( opaque) ;
310
+ }
311
+ }
312
+
224
313
struct VnState < ' body , ' a , ' tcx > {
225
314
tcx : TyCtxt < ' tcx > ,
226
315
ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -233,11 +322,9 @@ struct VnState<'body, 'a, 'tcx> {
233
322
rev_locals_ssa : IndexVec < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
234
323
// This vector holds the locals that are not SSA.
235
324
rev_locals_non_ssa : FxHashMap < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
236
- values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
325
+ values : ValueSet < ' a , ' tcx > ,
237
326
/// Values evaluated as constants if possible.
238
327
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
239
- /// Counter to generate different values.
240
- next_opaque : usize ,
241
328
/// Cache the deref values.
242
329
derefs : Vec < VnIndex > ,
243
330
ssa : & ' body SsaLocals ,
@@ -271,9 +358,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
271
358
locals : IndexVec :: with_capacity ( body. local_decls . len ( ) ) ,
272
359
rev_locals_ssa : IndexVec :: with_capacity ( num_values) ,
273
360
rev_locals_non_ssa : FxHashMap :: default ( ) ,
274
- values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
361
+ values : ValueSet :: new ( num_values) ,
275
362
evaluated : IndexVec :: with_capacity ( num_values) ,
276
- next_opaque : 1 ,
277
363
derefs : Vec :: new ( ) ,
278
364
ssa,
279
365
dominators,
@@ -299,10 +385,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
299
385
300
386
#[ instrument( level = "trace" , skip( self ) , ret) ]
301
387
fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' a , ' tcx > ) -> VnIndex {
302
- let ( index, new) = self . values . insert_full ( ( value, ty) ) ;
303
- let index = VnIndex :: from_usize ( index) ;
388
+ let ( index, new) = self . values . insert ( value, ty) ;
304
389
if new {
305
- // Grow `evaluated` and `rev_locals ` here to amortize the allocations.
390
+ // Grow `evaluated` and `rev_locals_ssa ` here to amortize the allocations.
306
391
let evaluated = self . eval_to_const ( index) ;
307
392
let _index = self . evaluated . push ( evaluated) ;
308
393
debug_assert_eq ! ( index, _index) ;
@@ -312,18 +397,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
312
397
index
313
398
}
314
399
315
- fn next_opaque ( & mut self ) -> usize {
316
- let next_opaque = self . next_opaque ;
317
- self . next_opaque += 1 ;
318
- next_opaque
319
- }
320
-
321
400
/// Create a new `Value` for which we have no information at all, except that it is distinct
322
401
/// from all the others.
323
402
#[ instrument( level = "trace" , skip( self ) , ret) ]
324
403
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
325
- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
326
- self . insert ( ty, value)
404
+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
405
+ let _index = self . evaluated . push ( None ) ;
406
+ debug_assert_eq ! ( index, _index) ;
407
+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
408
+ debug_assert_eq ! ( index, _index) ;
409
+ index
327
410
}
328
411
329
412
/// Create a new `Value::Address` distinct from all the others.
@@ -352,25 +435,57 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
352
435
AddressBase :: Local ( place. local )
353
436
} ;
354
437
// Do not try evaluating inside `Index`, this has been done by `simplify_place_value`.
355
- let projection = self
356
- . arena
357
- . try_alloc_from_iter (
358
- projection
359
- . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ,
360
- )
361
- . ok ( ) ?;
362
- let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
363
- Some ( self . insert ( ty, value) )
438
+ let projection = projection
439
+ . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ;
440
+ let projection = self . arena . try_alloc_from_iter ( projection) . ok ( ) ?;
441
+
442
+ let index = self . values . insert_unique ( ty, |provenance| Value :: Address {
443
+ base,
444
+ projection,
445
+ kind,
446
+ provenance,
447
+ } ) ;
448
+ let evaluated = self . eval_to_const ( index) ;
449
+ let _index = self . evaluated . push ( evaluated) ;
450
+ debug_assert_eq ! ( index, _index) ;
451
+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
452
+ debug_assert_eq ! ( index, _index) ;
453
+ Some ( index)
454
+ }
455
+
456
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
457
+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
458
+ let ( index, new) = if value. is_deterministic ( ) {
459
+ // The constant is deterministic, no need to disambiguate.
460
+ let constant = Value :: Constant { value, disambiguator : DETERMINISTIC } ;
461
+ self . values . insert ( constant, value. ty ( ) )
462
+ } else {
463
+ // Multiple mentions of this constant will yield different values,
464
+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
465
+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| {
466
+ debug_assert_ne ! ( disambiguator, DETERMINISTIC ) ;
467
+ Value :: Constant { value, disambiguator }
468
+ } ) ;
469
+ ( index, true )
470
+ } ;
471
+ if new {
472
+ let evaluated = self . eval_to_const ( index) ;
473
+ let _index = self . evaluated . push ( evaluated) ;
474
+ debug_assert_eq ! ( index, _index) ;
475
+ let _index = self . rev_locals_ssa . push ( SmallVec :: new ( ) ) ;
476
+ debug_assert_eq ! ( index, _index) ;
477
+ }
478
+ index
364
479
}
365
480
366
481
#[ inline]
367
482
fn get ( & self , index : VnIndex ) -> Value < ' a , ' tcx > {
368
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
483
+ self . values . value ( index)
369
484
}
370
485
371
486
#[ inline]
372
487
fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
373
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
488
+ self . values . ty ( index)
374
489
}
375
490
376
491
/// Record that `local` is assigned `value`.
@@ -406,33 +521,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
406
521
}
407
522
}
408
523
409
- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
410
- let disambiguator = if value. is_deterministic ( ) {
411
- // The constant is deterministic, no need to disambiguate.
412
- 0
413
- } else {
414
- // Multiple mentions of this constant will yield different values,
415
- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
416
- let disambiguator = self . next_opaque ( ) ;
417
- // `disambiguator: 0` means deterministic.
418
- debug_assert_ne ! ( disambiguator, 0 ) ;
419
- disambiguator
420
- } ;
421
- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
422
- }
423
-
424
524
fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
425
525
// Booleans are deterministic.
426
526
let value = Const :: from_bool ( self . tcx , flag) ;
427
527
debug_assert ! ( value. is_deterministic( ) ) ;
428
- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
528
+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : DETERMINISTIC } )
429
529
}
430
530
431
531
fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
432
532
// Scalars are deterministic.
433
533
let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
434
534
debug_assert ! ( value. is_deterministic( ) ) ;
435
- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
535
+ self . insert ( ty, Value :: Constant { value, disambiguator : DETERMINISTIC } )
436
536
}
437
537
438
538
fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : & [ VnIndex ] ) -> VnIndex {
@@ -447,8 +547,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
447
547
448
548
fn invalidate_derefs ( & mut self ) {
449
549
for deref in std:: mem:: take ( & mut self . derefs ) {
450
- let opaque = self . next_opaque ( ) ;
451
- self . values . get_index_mut2 ( deref. index ( ) ) . unwrap ( ) . 0 = Value :: Opaque ( opaque) ;
550
+ self . values . forget ( deref) ;
452
551
}
453
552
}
454
553
@@ -1714,7 +1813,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1714
1813
// This was already constant in MIR, do not change it. If the constant is not
1715
1814
// deterministic, adding an additional mention of it in MIR will not give the same value as
1716
1815
// the former mention.
1717
- if let Value :: Constant { value, disambiguator : 0 } = self . get ( index) {
1816
+ if let Value :: Constant { value, disambiguator : DETERMINISTIC } = self . get ( index) {
1718
1817
debug_assert ! ( value. is_deterministic( ) ) ;
1719
1818
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1720
1819
}
0 commit comments