-
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
Unnecesary discriminant checks in PartialEq
/PartialOrd
style code on enums
#119014
Comments
@rustbot label I-slow |
Interestingly, when |
Adding a zero-sized field (like |
The |
The improvement I'm looking for here is removing unnecessary repeated inspections of enum discriminants, not merging duplicate RHS per se. This improvement would still be useful even if each enum variant has different data in it: pub enum Enum {
A(u32),
B(u64),
C(f32),
D(f64),
} |
Here's some more similar strange behaviour: #[no_mangle]
pub fn f1(lhs: &Enum, rhs: &Enum) -> bool {
match (lhs, rhs) {
(Enum::A(lhs), Enum::A(rhs)) => true,
(Enum::B(lhs), Enum::B(rhs)) => true,
(Enum::C(lhs), Enum::C(rhs)) => true,
_ => false,
}
} demonstrates the repeated inspections, but if we remove the unused Seems like MIR optimisations manage to improve it to a point where LLVM can optimise it better |
Update: In fact, we just need to re-enable the early otherwise branch optimization. Hmm, this requires multiple optimizations to work together.
As we merge the two i32, we'll end up with better instructions. See https://llvm.godbolt.org/z/EYG46EaxY. mov rax, qword ptr [rsi]
cmp rax, qword ptr [rdi]
sete al
ret It may be that part of the optimization fits in MIR, I'll trade off. @rustbot claim |
… r=<try> Re-enable the early otherwise branch optimization Fixes rust-lang#95162. Fixes rust-lang#119014. Fixes rust-lang#117970. An invalid enum discriminant can come from anywhere. We have to check to see if all successors contain the discriminant statement. It should not be UB that we pass in an invalid enum discriminant when calling a function, this is more like LLVM's poison value. UB only when used. Although miri would consider the following code to be UB. (It's fine for miri.) https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=18602870aaeb07cbdf7dfcd2c28961a2 I extended the scenario with scalars and the same target values. r? compiler
… r=<try> Re-enable the early otherwise branch optimization Fixes rust-lang#95162. Fixes rust-lang#119014. Fixes rust-lang#117970. An invalid enum discriminant can come from anywhere. We have to check to see if all successors contain the discriminant statement. It should not be UB that we pass in an invalid enum discriminant when calling a function, this is more like LLVM's poison value. UB only when used. Although miri would consider the following code to be UB. (It's fine for miri.) https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=18602870aaeb07cbdf7dfcd2c28961a2 I extended the scenario with scalars and the same target values. r? compiler
…nch, r=<try> Re-enable the early otherwise branch optimization Closes rust-lang#95162. Fixes rust-lang#119014. This is the first part of rust-lang#121397. An invalid enum discriminant can come from anywhere. We have to check to see if all successors contain the discriminant statement. This should have a pass to hoist instructions. r? cjgillot
…nch, r=cjgillot Re-enable the early otherwise branch optimization Closes rust-lang#95162. Fixes rust-lang#119014. This is the first part of rust-lang#121397. An invalid enum discriminant can come from anywhere. We have to check to see if all successors contain the discriminant statement. This should have a pass to hoist instructions. r? cjgillot
I tried this code:
compiler explorer
Code like this is often used for implementations of
PartialEq
orPartialOrd
on enums, so it is important that it be optimized well.I expected to see this happen:
The functions
f1
andf2
should produce equivalent machine code tof3
.Instead, this happened:
f1
andf2
do not produce equivalent machine code.f1
is missing the early return for when the discriminants do not match.f2
unnecessarily examines the discriminant oflhs
twice!LLVM should be able to transform
f1
intof2
, andf2
intof3
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: