Skip to content

Commit 4b99699

Browse files
committed
index: introduce and use FiniteBitSet
This commit introduces a `FiniteBitSet` type which replaces the manual bit manipulation which was being performed in polymorphization. Signed-off-by: David Wood <[email protected]>
1 parent b1f8bd6 commit 4b99699

File tree

10 files changed

+211
-73
lines changed

10 files changed

+211
-73
lines changed

src/librustc_data_structures/stable_hasher.rs

+9
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,15 @@ impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C>
469469
}
470470
}
471471

472+
impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T>
473+
where
474+
T: HashStable<CTX> + bit_set::FiniteBitSetTy,
475+
{
476+
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
477+
self.0.hash_stable(hcx, hasher);
478+
}
479+
}
480+
472481
impl_stable_hash_via_hash!(::std::path::Path);
473482
impl_stable_hash_via_hash!(::std::path::PathBuf);
474483

src/librustc_index/bit_set.rs

+135
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::fmt;
44
use std::iter;
55
use std::marker::PhantomData;
66
use std::mem;
7+
use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
78
use std::slice;
89

910
#[cfg(test)]
@@ -1001,3 +1002,137 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
10011002
let mask = 1 << (elem % WORD_BITS);
10021003
(word_index, mask)
10031004
}
1005+
1006+
/// Integral type used to represent the bit set.
1007+
pub trait FiniteBitSetTy:
1008+
BitAnd<Output = Self>
1009+
+ BitAndAssign
1010+
+ BitOrAssign
1011+
+ Clone
1012+
+ Copy
1013+
+ Shl
1014+
+ Not<Output = Self>
1015+
+ PartialEq
1016+
+ Sized
1017+
{
1018+
/// Size of the domain representable by this type, e.g. 64 for `u64`.
1019+
const DOMAIN_SIZE: u32;
1020+
1021+
/// Value which represents the `FiniteBitSet` having every bit set.
1022+
const FILLED: Self;
1023+
/// Value which represents the `FiniteBitSet` having no bits set.
1024+
const EMPTY: Self;
1025+
1026+
/// Value for one as the integral type.
1027+
const ONE: Self;
1028+
/// Value for zero as the integral type.
1029+
const ZERO: Self;
1030+
1031+
/// Perform a checked left shift on the integral type.
1032+
fn checked_shl(self, rhs: u32) -> Option<Self>;
1033+
/// Perform a checked right shift on the integral type.
1034+
fn checked_shr(self, rhs: u32) -> Option<Self>;
1035+
}
1036+
1037+
impl FiniteBitSetTy for u64 {
1038+
const DOMAIN_SIZE: u32 = 64;
1039+
1040+
const FILLED: Self = Self::MAX;
1041+
const EMPTY: Self = Self::MIN;
1042+
1043+
const ONE: Self = 1u64;
1044+
const ZERO: Self = 0u64;
1045+
1046+
fn checked_shl(self, rhs: u32) -> Option<Self> {
1047+
self.checked_shl(rhs)
1048+
}
1049+
1050+
fn checked_shr(self, rhs: u32) -> Option<Self> {
1051+
self.checked_shr(rhs)
1052+
}
1053+
}
1054+
1055+
impl std::fmt::Debug for FiniteBitSet<u64> {
1056+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1057+
write!(f, "{:064b}", self.0)
1058+
}
1059+
}
1060+
1061+
impl FiniteBitSetTy for u128 {
1062+
const DOMAIN_SIZE: u32 = 128;
1063+
1064+
const FILLED: Self = Self::MAX;
1065+
const EMPTY: Self = Self::MIN;
1066+
1067+
const ONE: Self = 1u128;
1068+
const ZERO: Self = 0u128;
1069+
1070+
fn checked_shl(self, rhs: u32) -> Option<Self> {
1071+
self.checked_shl(rhs)
1072+
}
1073+
1074+
fn checked_shr(self, rhs: u32) -> Option<Self> {
1075+
self.checked_shr(rhs)
1076+
}
1077+
}
1078+
1079+
impl std::fmt::Debug for FiniteBitSet<u128> {
1080+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1081+
write!(f, "{:0128b}", self.0)
1082+
}
1083+
}
1084+
1085+
/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
1086+
/// representable by `T` are considered set.
1087+
#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
1088+
pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
1089+
1090+
impl<T: FiniteBitSetTy> FiniteBitSet<T> {
1091+
/// Creates a new, empty bitset.
1092+
pub fn new_empty() -> Self {
1093+
Self(T::EMPTY)
1094+
}
1095+
1096+
/// Sets the `index`th bit.
1097+
pub fn set(&mut self, index: u32) {
1098+
self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO);
1099+
}
1100+
1101+
/// Unsets the `index`th bit.
1102+
pub fn clear(&mut self, index: u32) {
1103+
self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO);
1104+
}
1105+
1106+
/// Sets the `i`th to `j`th bits.
1107+
pub fn set_range(&mut self, range: Range<u32>) {
1108+
let bits = T::FILLED
1109+
.checked_shl(range.end - range.start)
1110+
.unwrap_or(T::ZERO)
1111+
.not()
1112+
.checked_shl(range.start)
1113+
.unwrap_or(T::ZERO);
1114+
self.0 |= bits;
1115+
}
1116+
1117+
/// Is the set empty?
1118+
pub fn is_empty(&self) -> bool {
1119+
self.0 == T::EMPTY
1120+
}
1121+
1122+
/// Returns the domain size of the bitset.
1123+
pub fn within_domain(&self, index: u32) -> bool {
1124+
index < T::DOMAIN_SIZE
1125+
}
1126+
1127+
/// Returns if the `index`th bit is set.
1128+
pub fn contains(&self, index: u32) -> Option<bool> {
1129+
self.within_domain(index)
1130+
.then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
1131+
}
1132+
}
1133+
1134+
impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
1135+
fn default() -> Self {
1136+
Self::new_empty()
1137+
}
1138+
}

src/librustc_index/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(allow_internal_unstable)]
2+
#![feature(bool_to_option)]
23
#![feature(const_fn)]
34
#![feature(const_panic)]
45
#![feature(extend_one)]

src/librustc_metadata/rmeta/decoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11321132
.decode((self, tcx))
11331133
}
11341134

1135-
fn get_unused_generic_params(&self, id: DefIndex) -> u64 {
1135+
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> {
11361136
self.root
11371137
.tables
11381138
.unused_generic_params

src/librustc_metadata/rmeta/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir as hir;
99
use rustc_hir::def::CtorKind;
1010
use rustc_hir::def_id::{DefId, DefIndex};
1111
use rustc_hir::lang_items;
12-
use rustc_index::vec::IndexVec;
12+
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
1313
use rustc_middle::hir::exports::Export;
1414
use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib};
1515
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
@@ -277,7 +277,7 @@ define_tables! {
277277
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
278278
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
279279
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
280-
unused_generic_params: Table<DefIndex, Lazy<u64>>,
280+
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>,
281281
}
282282

283283
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]

src/librustc_middle/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,7 @@ rustc_queries! {
13091309
query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
13101310
desc { "codegen_unit" }
13111311
}
1312-
query unused_generic_params(key: DefId) -> u64 {
1312+
query unused_generic_params(key: DefId) -> FiniteBitSet<u64> {
13131313
cache_on_disk_if { key.is_local() }
13141314
desc {
13151315
|tcx| "determining which generic parameters are unused by `{}`",

src/librustc_middle/ty/instance.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -474,20 +474,20 @@ impl<'tcx> Instance<'tcx> {
474474
}
475475

476476
if let InstanceDef::Item(def) = self.def {
477-
let results = tcx.unused_generic_params(def.did);
477+
let unused = tcx.unused_generic_params(def.did);
478478

479-
if results == 0 {
479+
if unused.is_empty() {
480480
// Exit early if every parameter was used.
481481
return self;
482482
}
483483

484-
debug!("polymorphize: results={:064b}", results);
484+
debug!("polymorphize: unused={:?}", unused);
485485
let polymorphized_substs =
486486
InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
487487
// If parameter is a const or type parameter..
488488
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
489489
// ..and is within range and unused..
490-
param.index < 64 && ((results >> param.index) & 1) == 1 =>
490+
unused.contains(param.index).unwrap_or(false) =>
491491
// ..then use the identity for this parameter.
492492
tcx.mk_param_from_def(param),
493493
// Otherwise, use the parameter as before.

src/librustc_middle/ty/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use rustc_hir::def::DefKind;
4444
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
4545
use rustc_hir::lang_items::{LangItem, LanguageItems};
4646
use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
47-
use rustc_index::vec::IndexVec;
47+
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
4848
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
4949
use rustc_session::utils::NativeLibKind;
5050
use rustc_session::CrateDisambiguator;

0 commit comments

Comments
 (0)