Uh oh!
There was an error while loading. Please reload this page.
Eliminate bounds checking in slice::Windows - #77617
Conversation
rust-highfive
commented
Oct 6, 2020
(rust_highfive has picked a reviewer for you, use r? to override) |
Would you mind adding a codegen test which checks that |
I expect that you need something like this: https://github.com/bugadani/rust/blob/1d157ce797dddcee16a577796199b1144b4f7f34/src/test/codegen/enum-bounds-check-issue-13926.rs (potentially without min-llvm-version, depending on how stable this optimization is) |
AnthonyMikh
commented
Oct 6, 2020
@lcnr I can add it. However, I see no way to run codegen check. How can I do it? |
lcnr
commented
Oct 6, 2020
|
AnthonyMikh
commented
Oct 6, 2020
@lcnr I've added test but I am not sure if it is correct. Or should I test |
lcnr
commented
Oct 6, 2020
seems good to me. Does this test fail without your changes? |
AnthonyMikh
commented
Oct 6, 2020
It... Passes without my changes. Apparently I don't know how to write codegen tests |
lcnr
commented
Oct 6, 2020
Looks like you need |
0f52d1b to
b5096c1CompareAnthonyMikh
commented
Oct 6, 2020
@lcnr without my changes this codegen test fails on |
AnthonyMikh
commented
Oct 6, 2020
BTW I only now realised that my rather mechanical changes in other methods seem also to eliminate bounds check in |
b5096c1 to
a8f098bComparelcnr
commented
Oct 6, 2020
hmm, it probably won't hurt to use explicitly extend the test to also add functions for these methods 🤷 feel free to do so r? @lcnr |
a8f098b to
61fca88CompareAnthonyMikh
commented
Oct 7, 2020
@lcnr I've added codegen tests for |
lcnr
commented
Oct 7, 2020
Looking at the emitted code on https://godbolt.org/z/T716cx It looks to me like In general this looks to me like these tests might not be as useful as I thought, considering that method renames make them somewhat useless. Does it work to instead test with the following? // CHECK-NOT: panic// CHECK-NOT: fail |
61fca88 to
e699e83CompareAnthonyMikh
commented
Oct 7, 2020
Indeed, it correctly checks with |
lcnr
commented
Oct 7, 2020
@bors r+ |
bors
commented
Oct 7, 2020
📌 Commit e699e83 has been approved by |
| #[inline] | ||
| pub fn windows(&self, size: usize) -> Windows<'_, T> { | ||
| assert_ne!(size, 0); | ||
| let size = NonZeroUsize::new(size).expect("size is zero"); |
There was a problem hiding this comment.
Do we have guideline about what the phrase used in expect call ?
| let size = NonZeroUsize::new(size).expect("size is zero"); | |
| let size = NonZeroUsize::new(size).expect("`size` cannot be zero"); |
There was a problem hiding this comment.
I am not sure, but before my change panic message was assertion failed: size != 0.
There was a problem hiding this comment.
this is bike-shredding so don't worry much about this.
BTW while inspecting the assembly on order to determine which changed methods benefit from my changes I checked // impl DoubleEndedIteator ...pubfnnth_back(&mutself,n:usize) -> Option<&'a[T]>{let(end, overflow) = self.v.len().overflowing_sub(n);if end < self.size.get() || overflow {self.v = &[];None}else{let ret = &self.v[end - self.size.get()..end];self.v = &self.v[..end - 1];Some(ret)}}Here else branch is taken when both conditions in The compiler understands that |
scottmcm
commented
Oct 7, 2020
TBH I was surprised that |
bors
commented
Oct 7, 2020
bors
commented
Oct 7, 2020
☀️ Test successful - checks-actions, checks-azure |
This is how
<core::slice::Windows as Iterator>::nextlooks right now:The line with
self.v = &self.v[1..];relies on assumption thatself.vis definitely not empty at this point. Else branch is taken whenself.size <= self.v.len(), soself.vcan be empty ifself.sizeis zero. In practice, sinceWindowsis never created directly but rather trough[T]::windowswhich panics whensizeis zero,self.sizeis never zero. However, the compiler doesn't know about this check, so it keeps the code which checks bounds and panics.Using
NonZeroUsizelets the compiler know about this invariant and reliably eliminate bounds checking withoutunsafeon-O2. Here is assembly ofWindows<'a, u32>::nextbefore and after this change (goldbolt):Before
After
Note the lack of call to
core::slice::slice_index_order_failin second snippet.Possible reasons not to merge this PR:
[T]::windows. However, AFAIK this messages are not covered by backwards compatibility policy.