I tried this code:
compiler explorer
pub enum Enum {
A(u32),
B(u32),
C(u32),
}
#[no_mangle]
pub fn f1(lhs: &Enum, rhs: &Enum) -> bool {
match (lhs, rhs) {
(Enum::A(lhs), Enum::A(rhs)) => lhs == rhs,
(Enum::B(lhs), Enum::B(rhs)) => lhs == rhs,
(Enum::C(lhs), Enum::C(rhs)) => lhs == rhs,
_ => false,
}
}
#[no_mangle]
pub fn f2(lhs: &Enum, rhs: &Enum) -> bool {
if std::mem::discriminant(lhs) != std::mem::discriminant(rhs) {
return false;
}
match (lhs, rhs) {
(Enum::A(lhs), Enum::A(rhs)) => lhs == rhs,
(Enum::B(lhs), Enum::B(rhs)) => lhs == rhs,
(Enum::C(lhs), Enum::C(rhs)) => lhs == rhs,
_ => false,
}
}
#[no_mangle]
pub fn f3(lhs: &Enum, rhs: &Enum) -> bool {
if std::mem::discriminant(lhs) != std::mem::discriminant(rhs) {
return false;
}
match (lhs, rhs) {
(Enum::A(lhs), Enum::A(rhs)) => lhs == rhs,
(Enum::B(lhs), Enum::B(rhs)) => lhs == rhs,
(Enum::C(lhs), Enum::C(rhs)) => lhs == rhs,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
Code like this is often used for implementations of PartialEq or PartialOrd on enums, so it is important that it be optimized well.
I expected to see this happen:
The functions f1 and f2 should produce equivalent machine code to f3.
Instead, this happened:
f1 and f2 do not produce equivalent machine code.
f1 is missing the early return for when the discriminants do not match.
f2 unnecessarily examines the discriminant of lhs twice!
LLVM should be able to transform f1 into f2, and f2 into f3
Meta
rustc --version --verbose:
rustc 1.76.0-nightly (a96d57bdb 2023-12-15)
binary: rustc
commit-hash: a96d57bdb6d2bb6d233d7d5aaefc2995ab99be01
commit-date: 2023-12-15
host: x86_64-unknown-linux-gnu
release: 1.76.0-nightly
LLVM version: 17.0.6
Backtrace
I tried this code:
compiler explorer
Code like this is often used for implementations of
PartialEqorPartialOrdon enums, so it is important that it be optimized well.I expected to see this happen:
The functions
f1andf2should produce equivalent machine code tof3.Instead, this happened:
f1andf2do not produce equivalent machine code.f1is missing the early return for when the discriminants do not match.f2unnecessarily examines the discriminant oflhstwice!LLVM should be able to transform
f1intof2, andf2intof3Meta
rustc --version --verbose:Backtrace