Make abs, wrapping_abs, overflowing_abs const functions - #63786
Conversation
|
r? @cramertj (rust_highfive has picked a reviewer for you, use r? to override) |
|
@rfcbot fcp merge |
|
Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
|
Ping @withoutboats @Kimundi @sfackler in case y'all missed this. :) |
|
🔔 This is now entering its final comment period, as per the review above. 🔔 |
|
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon. |
|
@bors: r+ |
|
📌 Commit adee559 has been approved by |
Make `abs`, `wrapping_abs`, `overflowing_abs` const functions This makes `abs`, `wrapping_abs` and `overflowing_abs` const functions like rust-lang#58044 makes `wrapping_neg` and `overflowing_neg` const functions. `abs` is made const by returning `(self ^ -1) - -1` = `!self + 1` = `-self` for negative numbers and `(self ^ 0) - 0` = `self` for non-negative numbers. The subexpression `self >> ($BITS - 1)` evaluates to `-1` for negative numbers and `0` otherwise. The subtraction overflows when `self` is `min_value()`, as we would be subtracting `max_value() - -1`; this is when `abs` should overflow. `wrapping_abs` and `overflowing_abs` make use of `wrapping_sub` and `overflowing_sub` instead of the subtraction operator.
Rollup of 8 pull requests Successful merges: - #63786 (Make `abs`, `wrapping_abs`, `overflowing_abs` const functions) - #63989 (Add Yaah to clippy toolstain notification list) - #64256 (test/c-variadic: Fix patterns on powerpc64) - #64292 (lowering: extend temporary lifetimes around await) - #64311 (lldb: avoid mixing "Hit breakpoint" message with other output.) - #64330 (Clarify E0507 to note Fn/FnMut relationship to borrowing) - #64331 (Changed instant is earlier to instant is later) - #64344 (rustc_mir: buffer -Zdump-mir output instead of pestering the kernel constantly.) Failed merges: r? @ghost
| self | ||
| } | ||
| pub const fn wrapping_abs(self) -> Self { | ||
| (self ^ (self >> ($BITS - 1))).wrapping_sub(self >> ($BITS - 1)) |
There was a problem hiding this comment.
We've had variables for a while, please use them.
There was a problem hiding this comment.
Has it been verified that this optimizes to identical LLVM IR?
There was a problem hiding this comment.
@eddyb Since this has already passed final comment period and been merged, shall I open a new PR to use variables?
There was a problem hiding this comment.
@nikic I can't read LLVM IR; what I did do before submitting the PR was to use llvm-mca, and although the assembly is not identical, the performance measure from llvm-mca was the same, or if I remember well, in some tests the reverse throughput improved by something tiny like 0.1, but not regressed. I only used llvm-mca with i686 or x86-64 instructions, and I don't think I tested all types comprehensively.
There was a problem hiding this comment.
@nikic Hmm, using variables as @eddyb suggested seems to hit two birds with one stone. If I insert a variable for the sign, I get one implementation and an alias: https://godbolt.org/z/m-seT0
Does that mean that the performance will not regress?
There was a problem hiding this comment.
@tspiteri Oops, I simply made a typo in my test and that's why the result is different, duh :) It actually does produce the same IR, both with variable and without. So forget everything I said, this change is fine from the optimization perspective.
There was a problem hiding this comment.
@nikic While abs and wrapping_abs seem to be fine performance-wise, overflowing_abs from this PR actually does suffer from the problem discussed, so I will not forget everything you said! :) It's easily fixed by making it return (self.wrapping_abs(), self == Self::min_value()).
There was a problem hiding this comment.
And also, the code with the sign factored out is more readable. ;)
That said, I still think we should rather wait for CTFE to support conditionals than compromise code readability, and even the let sign version is still arcane magic. But that call is up to T-libs.
There was a problem hiding this comment.
No, we should definitely make as many of these small ops into const as soon as we can.
This makes
abs,wrapping_absandoverflowing_absconst functions like #58044 makeswrapping_negandoverflowing_negconst functions.absis made const by returning(self ^ -1) - -1=!self + 1=-selffor negative numbers and(self ^ 0) - 0=selffor non-negative numbers. The subexpressionself >> ($BITS - 1)evaluates to-1for negative numbers and0otherwise. The subtraction overflows whenselfismin_value(), as we would be subtractingmax_value() - -1; this is whenabsshould overflow.wrapping_absandoverflowing_absmake use ofwrapping_subandoverflowing_subinstead of the subtraction operator.