Skip to content

Commit 3d0eda7

Browse files
committed
Introduce ValueSet.
1 parent b50f345 commit 3d0eda7

File tree

3 files changed

+98
-21
lines changed

3 files changed

+98
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,6 +4235,7 @@ name = "rustc_mir_transform"
42354235
version = "0.0.0"
42364236
dependencies = [
42374237
"either",
4238+
"hashbrown",
42384239
"itertools",
42394240
"rustc_abi",
42404241
"rustc_arena",

compiler/rustc_mir_transform/Cargo.toml

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

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 96 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,18 @@
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 itertools::Itertools as _;
9193
use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
9294
use rustc_const_eval::const_eval::DummyMachine;
9395
use rustc_const_eval::interpret::{
9496
ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar,
9597
intern_const_alloc_for_constprop,
9698
};
97-
use rustc_data_structures::fx::{FxIndexSet, MutableValues};
99+
use rustc_data_structures::fx::FxHasher;
98100
use rustc_data_structures::graph::dominators::Dominators;
99101
use rustc_hir::def::DefKind;
100102
use rustc_index::bit_set::DenseBitSet;
@@ -152,6 +154,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
152154
}
153155

154156
newtype_index! {
157+
#[debug_format = "_v{}"]
155158
struct VnIndex {}
156159
}
157160

@@ -213,6 +216,89 @@ enum Value<'tcx> {
213216
},
214217
}
215218

219+
/// Stores and deduplicates pairs of `(Value, Ty)` into in `VnIndex` numbered values.
220+
///
221+
/// This data structure is mostly a partial reimplementation of `FxIndexMap<VnIndex, (Value, Ty)>`.
222+
/// We do not use a regular `FxIndexMap` to skip hashing values that are unique by construction,
223+
/// like opaque values, address with provenance and non-deterministic constants.
224+
struct ValueSet<'tcx> {
225+
indices: HashTable<VnIndex>,
226+
hashes: IndexVec<VnIndex, u64>,
227+
values: IndexVec<VnIndex, Value<'tcx>>,
228+
types: IndexVec<VnIndex, Ty<'tcx>>,
229+
/// Counter to generate different values.
230+
next_opaque: usize,
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+
next_opaque: 1,
241+
}
242+
}
243+
244+
/// Insert a `(Value, Ty)` pair to be deduplicated.
245+
/// Returns `true` as second tuple field if this value did not exist previously.
246+
#[allow(rustc::pass_by_value)] // closures take `&VnIndex`
247+
fn insert(&mut self, ty: Ty<'tcx>, value: Value<'tcx>) -> (VnIndex, bool) {
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+
/// Increment the opaque index counter return a new unique value.
275+
#[inline]
276+
fn next_opaque(&mut self) -> usize {
277+
let next_opaque = self.next_opaque;
278+
self.next_opaque += 1;
279+
next_opaque
280+
}
281+
282+
/// Return the `Value` associated with the given `VnIndex`.
283+
#[inline]
284+
fn value(&self, index: VnIndex) -> &Value<'tcx> {
285+
&self.values[index]
286+
}
287+
288+
/// Return the type associated with the given `VnIndex`.
289+
#[inline]
290+
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
291+
self.types[index]
292+
}
293+
294+
/// Replace the value associated with `index` with an opaque value.
295+
#[inline]
296+
fn forget(&mut self, index: VnIndex) {
297+
let opaque = self.next_opaque();
298+
self.values[index] = Value::Opaque(opaque);
299+
}
300+
}
301+
216302
struct VnState<'body, 'tcx> {
217303
tcx: TyCtxt<'tcx>,
218304
ecx: InterpCx<'tcx, DummyMachine>,
@@ -223,11 +309,9 @@ struct VnState<'body, 'tcx> {
223309
/// Locals that are assigned that value.
224310
// This vector does not hold all the values of `VnIndex` that we create.
225311
rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
226-
values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>,
312+
values: ValueSet<'tcx>,
227313
/// Values evaluated as constants if possible.
228314
evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
229-
/// Counter to generate different values.
230-
next_opaque: usize,
231315
/// Cache the deref values.
232316
derefs: Vec<VnIndex>,
233317
ssa: &'body SsaLocals,
@@ -258,9 +342,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
258342
is_coroutine: body.coroutine.is_some(),
259343
locals: IndexVec::from_elem(None, local_decls),
260344
rev_locals: IndexVec::with_capacity(num_values),
261-
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
345+
values: ValueSet::new(num_values),
262346
evaluated: IndexVec::with_capacity(num_values),
263-
next_opaque: 1,
264347
derefs: Vec::new(),
265348
ssa,
266349
dominators,
@@ -274,8 +357,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
274357

275358
#[instrument(level = "trace", skip(self), ret)]
276359
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);
360+
let (index, new) = self.values.insert(ty, value);
279361
if new {
280362
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
281363
let evaluated = self.eval_to_const(index);
@@ -287,17 +369,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
287369
index
288370
}
289371

290-
fn next_opaque(&mut self) -> usize {
291-
let next_opaque = self.next_opaque;
292-
self.next_opaque += 1;
293-
next_opaque
294-
}
295-
296372
/// Create a new `Value` for which we have no information at all, except that it is distinct
297373
/// from all the others.
298374
#[instrument(level = "trace", skip(self), ret)]
299375
fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
300-
let value = Value::Opaque(self.next_opaque());
376+
let value = Value::Opaque(self.values.next_opaque());
301377
self.insert(ty, value)
302378
}
303379

@@ -311,18 +387,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
311387
}
312388
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()),
313389
};
314-
let value = Value::Address { place, kind, provenance: self.next_opaque() };
390+
let value = Value::Address { place, kind, provenance: self.values.next_opaque() };
315391
self.insert(ty, value)
316392
}
317393

318394
#[inline]
319395
fn get(&self, index: VnIndex) -> &Value<'tcx> {
320-
&self.values.get_index(index.as_usize()).unwrap().0
396+
self.values.value(index)
321397
}
322398

323399
#[inline]
324400
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
325-
self.values.get_index(index.as_usize()).unwrap().1
401+
self.values.ty(index)
326402
}
327403

328404
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -340,7 +416,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
340416
} else {
341417
// Multiple mentions of this constant will yield different values,
342418
// so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
343-
let disambiguator = self.next_opaque();
419+
let disambiguator = self.values.next_opaque();
344420
// `disambiguator: 0` means deterministic.
345421
debug_assert_ne!(disambiguator, 0);
346422
disambiguator
@@ -374,8 +450,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
374450

375451
fn invalidate_derefs(&mut self) {
376452
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);
453+
self.values.forget(deref);
379454
}
380455
}
381456

0 commit comments

Comments
 (0)