Skip to content

Commit b1206a5

Browse files
Auto merge of #145737 - cjgillot:gvn-valueset, r=<try>
GVN: stop hashing opaque values
2 parents 6ba0ce4 + 1a6584f commit b1206a5

File tree

3 files changed

+114
-22
lines changed

3 files changed

+114
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4293,6 +4293,7 @@ name = "rustc_mir_transform"
42934293
version = "0.0.0"
42944294
dependencies = [
42954295
"either",
4296+
"hashbrown",
42964297
"itertools",
42974298
"rustc_abi",
42984299
"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: 112 additions & 22 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;
@@ -151,9 +153,15 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
151153
}
152154

153155
newtype_index! {
156+
#[debug_format = "_v{}"]
154157
struct VnIndex {}
155158
}
156159

160+
newtype_index! {
161+
#[debug_format = "_o{}"]
162+
struct VnOpaque {}
163+
}
164+
157165
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
158166
enum AddressKind {
159167
Ref(BorrowKind),
@@ -165,7 +173,7 @@ enum Value<'tcx> {
165173
// Root values.
166174
/// Used to represent values we know nothing about.
167175
/// The `usize` is a counter incremented by `new_opaque`.
168-
Opaque(usize),
176+
Opaque(VnOpaque),
169177
/// Evaluated or unevaluated constant value.
170178
Constant {
171179
value: Const<'tcx>,
@@ -212,6 +220,85 @@ enum Value<'tcx> {
212220
},
213221
}
214222

223+
struct ValueSet<'tcx> {
224+
indices: HashTable<VnIndex>,
225+
hashes: IndexVec<VnIndex, u64>,
226+
values: IndexVec<VnIndex, Value<'tcx>>,
227+
types: IndexVec<VnIndex, Ty<'tcx>>,
228+
opaques: IndexVec<VnOpaque, VnIndex>,
229+
}
230+
231+
impl<'tcx> ValueSet<'tcx> {
232+
fn new(num_values: usize) -> ValueSet<'tcx> {
233+
ValueSet {
234+
indices: HashTable::with_capacity(num_values),
235+
hashes: IndexVec::with_capacity(num_values),
236+
values: IndexVec::with_capacity(num_values),
237+
types: IndexVec::with_capacity(num_values),
238+
opaques: IndexVec::with_capacity(num_values),
239+
}
240+
}
241+
242+
#[allow(rustc::pass_by_value)]
243+
fn insert(&mut self, value: Value<'tcx>, ty: Ty<'tcx>) -> (VnIndex, bool) {
244+
if let Value::Opaque(opaque) = value {
245+
return (self.opaques[opaque], false);
246+
}
247+
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+
#[inline]
275+
fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
276+
let index = self.hashes.push(0);
277+
let _index = self.types.push(ty);
278+
debug_assert_eq!(index, _index);
279+
let opaque = self.opaques.push(index);
280+
let _index = self.values.push(Value::Opaque(opaque));
281+
debug_assert_eq!(index, _index);
282+
index
283+
}
284+
285+
#[inline]
286+
fn value(&self, index: VnIndex) -> &Value<'tcx> {
287+
&self.values[index]
288+
}
289+
290+
#[inline]
291+
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
292+
self.types[index]
293+
}
294+
295+
#[inline]
296+
fn forget(&mut self, index: VnIndex) {
297+
let opaque = self.opaques.push(index);
298+
self.values[index] = Value::Opaque(opaque);
299+
}
300+
}
301+
215302
struct VnState<'body, 'tcx> {
216303
tcx: TyCtxt<'tcx>,
217304
ecx: InterpCx<'tcx, DummyMachine>,
@@ -222,11 +309,11 @@ struct VnState<'body, 'tcx> {
222309
/// Locals that are assigned that value.
223310
// This vector does not hold all the values of `VnIndex` that we create.
224311
rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
225-
values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>,
312+
values: ValueSet<'tcx>,
226313
/// Values evaluated as constants if possible.
227314
evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
228315
/// Counter to generate different values.
229-
next_opaque: usize,
316+
next_disambiguator: usize,
230317
/// Cache the deref values.
231318
derefs: Vec<VnIndex>,
232319
ssa: &'body SsaLocals,
@@ -257,9 +344,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
257344
is_coroutine: body.coroutine.is_some(),
258345
locals: IndexVec::from_elem(None, local_decls),
259346
rev_locals: IndexVec::with_capacity(num_values),
260-
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
347+
values: ValueSet::new(num_values),
261348
evaluated: IndexVec::with_capacity(num_values),
262-
next_opaque: 1,
349+
next_disambiguator: 1,
263350
derefs: Vec::new(),
264351
ssa,
265352
dominators,
@@ -273,8 +360,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
273360

274361
#[instrument(level = "trace", skip(self), ret)]
275362
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);
363+
let (index, new) = self.values.insert(value, ty);
278364
if new {
279365
// Grow `evaluated` and `rev_locals` here to amortize the allocations.
280366
let evaluated = self.eval_to_const(index);
@@ -286,18 +372,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
286372
index
287373
}
288374

289-
fn next_opaque(&mut self) -> usize {
290-
let next_opaque = self.next_opaque;
291-
self.next_opaque += 1;
292-
next_opaque
293-
}
294-
295375
/// Create a new `Value` for which we have no information at all, except that it is distinct
296376
/// from all the others.
297377
#[instrument(level = "trace", skip(self), ret)]
298378
fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
299-
let value = Value::Opaque(self.next_opaque());
300-
self.insert(ty, value)
379+
let index = self.values.new_opaque(ty);
380+
let _index = self.evaluated.push(None);
381+
debug_assert_eq!(index, _index);
382+
let _index = self.rev_locals.push(SmallVec::new());
383+
debug_assert_eq!(index, _index);
384+
index
385+
}
386+
387+
#[inline]
388+
fn next_disambiguator(&mut self) -> usize {
389+
let next_disambiguator = self.next_disambiguator;
390+
self.next_disambiguator += 1;
391+
next_disambiguator
301392
}
302393

303394
/// Create a new `Value::Address` distinct from all the others.
@@ -310,18 +401,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
310401
}
311402
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()),
312403
};
313-
let value = Value::Address { place, kind, provenance: self.next_opaque() };
404+
let value = Value::Address { place, kind, provenance: self.next_disambiguator() };
314405
self.insert(ty, value)
315406
}
316407

317408
#[inline]
318409
fn get(&self, index: VnIndex) -> &Value<'tcx> {
319-
&self.values.get_index(index.as_usize()).unwrap().0
410+
self.values.value(index)
320411
}
321412

322413
#[inline]
323414
fn ty(&self, index: VnIndex) -> Ty<'tcx> {
324-
self.values.get_index(index.as_usize()).unwrap().1
415+
self.values.ty(index)
325416
}
326417

327418
/// Record that `local` is assigned `value`. `local` must be SSA.
@@ -339,7 +430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
339430
} else {
340431
// Multiple mentions of this constant will yield different values,
341432
// so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
342-
let disambiguator = self.next_opaque();
433+
let disambiguator = self.next_disambiguator();
343434
// `disambiguator: 0` means deterministic.
344435
debug_assert_ne!(disambiguator, 0);
345436
disambiguator
@@ -373,8 +464,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373464

374465
fn invalidate_derefs(&mut self) {
375466
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);
467+
self.values.forget(deref);
378468
}
379469
}
380470

0 commit comments

Comments
 (0)