]> git.lizzy.rs Git - rust.git/commitdiff
Use bit operations for setting large ranges of bits in a u64
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Wed, 20 Feb 2019 14:07:25 +0000 (15:07 +0100)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Mon, 4 Mar 2019 16:10:02 +0000 (17:10 +0100)
src/librustc/mir/interpret/allocation.rs
src/librustc_mir/interpret/memory.rs
src/test/run-pass-fulldeps/undef_mask.rs

index 18880c551ed55ff8f72baa53eed112c39dd586d4..004804f7c211e043aec3588876d390bed6b6fec0 100644 (file)
@@ -100,8 +100,7 @@ fn memory_allocated(
 impl<Tag, Extra> Allocation<Tag, Extra> {
     /// Creates a read-only allocation initialized by the given bytes
     pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
-        let mut undef_mask = UndefMask::new(Size::ZERO);
-        undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
+        let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
         Self {
             bytes: slice.to_owned(),
             relocations: Relocations::new(),
@@ -121,7 +120,7 @@ pub fn undef(size: Size, align: Align, extra: Extra) -> Self {
         Allocation {
             bytes: vec![0; size.bytes() as usize],
             relocations: Relocations::new(),
-            undef_mask: UndefMask::new(size),
+            undef_mask: UndefMask::new(size, false),
             align,
             mutability: Mutability::Mutable,
             extra,
@@ -625,12 +624,12 @@ pub struct UndefMask {
 impl UndefMask {
     pub const BLOCK_SIZE: u64 = 64;
 
-    pub fn new(size: Size) -> Self {
+    pub fn new(size: Size, state: bool) -> Self {
         let mut m = UndefMask {
             blocks: vec![],
             len: Size::ZERO,
         };
-        m.grow(size, false);
+        m.grow(size, state);
         m
     }
 
@@ -667,25 +666,40 @@ pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
         let (blocka, bita) = bit_index(start);
         let (blockb, bitb) = bit_index(end);
         if blocka == blockb {
-            // within a single block
-            for i in bita .. bitb {
-                self.set_bit(blocka, i, new_state);
+            // first set all bits but the first `bita`
+            // then unset the last `64 - bitb` bits
+            let range = if bitb == 0 {
+                u64::max_value() << bita
+            } else {
+                (u64::max_value() << bita) & (u64::max_value() >> (64 - bitb))
+            };
+            if new_state {
+                self.blocks[blocka] |= range;
+            } else {
+                self.blocks[blocka] &= !range;
             }
             return;
         }
         // across block boundaries
-        for i in bita .. Self::BLOCK_SIZE as usize {
-            self.set_bit(blocka, i, new_state);
-        }
-        for i in 0 .. bitb {
-            self.set_bit(blockb, i, new_state);
-        }
-        // fill in all the other blocks (much faster than one bit at a time)
         if new_state {
+            // set bita..64 to 1
+            self.blocks[blocka] |= u64::max_value() << bita;
+            // set 0..bitb to 1
+            if bitb != 0 {
+                self.blocks[blockb] |= u64::max_value() >> (64 - bitb);
+            }
+            // fill in all the other blocks (much faster than one bit at a time)
             for block in (blocka + 1) .. blockb {
                 self.blocks[block] = u64::max_value();
             }
         } else {
+            // set bita..64 to 0
+            self.blocks[blocka] &= !(u64::max_value() << bita);
+            // set 0..bitb to 0
+            if bitb != 0 {
+                self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb));
+            }
+            // fill in all the other blocks (much faster than one bit at a time)
             for block in (blocka + 1) .. blockb {
                 self.blocks[block] = 0;
             }
@@ -695,7 +709,7 @@ pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
     #[inline]
     pub fn get(&self, i: Size) -> bool {
         let (block, bit) = bit_index(i);
-        (self.blocks[block] & 1 << bit) != 0
+        (self.blocks[block] & (1 << bit)) != 0
     }
 
     #[inline]
@@ -714,6 +728,9 @@ fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) {
     }
 
     pub fn grow(&mut self, amount: Size, new_state: bool) {
+        if amount.bytes() == 0 {
+            return;
+        }
         let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
         if amount.bytes() > unused_trailing_bits {
             let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
index 6cbb611c1a3ec461c97b63d7add8775a12bce811..fba0a9af21392c6205bdb0bb12305951f0e1a6ec 100644 (file)
@@ -815,7 +815,7 @@ fn copy_undef_mask(
         // an optimization where we can just overwrite an entire range of definedness bits if
         // they are going to be uniformly `1` or `0`.
         if ranges.is_empty() {
-            dest_allocation.undef_mask.set_range(
+            dest_allocation.undef_mask.set_range_inbounds(
                 dest.offset,
                 dest.offset + size * repeat,
                 first,
index 37c44e2df6c5ecb9653beb699f175081c62b744b..cf6e6f72316384812aa6ed749f7e6d1b66bd751f 100644 (file)
@@ -9,7 +9,7 @@
 use rustc::ty::layout::Size;
 
 fn main() {
-    let mut mask = UndefMask::new(Size::from_bytes(500));
+    let mut mask = UndefMask::new(Size::from_bytes(500), false);
     assert!(!mask.get(Size::from_bytes(499)));
     mask.set(Size::from_bytes(499), true);
     assert!(mask.get(Size::from_bytes(499)));