Skip to content

Commit e1471cf

Browse files
committed
Introduce another way to compute the length, to fix position codegen regression
1 parent b0a82d9 commit e1471cf

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

src/libcore/slice/mod.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,22 @@ macro_rules! len {
23592359
}
23602360
}}
23612361
}
2362+
// To get rid of some bounds checks (see `position`), for some reason it
2363+
// makes a difference to compute the length in this way.
2364+
// (Tested by `codegen/slice-position-bounds-check`.)
2365+
macro_rules! len2 {
2366+
($self: ident) => {{
2367+
let start = $self.ptr;
2368+
let diff = ($self.end as usize).wrapping_sub(start as usize);
2369+
let size = size_from_ptr(start);
2370+
if size == 0 {
2371+
diff
2372+
} else {
2373+
// Using division instead of `offset_from` helps LLVM remove bounds checks
2374+
diff / size
2375+
}
2376+
}}
2377+
}
23622378

23632379
// The shared definition of the `Iter` and `IterMut` iterators
23642380
macro_rules! iterator {
@@ -2367,7 +2383,7 @@ macro_rules! iterator {
23672383
// Helper function for creating a slice from the iterator.
23682384
#[inline(always)]
23692385
fn make_slice(&self) -> &'a [T] {
2370-
unsafe { from_raw_parts(self.ptr, len!(self)) }
2386+
unsafe { from_raw_parts(self.ptr, len2!(self)) }
23712387
}
23722388

23732389
// Helper function for moving the start of the iterator forwards by `offset` elements,
@@ -2510,9 +2526,8 @@ macro_rules! iterator {
25102526
Self: Sized,
25112527
P: FnMut(Self::Item) -> bool,
25122528
{
2513-
// The addition might panic on overflow
2514-
// Use the len of the slice to hint optimizer to remove result index bounds check.
2515-
let n = self.make_slice().len();
2529+
// The addition might panic on overflow.
2530+
let n = len2!(self);
25162531
self.try_fold(0, move |i, x| {
25172532
if predicate(x) { Err(i) }
25182533
else { Ok(i + 1) }
@@ -2529,9 +2544,7 @@ macro_rules! iterator {
25292544
Self: Sized + ExactSizeIterator + DoubleEndedIterator
25302545
{
25312546
// No need for an overflow check here, because `ExactSizeIterator`
2532-
// implies that the number of elements fits into a `usize`.
2533-
// Use the len of the slice to hint optimizer to remove result index bounds check.
2534-
let n = self.make_slice().len();
2547+
let n = len2!(self);
25352548
self.try_rfold(n, move |i, x| {
25362549
let i = i - 1;
25372550
if predicate(x) { Err(i) }
@@ -2776,7 +2789,7 @@ impl<'a, T> IterMut<'a, T> {
27762789
/// ```
27772790
#[stable(feature = "iter_to_slice", since = "1.4.0")]
27782791
pub fn into_slice(self) -> &'a mut [T] {
2779-
unsafe { from_raw_parts_mut(self.ptr, len!(self)) }
2792+
unsafe { from_raw_parts_mut(self.ptr, len2!(self)) }
27802793
}
27812794
}
27822795

0 commit comments

Comments
 (0)