Skip to content

Commit 894236f

Browse files
committed
Avoid Layout::array() in raw_vec.rs.
A non-generic equivalent results in less LLVM IR and faster compilation.
1 parent 8244b1b commit 894236f

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

library/alloc/src/raw_vec.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
22
#![doc(hidden)]
33

4-
use core::alloc::{LayoutErr, MemoryBlock};
4+
use core::alloc::MemoryBlock;
55
use core::cmp;
66
use core::mem::{self, ManuallyDrop, MaybeUninit};
77
use core::ops::Drop;
@@ -172,7 +172,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
172172
} else {
173173
// We avoid `unwrap_or_else` here because it bloats the amount of
174174
// LLVM IR generated.
175-
let layout = match Layout::array::<T>(capacity) {
175+
let layout = match array_layout(Layout::new::<T>(), capacity) {
176176
Ok(layout) => layout,
177177
Err(_) => capacity_overflow(),
178178
};
@@ -423,10 +423,10 @@ impl<T, A: AllocRef> RawVec<T, A> {
423423
};
424424
let cap = cmp::max(min_non_zero_cap, cap);
425425

426-
let new_layout = Layout::array::<T>(cap);
426+
let elem_layout = Layout::new::<T>();
427427

428428
// `finish_grow` is non-generic over `T`.
429-
let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
429+
let memory = finish_grow(cap, elem_layout, self.current_memory(), &mut self.alloc)?;
430430
self.set_memory(memory);
431431
Ok(())
432432
}
@@ -442,10 +442,11 @@ impl<T, A: AllocRef> RawVec<T, A> {
442442
}
443443

444444
let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
445-
let new_layout = Layout::array::<T>(cap);
445+
446+
let elem_layout = Layout::new::<T>();
446447

447448
// `finish_grow` is non-generic over `T`.
448-
let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
449+
let memory = finish_grow(cap, elem_layout, self.current_memory(), &mut self.alloc)?;
449450
self.set_memory(memory);
450451
Ok(())
451452
}
@@ -478,15 +479,16 @@ impl<T, A: AllocRef> RawVec<T, A> {
478479
// significant, because the number of different `A` types seen in practice is
479480
// much smaller than the number of `T` types.)
480481
fn finish_grow<A>(
481-
new_layout: Result<Layout, LayoutErr>,
482+
cap: usize,
483+
elem_layout: Layout,
482484
current_memory: Option<(NonNull<u8>, Layout)>,
483485
alloc: &mut A,
484486
) -> Result<MemoryBlock, TryReserveError>
485487
where
486488
A: AllocRef,
487489
{
488490
// Check for the error here to minimize the size of `RawVec::grow_*`.
489-
let new_layout = new_layout.map_err(|_| CapacityOverflow)?;
491+
let new_layout = array_layout(elem_layout, cap)?;
490492

491493
alloc_guard(new_layout.size())?;
492494

@@ -501,6 +503,15 @@ where
501503
Ok(memory)
502504
}
503505

506+
// This is equivalent to Layout::array, but is non-generic and has a different
507+
// error type in its result. It helps reduce the amount of LLVM IR generated.
508+
#[inline]
509+
fn array_layout(elem_layout: Layout, n: usize) -> Result<Layout, TryReserveError> {
510+
let (new_layout, offset) = elem_layout.repeat(n).map_err(|_| CapacityOverflow)?;
511+
debug_assert_eq!(offset, elem_layout.size());
512+
Ok(new_layout.pad_to_align())
513+
}
514+
504515
unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> {
505516
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
506517
fn drop(&mut self) {

0 commit comments

Comments
 (0)