Skip to content

Commit b075528

Browse files
initial change
1 parent aa9680b commit b075528

1 file changed

Lines changed: 51 additions & 3 deletions

File tree

src/ion/data_structures.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,53 @@ impl core::ops::IndexMut<VReg> for VRegs {
444444
}
445445
}
446446

447+
/// A dedup set of `LiveBundleIndex` values that avoids hashing.
448+
///
449+
/// Each bundle index is mapped to a slot in a dense array holding the
450+
/// generation at which it was last inserted. `clear` simply bumps the
451+
/// current generation (O(1) in the common case), and `insert` is a
452+
/// single bounds-checked compare-and-store. This is a drop-in
453+
/// replacement for the previous `FxHashSet<LiveBundleIndex>` that is
454+
/// much cheaper when a bundle conflicts with many others (e.g. a
455+
/// function with many locals).
456+
#[derive(Clone, Debug, Default)]
457+
pub struct ConflictSet {
458+
// Generation at which each bundle was last inserted. The value `0`
459+
// means "never inserted"; `generation` is therefore always >= 1
460+
// after the first `clear`.
461+
stamps: Vec<u32>,
462+
generation: u32,
463+
}
464+
465+
impl ConflictSet {
466+
/// Empty the set. O(1) except on the rare generation wraparound.
467+
#[inline]
468+
pub fn clear(&mut self) {
469+
self.generation = self.generation.wrapping_add(1);
470+
if self.generation == 0 {
471+
// Wrapped around; reset stamps so stale entries don't read
472+
// as present, and skip the reserved `0` generation.
473+
self.stamps.iter_mut().for_each(|s| *s = 0);
474+
self.generation = 1;
475+
}
476+
}
477+
478+
/// Insert `bundle`. Returns `true` if it was not already present.
479+
#[inline]
480+
pub fn insert(&mut self, bundle: LiveBundleIndex) -> bool {
481+
let idx = bundle.index();
482+
if idx >= self.stamps.len() {
483+
self.stamps.resize(idx + 1, 0);
484+
}
485+
if self.stamps[idx] == self.generation {
486+
false
487+
} else {
488+
self.stamps[idx] = self.generation;
489+
true
490+
}
491+
}
492+
}
493+
447494
#[derive(Default)]
448495
pub struct Ctx {
449496
pub(crate) cfginfo: CFGInfo,
@@ -484,9 +531,10 @@ pub struct Ctx {
484531
pub(crate) debug_annotations: FxHashMap<ProgPoint, Vec<String>>,
485532
pub(crate) annotations_enabled: bool,
486533

487-
// Cached allocation for `try_to_allocate_bundle_to_reg` to avoid allocating
488-
// a new HashSet on every call.
489-
pub(crate) conflict_set: FxHashSet<LiveBundleIndex>,
534+
// Scratch dedup set for `try_to_allocate_bundle_to_reg`, reused
535+
// across calls. Uses generation stamping to avoid hashing and to
536+
// make clearing O(1).
537+
pub(crate) conflict_set: ConflictSet,
490538

491539
// Output:
492540
pub output: Output,

0 commit comments

Comments
 (0)