https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120963

            Bug ID: 120963
           Summary: Missed optimization of (a > b ? a - b : 0) pattern
           Product: gcc
           Version: 15.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: other
          Assignee: unassigned at gcc dot gnu.org
          Reporter: Explorer09 at gmail dot com
  Target Milestone: ---

This could be multiple missed optimization issues in one same test code. I just
don't know how to reduce the issues to even simpler test cases.

```c
#include <stdint.h>

int32_t func1a(int32_t a, int32_t b) {
    if (b - a < 0)
        a = b;
    return b - a;
}
int32_t func1b(int32_t a, int32_t b) {
    if (b < a)
        a = b;
    return b - a;
}
int32_t func1c(int32_t a, int32_t b) {
    if (b < a)
        return 0;
    return b - a;
}
```

x86-64 gcc 15.1 with `-Os -fno-wrapv` options produces the following assembly:

```x86asm
func1a:
    subl    %edi, %esi
    movl    $0, %eax
    cmovns  %esi, %eax
    ret
func1b:
    cmpl    %edi, %esi
    movl    %esi, %eax
    cmovle  %esi, %edi
    subl    %edi, %eax
    ret
func1c:
    movl    %esi, %eax
    xorl    %edx, %edx
    subl    %edi, %eax
    cmpl    %edi, %esi
    cmovl   %edx, %eax
    ret
```

Note that the three functions are equivalent, and yet the generated assembly
codes are different, and none of them are optimal.

The optimal code, AFAIK, is this:

```x86asm
func1:
    xorl    %eax, %eax
    subl    %edi, %esi
    cmovg   %esi, %eax
    ret
```

When compared with the assembly of three functions above:

* func1a missed the part that the `movl $0, %eax` can be simplified to `xorl   
%eax, %eax` if the instruction is performed _before_ the `sub` instruction, the
condition code of which is checked later.
* As signed integer overflow is undefined behavior in C, the `cmovns` in func1a
could as well be transformed to `cmovg`. (This optimization should be disabled
for `-fwrapv`.)
* func1c missed that the `sub` and `cmp` could be merged to one operation. This
can also save the `mov` instruction at the beginning. (I have reported Bug
113680 as similar to this issue.)

Reply via email to