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,17 @@ 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
+
165
+ const DETERMINISTIC : VnOpaque = VnOpaque :: MAX ;
166
+
157
167
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
158
168
enum AddressKind {
159
169
Ref ( BorrowKind ) ,
@@ -165,14 +175,14 @@ enum Value<'tcx> {
165
175
// Root values.
166
176
/// Used to represent values we know nothing about.
167
177
/// The `usize` is a counter incremented by `new_opaque`.
168
- Opaque ( usize ) ,
178
+ Opaque ( VnOpaque ) ,
169
179
/// Evaluated or unevaluated constant value.
170
180
Constant {
171
181
value : Const < ' tcx > ,
172
182
/// Some constants do not have a deterministic value. To avoid merging two instances of the
173
183
/// same `Const`, we assign them an additional integer index.
174
- // `disambiguator` is 0 iff the constant is deterministic.
175
- disambiguator : usize ,
184
+ // `disambiguator` is `DETERMINISTIC` iff the constant is deterministic.
185
+ disambiguator : VnOpaque ,
176
186
} ,
177
187
/// An aggregate value, either tuple/closure/struct/enum.
178
188
/// This does not contain unions, as we cannot reason with the value.
@@ -191,7 +201,7 @@ enum Value<'tcx> {
191
201
place : Place < ' tcx > ,
192
202
kind : AddressKind ,
193
203
/// Give each borrow and pointer a different provenance, so we don't merge them.
194
- provenance : usize ,
204
+ provenance : VnOpaque ,
195
205
} ,
196
206
197
207
// Extractions.
@@ -212,6 +222,85 @@ enum Value<'tcx> {
212
222
} ,
213
223
}
214
224
225
+ struct ValueSet < ' tcx > {
226
+ indices : HashTable < VnIndex > ,
227
+ hashes : IndexVec < VnIndex , u64 > ,
228
+ values : IndexVec < VnIndex , Value < ' tcx > > ,
229
+ types : IndexVec < VnIndex , Ty < ' tcx > > ,
230
+ opaques : IndexVec < VnOpaque , VnIndex > ,
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
+ opaques : IndexVec :: with_capacity ( num_values) ,
241
+ }
242
+ }
243
+
244
+ #[ inline]
245
+ fn insert_unique (
246
+ & mut self ,
247
+ ty : Ty < ' tcx > ,
248
+ value : impl FnOnce ( VnOpaque ) -> Value < ' tcx > ,
249
+ ) -> VnIndex {
250
+ let index = self . hashes . push ( 0 ) ;
251
+ let _index = self . types . push ( ty) ;
252
+ debug_assert_eq ! ( index, _index) ;
253
+ let opaque = self . opaques . push ( index) ;
254
+ let _index = self . values . push ( value ( opaque) ) ;
255
+ debug_assert_eq ! ( index, _index) ;
256
+ index
257
+ }
258
+
259
+ #[ allow( rustc:: pass_by_value) ]
260
+ fn insert ( & mut self , value : Value < ' tcx > , ty : Ty < ' tcx > ) -> ( VnIndex , bool ) {
261
+ let hash: u64 = {
262
+ let mut h = FxHasher :: default ( ) ;
263
+ value. hash ( & mut h) ;
264
+ ty. hash ( & mut h) ;
265
+ h. finish ( )
266
+ } ;
267
+
268
+ let eq = |index : & VnIndex | self . values [ * index] == value && self . types [ * index] == ty;
269
+ let hasher = |index : & VnIndex | self . hashes [ * index] ;
270
+ match self . indices . entry ( hash, eq, hasher) {
271
+ Entry :: Occupied ( entry) => {
272
+ let index = * entry. get ( ) ;
273
+ ( index, false )
274
+ }
275
+ Entry :: Vacant ( entry) => {
276
+ let index = self . hashes . push ( hash) ;
277
+ entry. insert ( index) ;
278
+ let _index = self . values . push ( value) ;
279
+ debug_assert_eq ! ( index, _index) ;
280
+ let _index = self . types . push ( ty) ;
281
+ debug_assert_eq ! ( index, _index) ;
282
+ ( index, true )
283
+ }
284
+ }
285
+ }
286
+
287
+ #[ inline]
288
+ fn value ( & self , index : VnIndex ) -> & Value < ' tcx > {
289
+ & self . values [ index]
290
+ }
291
+
292
+ #[ inline]
293
+ fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
294
+ self . types [ index]
295
+ }
296
+
297
+ #[ inline]
298
+ fn forget ( & mut self , index : VnIndex ) {
299
+ let opaque = self . opaques . push ( index) ;
300
+ self . values [ index] = Value :: Opaque ( opaque) ;
301
+ }
302
+ }
303
+
215
304
struct VnState < ' body , ' tcx > {
216
305
tcx : TyCtxt < ' tcx > ,
217
306
ecx : InterpCx < ' tcx , DummyMachine > ,
@@ -222,11 +311,9 @@ struct VnState<'body, 'tcx> {
222
311
/// Locals that are assigned that value.
223
312
// This vector does not hold all the values of `VnIndex` that we create.
224
313
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225
- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
314
+ values : ValueSet < ' tcx > ,
226
315
/// Values evaluated as constants if possible.
227
316
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228
- /// Counter to generate different values.
229
- next_opaque : usize ,
230
317
/// Cache the deref values.
231
318
derefs : Vec < VnIndex > ,
232
319
ssa : & ' body SsaLocals ,
@@ -257,9 +344,8 @@ 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 ,
263
349
derefs : Vec :: new ( ) ,
264
350
ssa,
265
351
dominators,
@@ -273,8 +359,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273
359
274
360
#[ instrument( level = "trace" , skip( self ) , ret) ]
275
361
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) ;
362
+ let ( index, new) = self . values . insert ( value, ty) ;
278
363
if new {
279
364
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
280
365
let evaluated = self . eval_to_const ( index) ;
@@ -286,18 +371,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286
371
index
287
372
}
288
373
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
374
/// Create a new `Value` for which we have no information at all, except that it is distinct
296
375
/// from all the others.
297
376
#[ instrument( level = "trace" , skip( self ) , ret) ]
298
377
fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
299
- let value = Value :: Opaque ( self . next_opaque ( ) ) ;
300
- self . insert ( ty, value)
378
+ let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
379
+ let _index = self . evaluated . push ( None ) ;
380
+ debug_assert_eq ! ( index, _index) ;
381
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
382
+ debug_assert_eq ! ( index, _index) ;
383
+ index
301
384
}
302
385
303
386
/// Create a new `Value::Address` distinct from all the others.
@@ -310,18 +393,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310
393
}
311
394
AddressKind :: Address ( mutbl) => Ty :: new_ptr ( self . tcx , pty, mutbl. to_mutbl_lossy ( ) ) ,
312
395
} ;
313
- let value = Value :: Address { place, kind, provenance : self . next_opaque ( ) } ;
314
- self . insert ( ty, value)
396
+ let index =
397
+ self . values . insert_unique ( ty, |provenance| Value :: Address { place, kind, provenance } ) ;
398
+ let evaluated = self . eval_to_const ( index) ;
399
+ let _index = self . evaluated . push ( evaluated) ;
400
+ debug_assert_eq ! ( index, _index) ;
401
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
402
+ debug_assert_eq ! ( index, _index) ;
403
+ index
404
+ }
405
+
406
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
407
+ fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
408
+ let ( index, new) = if value. is_deterministic ( ) {
409
+ // The constant is deterministic, no need to disambiguate.
410
+ let constant = Value :: Constant { value, disambiguator : DETERMINISTIC } ;
411
+ self . values . insert ( constant, value. ty ( ) )
412
+ } else {
413
+ // Multiple mentions of this constant will yield different values,
414
+ // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
415
+ let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| {
416
+ debug_assert_ne ! ( disambiguator, DETERMINISTIC ) ;
417
+ Value :: Constant { value, disambiguator }
418
+ } ) ;
419
+ ( index, true )
420
+ } ;
421
+ if new {
422
+ let evaluated = self . eval_to_const ( index) ;
423
+ let _index = self . evaluated . push ( evaluated) ;
424
+ debug_assert_eq ! ( index, _index) ;
425
+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
426
+ debug_assert_eq ! ( index, _index) ;
427
+ }
428
+ index
315
429
}
316
430
317
431
#[ inline]
318
432
fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319
- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
433
+ self . values . value ( index)
320
434
}
321
435
322
436
#[ inline]
323
437
fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
324
- self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
438
+ self . values . ty ( index)
325
439
}
326
440
327
441
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -332,33 +446,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
332
446
self . rev_locals [ value] . push ( local) ;
333
447
}
334
448
335
- fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
336
- let disambiguator = if value. is_deterministic ( ) {
337
- // The constant is deterministic, no need to disambiguate.
338
- 0
339
- } else {
340
- // Multiple mentions of this constant will yield different values,
341
- // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342
- let disambiguator = self . next_opaque ( ) ;
343
- // `disambiguator: 0` means deterministic.
344
- debug_assert_ne ! ( disambiguator, 0 ) ;
345
- disambiguator
346
- } ;
347
- self . insert ( value. ty ( ) , Value :: Constant { value, disambiguator } )
348
- }
349
-
350
449
fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
351
450
// Booleans are deterministic.
352
451
let value = Const :: from_bool ( self . tcx , flag) ;
353
452
debug_assert ! ( value. is_deterministic( ) ) ;
354
- self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : 0 } )
453
+ self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : DETERMINISTIC } )
355
454
}
356
455
357
456
fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
358
457
// Scalars are deterministic.
359
458
let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
360
459
debug_assert ! ( value. is_deterministic( ) ) ;
361
- self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
460
+ self . insert ( ty, Value :: Constant { value, disambiguator : DETERMINISTIC } )
362
461
}
363
462
364
463
fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : Vec < VnIndex > ) -> VnIndex {
@@ -373,8 +472,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373
472
374
473
fn invalidate_derefs ( & mut self ) {
375
474
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) ;
475
+ self . values . forget ( deref) ;
378
476
}
379
477
}
380
478
@@ -1615,7 +1713,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1615
1713
// This was already constant in MIR, do not change it. If the constant is not
1616
1714
// deterministic, adding an additional mention of it in MIR will not give the same value as
1617
1715
// the former mention.
1618
- if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1716
+ if let Value :: Constant { value, disambiguator : DETERMINISTIC } = * self . get ( index) {
1619
1717
debug_assert ! ( value. is_deterministic( ) ) ;
1620
1718
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1621
1719
}
0 commit comments