https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113585
Bug ID: 113585 Summary: Poor codegen turning int compare into -1,0,1 Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: redbeard0531 at gmail dot com Target Milestone: --- https://www.godbolt.org/z/Y31xG7EeT These two functions should be equivalent, but comp2() produces better code than comp1() on both arm64 and x86_64 int comp1(int a, int b) { return a == b ? 0 : (a < b ? -1 : 1); } int comp2(int a, int b) { return a < b ? -1 : (a > b ? 1 : 0); } arm64: comp1(int, int): cmp w0, w1 mov w0, -1 csinc w0, w0, wzr, lt csel w0, w0, wzr, ne ret comp2(int, int): cmp w0, w1 cset w0, gt csinv w0, w0, wzr, ge ret x86_64: comp1(int, int): xor eax, eax cmp edi, esi je .L1 setge al movzx eax, al lea eax, [rax-1+rax] .L1: ret comp2(int, int): xor eax, eax cmp edi, esi mov edx, -1 setg al cmovl eax, edx ret In the arm case, I suspect that the perf will be equivalent, although comp1 has an extra instruction, so will pay a size penalty. On x86, comp2 is branchless while comp1 has a branch which could be problematic if not predictable. It seems like there should be a normalization pass to convert these functions (and other equivalent ones) into a single normalized representation so that they get the same codegen. PS: I tried another equivalent function and it produces even worse codegen on x86_64, comparing the same registers twice: int comp3(int a, int b) { return a > b ? 1 : (a == b ? 0 : -1); } comp3(int, int): xor eax, eax cmp edi, esi mov edx, 1 setne al neg eax cmp edi, esi cmovg eax, edx ret