Skip to content

Commit 60fde17

Browse files
committed
Use bit operations for setting large ranges of bits in a u64
1 parent 4ded592 commit 60fde17

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

src/librustc/mir/interpret/allocation.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ impl AllocationExtra<(), ()> for () {
100100
impl<Tag, Extra> Allocation<Tag, Extra> {
101101
/// Creates a read-only allocation initialized by the given bytes
102102
pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
103-
let mut undef_mask = UndefMask::new(Size::ZERO);
104-
undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
103+
let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
105104
Self {
106105
bytes: slice.to_owned(),
107106
relocations: Relocations::new(),
@@ -121,7 +120,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
121120
Allocation {
122121
bytes: vec![0; size.bytes() as usize],
123122
relocations: Relocations::new(),
124-
undef_mask: UndefMask::new(size),
123+
undef_mask: UndefMask::new(size, false),
125124
align,
126125
mutability: Mutability::Mutable,
127126
extra,
@@ -625,12 +624,12 @@ impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
625624
impl UndefMask {
626625
pub const BLOCK_SIZE: u64 = 64;
627626

628-
pub fn new(size: Size) -> Self {
627+
pub fn new(size: Size, state: bool) -> Self {
629628
let mut m = UndefMask {
630629
blocks: vec![],
631630
len: Size::ZERO,
632631
};
633-
m.grow(size, false);
632+
m.grow(size, state);
634633
m
635634
}
636635

@@ -667,25 +666,40 @@ impl UndefMask {
667666
let (blocka, bita) = bit_index(start);
668667
let (blockb, bitb) = bit_index(end);
669668
if blocka == blockb {
670-
// within a single block
671-
for i in bita .. bitb {
672-
self.set_bit(blocka, i, new_state);
669+
// first set all bits but the first `bita`
670+
// then unset the last `64 - bitb` bits
671+
let range = if bitb == 0 {
672+
u64::max_value() << bita
673+
} else {
674+
(u64::max_value() << bita) & (u64::max_value() >> (64 - bitb))
675+
};
676+
if new_state {
677+
self.blocks[blocka] |= range;
678+
} else {
679+
self.blocks[blocka] &= !range;
673680
}
674681
return;
675682
}
676683
// across block boundaries
677-
for i in bita .. Self::BLOCK_SIZE as usize {
678-
self.set_bit(blocka, i, new_state);
679-
}
680-
for i in 0 .. bitb {
681-
self.set_bit(blockb, i, new_state);
682-
}
683-
// fill in all the other blocks (much faster than one bit at a time)
684684
if new_state {
685+
// set bita..64 to 1
686+
self.blocks[blocka] |= u64::max_value() << bita;
687+
// set 0..bitb to 1
688+
if bitb != 0 {
689+
self.blocks[blockb] |= u64::max_value() >> (64 - bitb);
690+
}
691+
// fill in all the other blocks (much faster than one bit at a time)
685692
for block in (blocka + 1) .. blockb {
686693
self.blocks[block] = u64::max_value();
687694
}
688695
} else {
696+
// set bita..64 to 0
697+
self.blocks[blocka] &= !(u64::max_value() << bita);
698+
// set 0..bitb to 0
699+
if bitb != 0 {
700+
self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb));
701+
}
702+
// fill in all the other blocks (much faster than one bit at a time)
689703
for block in (blocka + 1) .. blockb {
690704
self.blocks[block] = 0;
691705
}
@@ -695,7 +709,7 @@ impl UndefMask {
695709
#[inline]
696710
pub fn get(&self, i: Size) -> bool {
697711
let (block, bit) = bit_index(i);
698-
(self.blocks[block] & 1 << bit) != 0
712+
(self.blocks[block] & (1 << bit)) != 0
699713
}
700714

701715
#[inline]
@@ -714,6 +728,9 @@ impl UndefMask {
714728
}
715729

716730
pub fn grow(&mut self, amount: Size, new_state: bool) {
731+
if amount.bytes() == 0 {
732+
return;
733+
}
717734
let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
718735
if amount.bytes() > unused_trailing_bits {
719736
let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;

src/librustc_mir/interpret/memory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
815815
// an optimization where we can just overwrite an entire range of definedness bits if
816816
// they are going to be uniformly `1` or `0`.
817817
if ranges.is_empty() {
818-
dest_allocation.undef_mask.set_range(
818+
dest_allocation.undef_mask.set_range_inbounds(
819819
dest.offset,
820820
dest.offset + size * repeat,
821821
first,

src/test/run-pass-fulldeps/undef_mask.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc::mir::interpret::UndefMask;
99
use rustc::ty::layout::Size;
1010

1111
fn main() {
12-
let mut mask = UndefMask::new(Size::from_bytes(500));
12+
let mut mask = UndefMask::new(Size::from_bytes(500), false);
1313
assert!(!mask.get(Size::from_bytes(499)));
1414
mask.set(Size::from_bytes(499), true);
1515
assert!(mask.get(Size::from_bytes(499)));

0 commit comments

Comments
 (0)