-
Notifications
You must be signed in to change notification settings - Fork 19
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
Add get_unchecked
to Option
and Result
#378
Comments
this is just a duplicate of unwrap_unchecked, there's no value in having both |
[Experiment] Replace `unreachable_unchecked()` with `uninit().assume_init()` in `unwrap_unchecked()` [Relevant ACP.](rust-lang/libs-team#378) [Relevant godbolt.](https://godbolt.org/z/WqfcT7Ys9) Attempt to clean up the LLVM IR we generate based on the assumption that we usually don't want to `assume` the value of the discriminant (because it sticks around in the IR and randomly inhibits optimizations).
The documentation for
So we do not promise the implementation of |
You'll get the same optimized ASM using safe functions alone #[no_mangle]
fn sum_map_or(a: &[Option<NZ>; 16]) -> U {
a.iter().map(|&v| v.map_or(0, NZ::get)).sum()
} This works because |
[Experiment] Replace `unreachable_unchecked()` with `uninit().assume_init()` in `unwrap_unchecked()` [Relevant ACP.](rust-lang/libs-team#378) [Relevant godbolt.](https://godbolt.org/z/WqfcT7Ys9) Attempt to clean up the LLVM IR we generate based on the assumption that we usually don't want to `assume` the value of the discriminant (because it sticks around in the IR and randomly inhibits optimizations).
[Experiment] Replace `unreachable_unchecked()` with `uninit().assume_init()` in `unwrap_unchecked()` [Relevant ACP.](rust-lang/libs-team#378) [Relevant godbolt.](https://godbolt.org/z/WqfcT7Ys9) Attempt to clean up the LLVM IR we generate based on the assumption that we usually don't want to `assume` the value of the discriminant (because it sticks around in the IR and randomly inhibits optimizations).
Have you filed an LLVM bug? Seems worth seeing what they say, even if it's just "yes, this is why assume operand bundles are better than assume calls with values".
Most of which is the As Nils said, the proposed method is just That said, I do think there's a place for something here. Then you wouldn't need unsafe code for this at all, since pub fn sum_unwrap(a: &[Option<NZ>; 16]) -> U {
a.iter().map(|&v| v.unwrap_or_zero()).sum()
} would give exactly (https://godbolt.org/z/e5axT9bK8) what you wanted. |
That's just |
No, as in @kennytm 's snippit above it's So yes, there's a safe way, but it's a less-direct way. I like it when we have a clear "this is just the transmute you're about to write in unsafe code" method for things where the transmute would be safe given stable guarantees, because it's easy to link from next to the documentation of the layout guarantee and avoids all the "oh, I didn't think of that" or "but that's so much slower in debug mode" or whatever objections. |
Thank you for the ACP, discussion, godbolt links, and draft PRs for benchmarking! We discussed this ACP in this week's standard library API team meeting. Those present were not convinced that having 2 unsafe But instead we are open to whatever improvements can be made to LLVM, rustc, or the standard library to make the existing We didn't get a chance to evaluate |
Proposal
Problem statement
Prompted by this comment:
I began searching for concrete examples of situations where using
unwrap_unchecked
leads to bad codegen. I didn't have to search long.The problem with
unwrap_unchecked
is that it's the programming equivalent of littering - with every unwrap we're sprinkling in a condition for LLVM to keep around, even though frequently what we really mean is "I know this isSome
/Ok
/Err
, please give me the contents without checking the variant." In a perfect world, these conditions would just get ignored when irrelevant and cleanly DCE'd, but...Motivating examples or use cases
godbolt
This innocuous snippet leads to staggeringly bad assembly - 80+ lines of LLVM IR and 30+ ARM instructions... to add together 16 numbers. For reference, a non-vectorized implementation would be 15 adds, 8 pair-loads, and a return. Autovectorized it's just 8 instructions.
Solution sketch
Maybe we should just stop littering.
We can restore good codegen if we express the unwrap in a different way, without invoking
unreachable_unchecked
; for example, like this:godbolt
Add the above method (and analogous methods on
Result
) tocore
.Alternatives
Change implementation of
unwrap_unchecked
Idly browsing through uses of
unwrap_unchecked
, I notice that a significant portion (perhaps even majority!) of them probably don't care to keep their conditions around. Worth investigating with benchmarks.Not convinced it's relevant, but clang does not generate an
assume
for anstd::optional
dereference. godboltAdditionally, the "unchecked" wording sort of implies a lack of checks, which is... well, ostensibly true...
Change current implementation and add new methods
Assuming
get_unchecked
is on average better thanunwrap_unchecked
, we might want to replace the functionality for current code and also keep providing the previous functionality for the cases where it is useful. Call itunwrap_assume
or something.Do nothing
This can be implemented in user code just fine, as an extension method. The problem is discoverability - if you're reaching for
unwrap_unchecked
, you probably care about performance, and withunwrap_unchecked
being the onlyunchecked
method onOption
/Result
you might not think to search further, or consider what the method does under the hood (and whether that's something you want to happen).Improve LLVM
Presumably a long-term effort. I don't have the necessary knowledge to properly consider this alternative.
The text was updated successfully, but these errors were encountered: