diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index ae9aa743a75f8..5039d27a46fb4 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -437,7 +437,7 @@ fn expand_preparsed_asm( let positional_args = args.operands.len() - args.named_args.len() - - args.reg_args.len(); + - args.reg_args.count(); let positional = if positional_args != args.operands.len() { "positional " } else { diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index aa3c759a6adbd..ff66c33fe2236 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -78,7 +78,7 @@ fn inclusive_start_end( #[derive(Eq, PartialEq, Hash)] pub struct DenseBitSet { domain_size: usize, - words: Vec, + words: Box<[Word]>, marker: PhantomData, } @@ -94,19 +94,44 @@ impl DenseBitSet { #[inline] pub fn new_empty(domain_size: usize) -> DenseBitSet { let num_words = num_words(domain_size); - DenseBitSet { domain_size, words: vec![0; num_words], marker: PhantomData } + DenseBitSet { + domain_size, + words: vec![0; num_words].into_boxed_slice(), + marker: PhantomData, + } } /// Creates a new, filled bitset with a given `domain_size`. #[inline] pub fn new_filled(domain_size: usize) -> DenseBitSet { let num_words = num_words(domain_size); - let mut result = - DenseBitSet { domain_size, words: vec![!0; num_words], marker: PhantomData }; + let mut result = DenseBitSet { + domain_size, + words: vec![!0; num_words].into_boxed_slice(), + marker: PhantomData, + }; result.clear_excess_bits(); result } + /// Replaces this bitset with one having the same elements, but a larger domain size. + #[inline] + pub fn enlarge(self, new_domain_size: usize) -> DenseBitSet { + // We could also support shrinking, but it's hard to imagine a real use-case for it. + assert!(self.domain_size <= new_domain_size); + let new_num_words = num_words(new_domain_size); + + let DenseBitSet { domain_size: _, mut words, marker } = self; + + if new_num_words != words.len() { + let mut words_vec = words.into_vec(); + words_vec.resize(new_num_words, 0); + words = words_vec.into_boxed_slice() + } + + DenseBitSet { domain_size: new_domain_size, words, marker } + } + /// Clear all elements. #[inline] pub fn clear(&mut self) { @@ -123,11 +148,27 @@ impl DenseBitSet { count_ones(&self.words) } - /// Returns `true` if `self` contains `elem`. + /// Returns `true` if this bitset contains `value`. + /// + /// Unlike [`DenseBitSet::contains`], this method does not panic if the value + /// is outside this bitset's domain, and simply returns `false` instead. #[inline] - pub fn contains(&self, elem: T) -> bool { - assert!(elem.index() < self.domain_size); - let (word_index, mask) = word_index_and_mask(elem); + pub fn contains_loose(&self, value: T) -> bool { + (value.index() < self.domain_size) && self.contains(value) + } + + /// Returns `true` if this bitset contains `value`. + /// + /// # Panics + /// If `value` is outside this bitset's domain. + /// + /// # See also + /// To allow out-of-domain values without panicking, use [`DenseBitSet::contains_loose`] + /// instead. + #[inline] + pub fn contains(&self, value: T) -> bool { + assert!(value.index() < self.domain_size); + let (word_index, mask) = word_index_and_mask(value); (self.words[word_index] & mask) != 0 } @@ -146,19 +187,14 @@ impl DenseBitSet { /// Insert `elem`. Returns whether the set has changed. #[inline] - pub fn insert(&mut self, elem: T) -> bool { + pub fn insert(&mut self, value: T) -> bool { assert!( - elem.index() < self.domain_size, + value.index() < self.domain_size, "inserting element at index {} but domain size is {}", - elem.index(), + value.index(), self.domain_size, ); - let (word_index, mask) = word_index_and_mask(elem); - let word_ref = &mut self.words[word_index]; - let word = *word_ref; - let new_word = word | mask; - *word_ref = new_word; - new_word != word + insert(&mut self.words, value) } #[inline] @@ -317,12 +353,6 @@ impl DenseBitSet { } } -impl From> for DenseBitSet { - fn from(bit_set: GrowableBitSet) -> Self { - bit_set.bit_set - } -} - impl Clone for DenseBitSet { fn clone(&self) -> Self { DenseBitSet { @@ -1199,22 +1229,25 @@ impl<'a, T: Idx> Iterator for MixedBitIter<'a, T> { /// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also /// just be `usize`. -/// -/// All operations that involve an element will panic if the element is equal -/// to or greater than the domain size. #[derive(Debug, PartialEq)] pub struct GrowableBitSet { - bit_set: DenseBitSet, + domain_size: usize, + words: Vec, + marker: PhantomData, } -// Manually implemented to forward `clone_from`, and to avoid the `T: Clone` bound. +// Manually implemented to provide `clone_from`. impl Clone for GrowableBitSet { fn clone(&self) -> Self { - Self { bit_set: self.bit_set.clone() } + let &GrowableBitSet { domain_size, ref words, marker } = self; + GrowableBitSet { domain_size, words: words.clone(), marker } } fn clone_from(&mut self, source: &Self) { - self.bit_set.clone_from(&source.bit_set); + let GrowableBitSet { domain_size, words, marker } = source; + self.domain_size.clone_from(domain_size); + self.words.clone_from(words); + self.marker.clone_from(marker); } } @@ -1227,87 +1260,54 @@ impl Default for GrowableBitSet { impl GrowableBitSet { /// Ensure that the set can hold at least `min_domain_size` elements. pub fn ensure(&mut self, min_domain_size: usize) { - if self.bit_set.domain_size < min_domain_size { - self.bit_set.domain_size = min_domain_size; + if self.domain_size < min_domain_size { + self.domain_size = min_domain_size; } let min_num_words = num_words(min_domain_size); - if self.bit_set.words.len() < min_num_words { - self.bit_set.words.resize(min_num_words, 0) + if self.words.len() < min_num_words { + self.words.resize(min_num_words, 0) } } pub fn new_empty() -> GrowableBitSet { - GrowableBitSet { bit_set: DenseBitSet::new_empty(0) } + GrowableBitSet { domain_size: 0, words: vec![], marker: PhantomData } } pub fn with_capacity(capacity: usize) -> GrowableBitSet { - GrowableBitSet { bit_set: DenseBitSet::new_empty(capacity) } - } - - /// Returns `true` if the set has changed. - #[inline] - pub fn insert(&mut self, elem: T) -> bool { - self.ensure(elem.index() + 1); - self.bit_set.insert(elem) - } - - #[inline] - pub fn insert_range(&mut self, elems: Range) { - self.ensure(elems.end.index()); - self.bit_set.insert_range(elems); + GrowableBitSet { + domain_size: capacity, + words: vec![0; num_words(capacity)], + marker: PhantomData, + } } /// Returns `true` if the set has changed. #[inline] - pub fn remove(&mut self, elem: T) -> bool { - self.ensure(elem.index() + 1); - self.bit_set.remove(elem) - } - - #[inline] - pub fn clear(&mut self) { - self.bit_set.clear(); + pub fn insert(&mut self, value: T) -> bool { + self.ensure(value.index() + 1); + insert(&mut self.words, value) } #[inline] pub fn count(&self) -> usize { - self.bit_set.count() + count_ones(&self.words) } #[inline] pub fn is_empty(&self) -> bool { - self.bit_set.is_empty() + self.words.iter().all(|&w| w == 0) } #[inline] pub fn contains(&self, elem: T) -> bool { let (word_index, mask) = word_index_and_mask(elem); - self.bit_set.words.get(word_index).is_some_and(|word| (word & mask) != 0) - } - - #[inline] - pub fn contains_any(&self, elems: Range) -> bool { - elems.start.index() < self.bit_set.domain_size - && self - .bit_set - .contains_any(elems.start..T::new(elems.end.index().min(self.bit_set.domain_size))) + self.words.get(word_index).is_some_and(|word| (word & mask) != 0) } #[inline] pub fn iter(&self) -> BitIter<'_, T> { - self.bit_set.iter() - } - - #[inline] - pub fn len(&self) -> usize { - self.bit_set.count() - } -} - -impl From> for GrowableBitSet { - fn from(bit_set: DenseBitSet) -> Self { - Self { bit_set } + BitIter::new(&self.words) } } @@ -1644,3 +1644,13 @@ fn max_bit(word: Word) -> usize { fn count_ones(words: &[Word]) -> usize { words.iter().map(|word| word.count_ones() as usize).sum() } + +#[inline] +fn insert(words: &mut [Word], value: T) -> bool { + let (word_index, mask) = word_index_and_mask(value); + let word_ref = &mut words[word_index]; + let word = *word_ref; + let new_word = word | mask; + *word_ref = new_word; + new_word != word +} diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 1834be2edbac2..871216b553651 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -15,6 +15,17 @@ fn test_new_filled() { } } +/// [`DenseBitSet::contains_loose`] should not panic when given an out-of-domain value. +#[test] +fn contains_loose() { + let mut bitset = DenseBitSet::new_empty(100); + bitset.insert(77u32); + + for i in 0..256 { + assert_eq!(bitset.contains_loose(i), i == 77); + } +} + #[test] fn bitset_iter_works() { let mut bitset: DenseBitSet = DenseBitSet::new_empty(100); diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index e4fa76b0c8aaf..e3b600e8ae778 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -66,7 +66,7 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; -use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet}; +use rustc_index::bit_set::{BitMatrix, DenseBitSet}; use rustc_index::{Idx, IndexVec, indexvec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -172,7 +172,7 @@ struct SuspensionPoint<'tcx> { /// Which block to jump to if the coroutine is dropped in this state. drop: Option, /// Set of locals that have live storage while at this suspension point. - storage_liveness: GrowableBitSet, + storage_liveness: DenseBitSet, } struct TransformVisitor<'tcx> { @@ -510,8 +510,8 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); } - let storage_liveness: GrowableBitSet = - self.storage_liveness[block].clone().unwrap().into(); + let storage_liveness: DenseBitSet = + self.storage_liveness[block].clone().unwrap(); for i in 0..self.always_live_locals.domain_size() { let l = Local::new(i); @@ -991,7 +991,7 @@ fn create_cases<'tcx>( // Create StorageLive instructions for locals with live storage for l in body.local_decls.indices() { - let needs_storage_live = point.storage_liveness.contains(l) + let needs_storage_live = point.storage_liveness.contains_loose(l) && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); if needs_storage_live { diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index c115889205878..88056de13b6d1 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -2,7 +2,7 @@ use rustc_abi::FieldIdx; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_hir::attrs::lang_items::LangItem; use rustc_index::IndexVec; -use rustc_index::bit_set::{DenseBitSet, GrowableBitSet}; +use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; @@ -40,11 +40,7 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates { let all_dead_locals = replace_flattened_locals(tcx, body, replacements); if !all_dead_locals.is_empty() { excluded.union(&all_dead_locals); - excluded = { - let mut growable = GrowableBitSet::from(excluded); - growable.ensure(body.local_decls.len()); - growable.into() - }; + excluded = excluded.enlarge(body.local_decls.len()); } else { break; } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 84b92d49f24c2..c0a8ec210769e 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -59,7 +59,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { .max() .expect("owning item has no entry"); - if max != self.hir_ids_seen.len() - 1 { + if max != self.hir_ids_seen.count() - 1 { let pretty_owner = self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose(); let missing_items: Vec<_> = (0..=max as u32)