-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Use bitand when checking for signed integer division overflow #89459
Conversation
For `self == Self::MIN && rhs == -1`, LLVM does not realize that this is the same check made by `self / rhs`, so the code generated may have some unnecessary duplication. For `(self == Self::MIN) & (rhs == -1)`, LLVM realizes it is the same check.
r? @kennytm (rust-highfive has picked a reviewer for you, use r? to override) |
An example for Note that this PR does not affect |
I really think this is something that should be improved at the code generation level instead of doing this manually for every case like this because there are likely a lot more cases and doing so would be cleaner and could cover more cases IMO. |
@bors r+ rollup=never |
📌 Commit 1139ee3 has been approved by |
☀️ Test successful - checks-actions |
Finished benchmarking commit (4479cb8): comparison url. Summary: This benchmark run did not return any relevant changes. If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. @rustbot label: -perf-regression |
Replace some operators in libcore with their short-circuiting equivalents In libcore there are a few occurrences of bitwise operators used in boolean expressions instead of their short-circuiting equivalents. This makes it harder to perform some kinds of source code analysis over libcore, for example [MC/DC] code coverage (a requirement in safety-critical environments). This PR aims to remove as many bitwise operators in boolean expressions from libcore as possible, without any performance regression and without other changes. This means not all bitwise operators are removed, only the ones that don't have any difference with their short-circuiting counterparts. This already simplifies achieving MC/DC coverage, and the other functions can be changed in future PRs. The PR is best reviewed commit-by-commit, and each commit has the resulting assembly in the message. ## Checked integer methods These methods recently switched to bitwise operators in PRs rust-lang#89459 and rust-lang#89351. I confirmed bitwise operators are needed in most of the functions, except these two: * `{integer}::checked_div` ([Godbolt link (nightly)](https://rust.godbolt.org/z/17efh5jPc)) * `{integer}::checked_rem` ([Godbolt link (nightly)](https://rust.godbolt.org/z/85qGWc94K)) `@tspiteri` already mentioned this was the case in rust-lang#89459 (comment), but opted to also switch those two to bitwise operators for consistency. As that makes MC/DC analysis harder this PR proposes switching those two back to short-circuiting operators. ## `{unsigned_ints}::carrying_add` [Godbolt link (1.56.0)](https://rust.godbolt.org/z/vG9vx8x48) In this instance replacing the `|` with `||` produces the exact same assembly when optimizations are enabled, so switching to the short-circuiting operator shouldn't have any impact. ## `{unsigned_ints}::borrowing_sub` [Godbolt link (1.56.0)](https://rust.godbolt.org/z/asEfKaGE4) In this instance replacing the `|` with `||` produces the exact same assembly when optimizations are enabled, so switching to the short-circuiting operator shouldn't have any impact. ## String UTF-8 validation [Godbolt link (1.56.0)](https://rust.godbolt.org/z/a4rEbTvvx) In this instance replacing the `|` with `||` produces practically the same assembly, with the two operands for the "or" swapped: ```asm ; Old mov rax, qword ptr [rdi + rdx + 8] or rax, qword ptr [rdi + rdx] test rax, r9 je .LBB0_7 ; New mov rax, qword ptr [rdi + rdx] or rax, qword ptr [rdi + rdx + 8] test rax, r8 je .LBB0_7 ``` [MC/DC]: https://en.wikipedia.org/wiki/Modified_condition/decision_coverage
For
self == Self::MIN && rhs == -1
, LLVM does not realize that this is the same check made byself / rhs
, so the code generated may have some unnecessary duplication. For(self == Self::MIN) & (rhs == -1)
, LLVM realizes it is the same check.