]> git.lizzy.rs Git - rust.git/commitdiff
Optimize layout calculations in HashMap
authorAmanieu d'Antras <amanieu@gmail.com>
Mon, 4 Jun 2018 08:22:07 +0000 (09:22 +0100)
committerAmanieu d'Antras <amanieu@gmail.com>
Mon, 4 Jun 2018 15:00:08 +0000 (16:00 +0100)
This now produces the same assembly code as the previous implementation.

src/libstd/collections/hash/table.rs

index c62a409ac02c9a635faa827fb5899fd8ba87f5bf..d997fb28d4286595d5c313b669e9dbfbc7582827 100644 (file)
@@ -15,6 +15,7 @@
 use mem;
 use ops::{Deref, DerefMut};
 use ptr::{self, Unique, NonNull};
+use hint;
 
 use self::BucketState::*;
 
@@ -655,7 +656,17 @@ pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
 fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
     let hashes = Layout::array::<HashUint>(capacity)?;
     let pairs = Layout::array::<(K, V)>(capacity)?;
-    hashes.extend(pairs)
+    hashes.extend(pairs).map(|(layout, _)| {
+        // LLVM seems to have trouble properly const-propagating pairs.align(),
+        // possibly due to the use of NonZeroUsize. This little hack allows it
+        // to generate optimal code.
+        //
+        // See https://github.com/rust-lang/rust/issues/51346 for more details.
+        (
+            layout,
+            hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()),
+        )
+    })
 }
 
 pub(crate) enum Fallibility {
@@ -711,7 +722,8 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
     }
 
     fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
-        let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity()).unwrap();
+        let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity())
+            .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
         let buffer = self.hashes.ptr() as *mut u8;
         unsafe {
             RawBucket {
@@ -1109,7 +1121,8 @@ fn drop(&mut self) {
             }
         }
 
-        let (layout, _) = calculate_layout::<K, V>(self.capacity()).unwrap();
+        let (layout, _) = calculate_layout::<K, V>(self.capacity())
+            .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
         unsafe {
             Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
             // Remember how everything was allocated out of one buffer