28928c750c
Eliminate bounds checking in slice::Windows This is how `<core::slice::Windows as Iterator>::next` looks right now: ```rust fn next(&mut self) -> Option<&'a [T]> { if self.size > self.v.len() { None } else { let ret = Some(&self.v[..self.size]); self.v = &self.v[1..]; ret } } ``` The line with `self.v = &self.v[1..];` relies on assumption that `self.v` is definitely not empty at this point. Else branch is taken when `self.size <= self.v.len()`, so `self.v` can be empty if `self.size` is zero. In practice, since `Windows` is never created directly but rather trough `[T]::windows` which panics when `size` is zero, `self.size` is never zero. However, the compiler doesn't know about this check, so it keeps the code which checks bounds and panics. Using `NonZeroUsize` lets the compiler know about this invariant and reliably eliminate bounds checking without `unsafe` on `-O2`. Here is assembly of `Windows<'a, u32>::next` before and after this change ([goldbolt](https://godbolt.org/z/xrefzx)): <details> <summary>Before</summary> ``` example::next: push rax mov rcx, qword ptr [rdi + 8] mov rdx, qword ptr [rdi + 16] cmp rdx, rcx jbe .LBB0_2 xor eax, eax pop rcx ret .LBB0_2: test rcx, rcx je .LBB0_5 mov rax, qword ptr [rdi] mov rsi, rax add rsi, 4 add rcx, -1 mov qword ptr [rdi], rsi mov qword ptr [rdi + 8], rcx pop rcx ret .LBB0_5: lea rdx, [rip + .L__unnamed_1] mov edi, 1 xor esi, esi call qword ptr [rip + core::slice::slice_index_order_fail@GOTPCREL] ud2 .L__unnamed_2: .ascii "./example.rs" .L__unnamed_1: .quad .L__unnamed_2 .asciz "\f\000\000\000\000\000\000\000\016\000\000\000\027\000\000" ``` </details> <details> <summary>After</summary> ``` example::next: mov rcx, qword ptr [rdi + 8] mov rdx, qword ptr [rdi + 16] cmp rdx, rcx jbe .LBB0_2 xor eax, eax ret .LBB0_2: mov rax, qword ptr [rdi] lea rsi, [rax + 4] add rcx, -1 mov qword ptr [rdi], rsi mov qword ptr [rdi + 8], rcx ret ``` </details> Note the lack of call to `core::slice::slice_index_order_fail` in second snippet. #### Possible reasons _not_ to merge this PR: * this changes the error message on panic in `[T]::windows`. However, AFAIK this messages are not covered by backwards compatibility policy. |
||
---|---|---|
.. | ||
alloc | ||
backtrace@4083a90168 | ||
core | ||
panic_abort | ||
panic_unwind | ||
proc_macro | ||
profiler_builtins | ||
rtstartup | ||
rustc-std-workspace-alloc | ||
rustc-std-workspace-core | ||
rustc-std-workspace-std | ||
std | ||
stdarch@3c3664355e | ||
term | ||
test | ||
unwind |