Closed
Description
Today, this code https://cpp.godbolt.org/z/e8q15zzK1
#include <compare>
std::strong_ordering cmp(int a, int b) {
return a <=> b;
}
gives this select chain
define dso_local i8 @_Z3cmpii(i32 noundef %0, i32 noundef %1) local_unnamed_addr #0 {
%3 = icmp slt i32 %0, %1
%4 = select i1 %3, i8 -1, i8 1
%5 = icmp eq i32 %0, %1
%6 = select i1 %5, i8 0, i8 %4
ret i8 %6
}
which compiles to some pretty verbose assembly:
cmp(int, int): # @cmp(int, int)
cmp edi, esi
setl al
neg al
or al, 1
xor ecx, ecx
cmp edi, esi
movzx eax, al
cmove eax, ecx
ret
There are other ways of doing this that are definitely better for size, and plausibly better for speed too https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign
For example, it could be
cmp(int, int): # @cmp(int, int)
cmp edi, esi
setg al
setl cl
sub al, cl
ret
(I've filed this as x86-specific because the select
s in LLVM-IR might be better for optimizations to use, as more obvious than the subtraction. The specific pattern that Clang emits for <=>
is most important, but it would be nice if it also recognized -- or canonicalized in IR -- the bunch of equivalent select chains.)