Currently, impl Ord for bool converts the bools to u8s and then compares them.
On the playground,
pub fn using_ord(x: bool, y: bool) -> Ordering {
x.cmp(&y)
}
compiles to
playground::using_ord: # @playground::using_ord
# %bb.0:
movl %edi, %ecx
xorl %esi, %ecx
testl %esi, %esi
movl $255, %eax
cmovel %ecx, %eax
testl %edi, %edi
cmovnel %ecx, %eax
# kill: def $al killed $al killed $eax
retq
# -- End function
A much shorter (in instruction count) and almost certainly faster version taking advantage of the fact that orderings are represented by i8 values -1, 0, and 1, is:
pub fn minus_transmute(x: bool, y: bool) -> Ordering {
unsafe { std::mem::transmute(x as i8 - y as i8) }
}
which on the playground compiles to
playground::minus_transmute: # @playground::minus_transmute
# %bb.0:
movl %edi, %eax
subb %sil, %al
# kill: def $al killed $al killed $eax
retq
# -- End function
FWIW, you get identical codegen with a match statement (+ an unreachable_unchecked), which I find slightly more readable than the transmute:
pub fn minus_match(x: bool, y: bool) -> Ordering {
match x as i8 - y as i8 {
-1 => Ordering::Less,
0 => Ordering::Equal,
1 => Ordering::Greater,
_ => unsafe { std::hint::unreachable_unchecked() }
}
}
Fair enough; that does seem like it relies on less assumptions about "the outside", too.
I would like to work on this issue unless somebody else already started working on it.
Most helpful comment
FWIW, you get identical codegen with a
matchstatement (+ anunreachable_unchecked), which I find slightly more readable than thetransmute: