|
25 | 25 | use crate::cmp::Ordering::{self, Less, Equal, Greater}; |
26 | 26 | use crate::cmp; |
27 | 27 | use crate::fmt; |
28 | | -use crate::intrinsics::assume; |
| 28 | +use crate::intrinsics::{assume, exact_div, unchecked_sub}; |
29 | 29 | use crate::isize; |
30 | 30 | use crate::iter::*; |
31 | 31 | use crate::ops::{FnMut, Try, self}; |
@@ -2998,14 +2998,27 @@ macro_rules! is_empty { |
2998 | 2998 | // unexpected way. (Tested by `codegen/slice-position-bounds-check`.) |
2999 | 2999 | macro_rules! len { |
3000 | 3000 | ($self: ident) => {{ |
| 3001 | + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block |
| 3002 | + |
3001 | 3003 | let start = $self.ptr; |
3002 | | - let diff = ($self.end as usize).wrapping_sub(start as usize); |
3003 | 3004 | let size = size_from_ptr(start); |
3004 | 3005 | if size == 0 { |
| 3006 | + // This _cannot_ use `unchecked_sub` because we depend on wrapping |
| 3007 | + // to represent the length of long ZST slice iterators. |
| 3008 | + let diff = ($self.end as usize).wrapping_sub(start as usize); |
3005 | 3009 | diff |
3006 | 3010 | } else { |
3007 | | - // Using division instead of `offset_from` helps LLVM remove bounds checks |
3008 | | - diff / size |
| 3011 | + // We know that `start <= end`, so can do better than `offset_from`, |
| 3012 | + // which needs to deal in signed. By setting appropriate flags here |
| 3013 | + // we can tell LLVM this, which helps it remove bounds checks. |
| 3014 | + // SAFETY: By the type invariant, `start <= end` |
| 3015 | + let diff = unsafe { unchecked_sub($self.end as usize, start as usize) }; |
| 3016 | + // By also telling LLVM that the pointers are apart by an exact |
| 3017 | + // multiple of the type size, it can optimize `len() == 0` down to |
| 3018 | + // `start == end` instead of `(end - start) < size`. |
| 3019 | + // SAFETY: By the type invariant, the pointers are aligned so the |
| 3020 | + // distance between them must be a multiple of pointee size |
| 3021 | + unsafe { exact_div(diff, size) } |
3009 | 3022 | } |
3010 | 3023 | }} |
3011 | 3024 | } |
|
0 commit comments