Skip to content

Commit cc6cd58

Browse files
committed
Introduce ValueSet.
1 parent 040a98a commit cc6cd58

File tree

3 files changed

+86
-21
lines changed

3 files changed

+86
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4282,6 +4282,7 @@ name = "rustc_mir_transform"
42824282
version = "0.0.0"
42834283
dependencies = [
42844284
"either",
4285+
"hashbrown",
42854286
"itertools",
42864287
"rustc_abi",
42874288
"rustc_arena",

compiler/rustc_mir_transform/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2024"
77
# tidy-alphabetical-start
88
either = "1"
99
itertools = "0.12"
10+
hashbrown = "0.15"
1011
rustc_abi = { path = "../rustc_abi" }
1112
rustc_arena = { path = "../rustc_arena" }
1213
rustc_ast = { path = "../rustc_ast" }

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,17 @@
8585
//! that contain `AllocId`s.
8686
8787
use std::borrow::Cow;
88+
use std::hash::{Hash, Hasher};
8889

8990
use either::Either;
91+
use hashbrown::hash_table::{Entry, HashTable};
9092
use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
9193
use rustc_const_eval::const_eval::DummyMachine;
9294
use rustc_const_eval::interpret::{
9395
ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar,
9496
intern_const_alloc_for_constprop,
9597
};
96-
use rustc_data_structures::fx::{FxIndexSet, MutableValues};
98+
use rustc_data_structures::fx::FxHasher;
9799
use rustc_data_structures::graph::dominators::Dominators;
98100
use rustc_hir::def::DefKind;
99101
use rustc_index::bit_set::DenseBitSet;
@@ -212,6 +214,78 @@ enum Value<'tcx> {
212214
},
213215
}
214216

217+
struct ValueSet<'tcx> {
218+
indices: HashTable<VnIndex>,
219+
hashes: IndexVec<VnIndex, u64>,
220+
values: IndexVec<VnIndex, Value<'tcx>>,
221+
types: IndexVec<VnIndex, Ty<'tcx>>,
222+
/// Counter to generate different values.
223+
next_opaque: usize,
224+
}
225+
226+
impl<'tcx> ValueSet<'tcx> {
227+
fn new(num_values: usize) -> ValueSet<'tcx> {
228+
ValueSet {
229+
indices: HashTable::with_capacity(num_values),
230+
hashes: IndexVec::with_capacity(num_values),
231+
values: IndexVec::with_capacity(num_values),
232+
types: IndexVec::with_capacity(num_values),
233+
next_opaque: 1,
234+
}
235+
}
236+
237+
#[allow(rustc::pass_by_value)]
238+
fn insert(&mut self, value: Value<'tcx>, ty: Ty<'tcx>) -> (VnIndex, bool) {
239+
let hash: u64 = {
240+
let mut h = FxHasher::default();
241+
value.hash(&mut h);
242+
ty.hash(&mut h);
243+
h.finish()
244+
};
245+
246+
let eq = |index: &VnIndex| self.values[*index] == value && self.types[*index] == ty;
247+
let hasher = |index: &VnIndex| self.hashes[*index];
248+
match self.indices.entry(hash, eq, hasher) {
249+
Entry::Occupied(entry) => {
250+
let index = *entry.get();
251+
(index, false)
252+
}
253+
Entry::Vacant(entry) => {
254+
let index = self.hashes.push(hash);
255+
entry.insert(index);
256+
let _index = self.values.push(value);
257+
debug_assert_eq!(index, _index);
258+
let _index = self.types.push(ty);
259+
debug_assert_eq!(index, _index);
260+
(index, true)
261+
}
262+
}
263+
}
264+
265+
#[inline]
266+
fn next_opaque(&mut self) -> usize {
267+
let next_opaque = self.next_opaque;
268+
self.next_opaque += 1;
269+
next_opaque
270+
}
271+
272+
#[inline]
273+
fn value(&self, index: VnIndex) -> &Value<'tcx> {
274+
&self.values[index]
275+
}
276+
277+
#[inline]
278+
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
279+
self.types[index]
280+
}
281+
282+
#[inline]
283+
fn forget(&mut self, index: VnIndex) {
284+
let opaque = self.next_opaque();
285+
self.values[index] = Value::Opaque(opaque);
286+
}
287+
}
288+
215289
struct VnState<'body, 'tcx> {
216290
tcx: TyCtxt<'tcx>,
217291
ecx: InterpCx<'tcx, DummyMachine>,
@@ -222,11 +296,9 @@ struct VnState<'body, 'tcx> {
222296
/// Locals that are assigned that value.
223297
// This vector does not hold all the values of `VnIndex` that we create.
224298
rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
225-
values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>,
299+
values: ValueSet<'tcx>,
226300
/// Values evaluated as constants if possible.
227301
evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
228-
/// Counter to generate different values.
229-
next_opaque: usize,
230302
/// Cache the deref values.
231303
derefs: Vec<VnIndex>,
232304
ssa: &'body SsaLocals,
@@ -257,9 +329,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257329
is_coroutine: body.coroutine.is_some(),
258330
locals: IndexVec::from_elem(None, local_decls),
259331
rev_locals: IndexVec::with_capacity(num_values),
260-
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
332+
values: ValueSet::new(num_values),
261333
evaluated: IndexVec::with_capacity(num_values),
262-
next_opaque: 1,
263334
derefs: Vec::new(),
264335
ssa,
265336
dominators,
@@ -273,8 +344,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273344

274345
#[instrument(level = "trace", skip(self), ret)]
275346
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);
347+
let (index, new) = self.values.insert(value, ty);
278348
if new {
279349
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
280350
let evaluated = self.eval_to_const(index);
@@ -286,17 +356,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286356
index
287357
}
288358

289-
fn next_opaque(&mut self) -> usize {
290-
let next_opaque = self.next_opaque;
291-
self.next_opaque += 1;
292-
next_opaque
293-
}
294-
295359
/// Create a new `Value` for which we have no information at all, except that it is distinct
296360
/// from all the others.
297361
#[instrument(level = "trace", skip(self), ret)]
298362
fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
299-
let value = Value::Opaque(self.next_opaque());
363+
let value = Value::Opaque(self.values.next_opaque());
300364
self.insert(ty, value)
301365
}
302366

@@ -310,18 +374,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310374
}
311375
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()),
312376
};
313-
let value = Value::Address { place, kind, provenance: self.next_opaque() };
377+
let value = Value::Address { place, kind, provenance: self.values.next_opaque() };
314378
self.insert(ty, value)
315379
}
316380

317381
#[inline]
318382
fn get(&self, index: VnIndex) -> &Value<'tcx> {
319-
&self.values.get_index(index.as_usize()).unwrap().0
383+
self.values.value(index)
320384
}
321385

322386
#[inline]
323387
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
324-
self.values.get_index(index.as_usize()).unwrap().1
388+
self.values.ty(index)
325389
}
326390

327391
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -339,7 +403,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339403
} else {
340404
// Multiple mentions of this constant will yield different values,
341405
// so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342-
let disambiguator = self.next_opaque();
406+
let disambiguator = self.values.next_opaque();
343407
// `disambiguator: 0` means deterministic.
344408
debug_assert_ne!(disambiguator, 0);
345409
disambiguator
@@ -373,8 +437,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373437

374438
fn invalidate_derefs(&mut self) {
375439
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);
440+
self.values.forget(deref);
378441
}
379442
}
380443

0 commit comments

Comments
 (0)