Similar to gcc's https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94589 , it would be nice to optimize (x<=>y)@0 to x@y for all comparisons @, and clang/llvm seems to manage for some but not all. #include <compare> int n(int x){return (x<=>0)<0;} Debian clang version 13.0.0-++20210129063721+010b176cdefb-1~exp1 x86_64-pc-linux-gnu movl %edi, %eax shrl $24, %eax testl %edi, %edi setne %cl testb %al, %al sets %al andb %cl, %al movzbl %al, %eax retq
Can you please post relevant standalone snippets here, as links to godbolt?
#include <compare> bool test1(int x, int y){return (x<=>y)<0;} bool test2(int x){return (x<=>1)<0;} bool test3(int x){return (x<=>0)>0;} bool test4(int x){return (x<=>0)<0;} define dso_local zeroext i1 @_Z5test1ii(i32 %0, i32 %1) local_unnamed_addr #0 { %3 = icmp slt i32 %0, %1 ret i1 %3 } define dso_local zeroext i1 @_Z5test2i(i32 %0) local_unnamed_addr #0 { %2 = icmp slt i32 %0, 1 ret i1 %2 } define dso_local zeroext i1 @_Z5test3i(i32 %0) local_unnamed_addr #0 { %2 = icmp sgt i32 %0, 0 ret i1 %2 } define dso_local zeroext i1 @_Z5test4i(i32 %0) local_unnamed_addr #0 { %2 = lshr i32 %0, 24 %3 = trunc i32 %2 to i8 %4 = icmp ne i32 %0, 0 %5 = icmp slt i8 %3, 0 %6 = and i1 %4, %5 ret i1 %6 } https://godbolt.org/z/n78v1dahz
---------------------------------------- define i1 @src(i32 %0) { %1: %2 = icmp slt i32 %0, 0 %3 = select i1 %2, i8 255, i8 1 %4 = icmp eq i32 %0, 0 %5 = select i1 %4, i8 0, i8 %3 %6 = icmp slt i8 %5, 0 ret i1 %6 } => define i1 @tgt(i32 %0) { %1: %2 = icmp slt i32 %0, 0 ret i1 %2 } Transformation seems to be correct! https://alive2.llvm.org/ce/z/jAqWw4 We somehow miss this transformation for SLT, https://godbolt.org/z/8KrnKj1sh for SGT it works now: https://godbolt.org/z/PaKbY48Pv
Looks like we're just missing a basic icmp fold for a truncated value: https://alive2.llvm.org/ce/z/6vQvrP I'll post a patch.
This should get the example in the description: https://reviews.llvm.org/rG5354a213a0e3 If there are other examples, please reopen or file more bugs. Thanks!