-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Pre-RFC: Unchecked arithmetic #2508
Comments
I don’t know how much context you reviewed when discussing this matter, but it would be a good thing for any RFC here to start by reviewing the text of RFC 560, PR: #560 and the discussion thread linked on its PR, and perhaps the other discussions that preceded it |
Thank you for the pointers! I must say I didn't read in detail all the discussions, but looking at everything that mentions “unsafe” (assuming this would lead to the messages relevant for the current discussion, given I can't imagine such primitives not being “unsafe” and noone mentioning it) and reading about half the other posts to try not to miss any extended discussion, I think that:
Overall, I think the possibility of having However, these discussions do me feel better about the That said, reading these discussions also makes me wonder which should be the behaviour for preconditions not matched in
Undefined behaviour is much more violent, and not required for LLVM's Overall, given these functions would be defined as BTW, I've edited the topmost post according to feedback received over IRC, basically removing the parts about a |
Was let (result, overflowed) = a.overflowing_add(b);
if overflowed {
unsafe { unreachable_unchecked() }
} else {
result
} discussed or tried? |
Not yet, what has been tried is this: pub unsafe fn foo(a: u32, b: u32) -> u32 {
a.checked_add(b).unwrap_or(std::mem::uninitialized())
} and this pub unsafe fn foo(a: u32, b: u32) -> u32 {
if let Some(x) = a.checked_add(b) {
x
} else {
std::hint::unreachable_unchecked()
}
} Both of which fail to generate I can now confirm the same result with pub unsafe fn foo(a: u32, b: u32) -> u32 {
let (result, overflowed) = a.overflowing_add(b);
if overflowed {
std::hint::unreachable_unchecked();
} else {
result
}
} That said, the example you're giving does look like a reasonable “default cross-platform” implementation for BTW, rustc appears to generate most-likely optimal IR for the example using |
Why not AFAIK we can't currently generate the appropriate LLVM-IR in any way, so whether these could actually make a performance difference or not in some situations is basically just speculation unless one modifies rustc to try it out, and those who want to reproduce modify and recompile rustc themselves to do so. I think we could add these to Once we have more information we can reconsider adding the methods to the integers, the Worst case these will just hang in |
Indeed, it's all speculative for Rust, but in C, this StackOverflow question appears to state that integer arithmetic (ie. something similar to the Then, I agree with you that having intrinsics first would likely be first step. Let's wait for the follow-up of rust-lang/rust#52205 for the time being, then, and the result of the |
These intrinsics not being useful for |
@gnzlbg Because there's no obvious type for which to have the methods do that. My PR does |
I've written a note about this topic: |
add support for unchecked math add compiler support for ```rust /// Returns the result of an unchecked addition, resulting in /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`. pub fn unchecked_add<T>(x: T, y: T) -> T; /// Returns the result of an unchecked substraction, resulting in /// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`. pub fn unchecked_sub<T>(x: T, y: T) -> T; /// Returns the result of an unchecked multiplication, resulting in /// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`. pub fn unchecked_mul<T>(x: T, y: T) -> T; ``` cc rust-lang/rfcs#2508
The intrinsics for |
Also for |
any plans to migrate those to stable ? |
What about |
@A1-Triard There's no |
Still, I think, it is not a reason to not having |
@A1-Triard It's a reason not to have it as an intrinsic, which are the only things that exist right now. Whether there should be an Last I heard there was potential concern with stabilizing things here, so anyone wanting to see further movement will need to do some experimentation in nightly to prove the value of these in real code. |
From my perspective, the main use of this would be in code that is generated from tools like EverParse, which provide formal proofs that overflow indeed cannot occur. |
There is already If this doesn't optimize as well as Optimization can always be improved, but core API is forever. |
I think the API is pretty clear cut though. If we have Also people may not want to rely on optimizations occurring, and in e.g. a debug build I'm not sure they would. There is quite some overhead on creating an option and unwrapping it compared to a simple addition which can always be safely pessimized to any of the other |
Given that We don't need an RFC-repo issue for this. The remainder are rust-lang/rust#85122. (Not everything mentioned here literally exists, but for example |
On IRC, we recently discussed the speed of addition. I think Rust currently has no way to say “I know this cannot overflow, so just optimize and UB if it actually can”.
Hence the idea of adding
unchecked_add
, etc., that would beunsafe
functions. (addition of anUnchecked<u*>
type is left to later assessment)Specific list of functions that'd be available as
unchecked_*
is the same set of functions that are currently available aschecked_*
,overflowing_*
andwrapping_*
forms:unchecked_add
unchecked_sub
unchecked_mul
unchecked_div
unchecked_div_euc
unchecked_rem
unchecked_mod_euc
unchecked_neg
unchecked_shl
unchecked_shr
unchecked_pow
Is there any major roadblock/risks that you think I should be aware of before starting to write this RFC? Do you like this idea or not?
For the potential for improvement, even though it's hard to pinpoint the exact reason why, using signed arithmetic instead of unsigned arithmetic in C here made the code run 10% faster -- this is likely an equivalent gain we could have using
unchecked
variants instead ofoverflowing
(or equivalent) ones. :) (not even counting debug builds, where most of the huge gain could already be had by using eg.overflowing_*
, even though it wouldn't really be semantically correct)Note: this is the same idea as rust-lang/rust#52205 , except it'd be available to user code
The text was updated successfully, but these errors were encountered: