-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
slice::split_mut
does not elide bound checks in release mode
#86313
Comments
Nice catch.
Oh, I'm doing the same (but in regular std code). |
this is something I've been meaning to do for a _long_ time now, and after many failed attempts and false-starts, I've finally done it! if you inspect the asm output of `example_no_std`, you'll find that there is absolutely _zero_ panic handling machinery in the final binary! This has also resulted in a _substantial_ drop in binary size, as those bounds checks and panicking machinery were taking up a lot of space! removing panicking code ended up requiring 3 different approaches: 1. Rewriting array-indexing operations to use simpler indexing, which the compiler is able to optimize better. e.g: see the code used to index into the `target.xml` buffer in `base.rs` 2. Adding a sprinkle of unsafe code to certain array-indexing operations that the compiler is unsable to prove are safe. This was only done in two places: `decode_hex_buf` and `PacketBuf`. 3. Manually re-implementing the standard library's `slice::split_mut` and `slice::splitn_mut` methods to elide a bounds check. - Tracked upstream via rust-lang/rust#86313 Introducing unsafe code isn't something I take lightly, and while I've done my best to audit and validate the unsafe code I've written, I did end up including an optional `paranoid_unsafe` feature which gives end-users the option to opt-out of `gdbstub`'s no-panic guarantee in exchange for some additional peace of mind.
@rustbot label +A-codegen +A-slice +T-libs +T-compiler |
@rustbot claim |
Awesome, thanks for looking into this @saethlin! |
Rearrange slice::split_mut to remove bounds check Closes rust-lang/rust#86313 Turns out that all we need to do here is reorder the bounds checks to convince LLVM that all the bounds checks can be removed. It seems like LLVM just fails to propagate the original length information past the first bounds check and into the second one. With this implementation it doesn't need to, each check can be proven inbounds based on the one immediately previous. I've gradually convinced myself that this implementation is unambiguously better based on the above logic, but maybe this is still deserving of a codegen test? Also the mentioned borrowck limitation no longer seems to exist.
As part of an ongoing effort to eliminate all panics from one of my
no_std
projects, I discovered thatslice::split_mut
does not elide bounds checks in release mode, whereasslice::split
does.This issue also affects
slice::splitn_mut
.The following examples illustrate this issue:
The generated asm for
split
elides all bounds checks:Unfortunately, the bounds check is reintroduced when
split_mut
is used instead:It seems that the following code in the
SplitMut
iterator is responsible for introducing the bounds check (specifically the array index on line 640):rust/library/core/src/slice/iter.rs
Lines 630 to 643 in 673d0db
Meta
rustc --version --verbose
:Also tested on
1.55.0-nightly (2021-06-13 f586d79d183d144e0cbf)
from the Rust playground.The text was updated successfully, but these errors were encountered: