diff options
| author | Ralf Jung <post@ralfj.de> | 2018-07-29 23:52:36 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2018-08-02 00:33:04 +0200 |
| commit | e1471cf41f6b88f6ddc91278f5a0a975a27b3de0 (patch) | |
| tree | f8b717bbd84a55fd403b0f4a2753d5e126e2fc39 | |
| parent | b0a82d9314083cad0c985c8f5f752749c9ae96ca (diff) | |
| download | rust-e1471cf41f6b88f6ddc91278f5a0a975a27b3de0.tar.gz rust-e1471cf41f6b88f6ddc91278f5a0a975a27b3de0.zip | |
Introduce another way to compute the length, to fix position codegen regression
| -rw-r--r-- | src/libcore/slice/mod.rs | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a807e92a2a8..32d1eafae7d 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2359,6 +2359,22 @@ macro_rules! len { } }} } +// To get rid of some bounds checks (see `position`), for some reason it +// makes a difference to compute the length in this way. +// (Tested by `codegen/slice-position-bounds-check`.) +macro_rules! len2 { + ($self: ident) => {{ + let start = $self.ptr; + let diff = ($self.end as usize).wrapping_sub(start as usize); + let size = size_from_ptr(start); + if size == 0 { + diff + } else { + // Using division instead of `offset_from` helps LLVM remove bounds checks + diff / size + } + }} +} // The shared definition of the `Iter` and `IterMut` iterators macro_rules! iterator { @@ -2367,7 +2383,7 @@ macro_rules! iterator { // Helper function for creating a slice from the iterator. #[inline(always)] fn make_slice(&self) -> &'a [T] { - unsafe { from_raw_parts(self.ptr, len!(self)) } + unsafe { from_raw_parts(self.ptr, len2!(self)) } } // Helper function for moving the start of the iterator forwards by `offset` elements, @@ -2510,9 +2526,8 @@ macro_rules! iterator { Self: Sized, P: FnMut(Self::Item) -> bool, { - // The addition might panic on overflow - // Use the len of the slice to hint optimizer to remove result index bounds check. - let n = self.make_slice().len(); + // The addition might panic on overflow. + let n = len2!(self); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } @@ -2529,9 +2544,7 @@ macro_rules! iterator { Self: Sized + ExactSizeIterator + DoubleEndedIterator { // No need for an overflow check here, because `ExactSizeIterator` - // implies that the number of elements fits into a `usize`. - // Use the len of the slice to hint optimizer to remove result index bounds check. - let n = self.make_slice().len(); + let n = len2!(self); self.try_rfold(n, move |i, x| { let i = i - 1; if predicate(x) { Err(i) } @@ -2776,7 +2789,7 @@ impl<'a, T> IterMut<'a, T> { /// ``` #[stable(feature = "iter_to_slice", since = "1.4.0")] pub fn into_slice(self) -> &'a mut [T] { - unsafe { from_raw_parts_mut(self.ptr, len!(self)) } + unsafe { from_raw_parts_mut(self.ptr, len2!(self)) } } } |
