Skip to content

Commit

Permalink
index: introduce and use FiniteBitSet
Browse files Browse the repository at this point in the history
This commit introduces a `FiniteBitSet` type which replaces the manual
bit manipulation which was being performed in polymorphization.

Signed-off-by: David Wood <david@davidtw.co>
  • Loading branch information
davidtwco committed Jul 20, 2020
1 parent b1f8bd6 commit 4b99699
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 73 deletions.
9 changes: 9 additions & 0 deletions src/librustc_data_structures/stable_hasher.rs
Expand Up @@ -469,6 +469,15 @@ impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C>
}
}

impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T>
where
T: HashStable<CTX> + bit_set::FiniteBitSetTy,
{
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.0.hash_stable(hcx, hasher);
}
}

impl_stable_hash_via_hash!(::std::path::Path);
impl_stable_hash_via_hash!(::std::path::PathBuf);

Expand Down
135 changes: 135 additions & 0 deletions src/librustc_index/bit_set.rs
Expand Up @@ -4,6 +4,7 @@ use std::fmt;
use std::iter;
use std::marker::PhantomData;
use std::mem;
use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
use std::slice;

#[cfg(test)]
Expand Down Expand Up @@ -1001,3 +1002,137 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
let mask = 1 << (elem % WORD_BITS);
(word_index, mask)
}

/// Integral type used to represent the bit set.
pub trait FiniteBitSetTy:
BitAnd<Output = Self>
+ BitAndAssign
+ BitOrAssign
+ Clone
+ Copy
+ Shl
+ Not<Output = Self>
+ PartialEq
+ Sized
{
/// Size of the domain representable by this type, e.g. 64 for `u64`.
const DOMAIN_SIZE: u32;

/// Value which represents the `FiniteBitSet` having every bit set.
const FILLED: Self;
/// Value which represents the `FiniteBitSet` having no bits set.
const EMPTY: Self;

/// Value for one as the integral type.
const ONE: Self;
/// Value for zero as the integral type.
const ZERO: Self;

/// Perform a checked left shift on the integral type.
fn checked_shl(self, rhs: u32) -> Option<Self>;
/// Perform a checked right shift on the integral type.
fn checked_shr(self, rhs: u32) -> Option<Self>;
}

impl FiniteBitSetTy for u64 {
const DOMAIN_SIZE: u32 = 64;

const FILLED: Self = Self::MAX;
const EMPTY: Self = Self::MIN;

const ONE: Self = 1u64;
const ZERO: Self = 0u64;

fn checked_shl(self, rhs: u32) -> Option<Self> {
self.checked_shl(rhs)
}

fn checked_shr(self, rhs: u32) -> Option<Self> {
self.checked_shr(rhs)
}
}

impl std::fmt::Debug for FiniteBitSet<u64> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:064b}", self.0)
}
}

impl FiniteBitSetTy for u128 {
const DOMAIN_SIZE: u32 = 128;

const FILLED: Self = Self::MAX;
const EMPTY: Self = Self::MIN;

const ONE: Self = 1u128;
const ZERO: Self = 0u128;

fn checked_shl(self, rhs: u32) -> Option<Self> {
self.checked_shl(rhs)
}

fn checked_shr(self, rhs: u32) -> Option<Self> {
self.checked_shr(rhs)
}
}

impl std::fmt::Debug for FiniteBitSet<u128> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:0128b}", self.0)
}
}

/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
/// representable by `T` are considered set.
#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);

impl<T: FiniteBitSetTy> FiniteBitSet<T> {
/// Creates a new, empty bitset.
pub fn new_empty() -> Self {
Self(T::EMPTY)
}

/// Sets the `index`th bit.
pub fn set(&mut self, index: u32) {
self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO);
}

/// Unsets the `index`th bit.
pub fn clear(&mut self, index: u32) {
self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO);
}

/// Sets the `i`th to `j`th bits.
pub fn set_range(&mut self, range: Range<u32>) {
let bits = T::FILLED
.checked_shl(range.end - range.start)
.unwrap_or(T::ZERO)
.not()
.checked_shl(range.start)
.unwrap_or(T::ZERO);
self.0 |= bits;
}

/// Is the set empty?
pub fn is_empty(&self) -> bool {
self.0 == T::EMPTY
}

/// Returns the domain size of the bitset.
pub fn within_domain(&self, index: u32) -> bool {
index < T::DOMAIN_SIZE
}

/// Returns if the `index`th bit is set.
pub fn contains(&self, index: u32) -> Option<bool> {
self.within_domain(index)
.then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
}
}

impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
fn default() -> Self {
Self::new_empty()
}
}
1 change: 1 addition & 0 deletions src/librustc_index/lib.rs
@@ -1,4 +1,5 @@
#![feature(allow_internal_unstable)]
#![feature(bool_to_option)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/rmeta/decoder.rs
Expand Up @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.decode((self, tcx))
}

fn get_unused_generic_params(&self, id: DefIndex) -> u64 {
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> {
self.root
.tables
.unused_generic_params
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_metadata/rmeta/mod.rs
Expand Up @@ -9,7 +9,7 @@ use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, DefIndex};
use rustc_hir::lang_items;
use rustc_index::vec::IndexVec;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib};
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
Expand Down Expand Up @@ -277,7 +277,7 @@ define_tables! {
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
unused_generic_params: Table<DefIndex, Lazy<u64>>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>,
}

#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/query/mod.rs
Expand Up @@ -1309,7 +1309,7 @@ rustc_queries! {
query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
desc { "codegen_unit" }
}
query unused_generic_params(key: DefId) -> u64 {
query unused_generic_params(key: DefId) -> FiniteBitSet<u64> {
cache_on_disk_if { key.is_local() }
desc {
|tcx| "determining which generic parameters are unused by `{}`",
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_middle/ty/instance.rs
Expand Up @@ -474,20 +474,20 @@ impl<'tcx> Instance<'tcx> {
}

if let InstanceDef::Item(def) = self.def {
let results = tcx.unused_generic_params(def.did);
let unused = tcx.unused_generic_params(def.did);

if results == 0 {
if unused.is_empty() {
// Exit early if every parameter was used.
return self;
}

debug!("polymorphize: results={:064b}", results);
debug!("polymorphize: unused={:?}", unused);
let polymorphized_substs =
InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
// If parameter is a const or type parameter..
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
// ..and is within range and unused..
param.index < 64 && ((results >> param.index) & 1) == 1 =>
unused.contains(param.index).unwrap_or(false) =>
// ..then use the identity for this parameter.
tcx.mk_param_from_def(param),
// Otherwise, use the parameter as before.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/ty/query/mod.rs
Expand Up @@ -44,7 +44,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
use rustc_index::vec::IndexVec;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind;
use rustc_session::CrateDisambiguator;
Expand Down

0 comments on commit 4b99699

Please sign in to comment.