Skip to content

Commit b69724f

Browse files
committed
Optimize layout calculations in HashMap
This now produces the same assembly code as the previous implementation.
1 parent 6232478 commit b69724f

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

src/libstd/collections/hash/table.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use mem::{size_of, needs_drop};
1515
use mem;
1616
use ops::{Deref, DerefMut};
1717
use ptr::{self, Unique, NonNull};
18+
use hint;
1819

1920
use self::BucketState::*;
2021

@@ -655,7 +656,17 @@ impl<K, V, M> GapThenFull<K, V, M>
655656
fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
656657
let hashes = Layout::array::<HashUint>(capacity)?;
657658
let pairs = Layout::array::<(K, V)>(capacity)?;
658-
hashes.extend(pairs)
659+
hashes.extend(pairs).map(|(layout, _)| {
660+
// LLVM seems to have trouble properly const-propagating pairs.align(),
661+
// possibly due to the use of NonZeroUsize. This little hack allows it
662+
// to generate optimal code.
663+
//
664+
// See https://github.com/rust-lang/rust/issues/51346 for more details.
665+
(
666+
layout,
667+
hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()),
668+
)
669+
})
659670
}
660671

661672
pub(crate) enum Fallibility {
@@ -711,7 +722,8 @@ impl<K, V> RawTable<K, V> {
711722
}
712723

713724
fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
714-
let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity()).unwrap();
725+
let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity())
726+
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
715727
let buffer = self.hashes.ptr() as *mut u8;
716728
unsafe {
717729
RawBucket {
@@ -1109,7 +1121,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
11091121
}
11101122
}
11111123

1112-
let (layout, _) = calculate_layout::<K, V>(self.capacity()).unwrap();
1124+
let (layout, _) = calculate_layout::<K, V>(self.capacity())
1125+
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
11131126
unsafe {
11141127
Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
11151128
// Remember how everything was allocated out of one buffer

0 commit comments

Comments
 (0)