https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88916
Bug ID: 88916 Summary: [x86] suboptimal code generated for integer comparisons joined with boolean operators Product: gcc Version: 8.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: wojciech_mula at poczta dot onet.pl Target Milestone: --- Let's consider these two simple, yet pretty useful functions: --test.c--- int both_nonnegative(long a, long b) { return (a >= 0) && (b >= 0); } int both_nonzero(unsigned long a, unsigned long b) { return (a > 0) && (b > 0); } ---eof-- $ gcc --version gcc (Debian 8.2.0-13) 8.2.0 $ gcc -O3 test.c -march=skylake -S $ cat test.s both_nonnegative: notq %rdi movq %rdi, %rax notq %rsi shrq $63, %rax shrq $63, %rsi andl %esi, %eax ret both_nonzero: testq %rdi, %rdi setne %al xorl %edx, %edx testq %rsi, %rsi setne %dl andl %edx, %eax ret I checked different target machines (haswell, broadwell and cannonlake), however the result remained the same. Also GCC trunk on godbolt.org produces the same assembly code. The first function, `both_nonnegative`, can be rewritten as: (((unsigned long)(a) | (unsigned long)(b)) >> 63) ^ 1 yielding something like this: both_nonnegative: orq %rsi, %rdi movq %rdi, %rax shrq $63, %rax xorl $1, %eax ret It's also possible to use this expression: (long)(unsigned long)a | (unsigned long)b) < 0, but the assembly output is almost the same. The condition from `both_nonzero` can be expressed as: ((unsigned long)a | (unsigned long)b) != 0 GCC compiles it to: both_nonzero: xorl %eax, %eax orq %rsi, %rdi setne %al retq