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

--- Comment #2 from Tobias Schlüter <tobi at gcc dot gnu.org> ---
Thanks, it's interesting in your variation that the code is almost the same as
clang's except that it uses `sete dl; sub eax, edx` where clang uses a
conditional move.  Seems like clang can figure out that `eax` is one in that
case.

Because you wrote down a ternary for the handling of `len`, allow me to add
that substituting `((len == 1) ? 0 : len)` for `(len - (len == 1)_` leads to
additional jumps in the assembly.  I skipped this before because didn't want to
add another issue to this PR, but maybe it's still worth mentioning because it
seems to contradict my observation that the size of the expressions in the
branches is the main driver for gcc not using a `cmov`.

E.g.:
```
int bla_len_ternary(int last_digit, uint32_t len) {
    return (last_digit != 0) * 17 + (last_digit == 0) * (len == 1 ? 0 : len);
}

int bla_double_ternary(int last_digit, uint32_t len) {
    return (last_digit != 0) ? 17 : (len == 1 ? 0 : len);
}
```
gives https://godbolt.org/z/18686WvoT
```
bla_len_ternary(int, unsigned int):
        test    edi, edi
        je      .L16
        mov     eax, 17
        mov     edx, 17
.L14:
        cmp     esi, 1
        je      .L13
        xor     eax, eax
        test    edi, edi
        cmovne  esi, eax
        lea     eax, [rsi+rdx]
.L13:
        ret
.L16:
        xor     eax, eax
        xor     edx, edx
        jmp     .L14
bla_double_ternary(int, unsigned int):
        mov     eax, 17
        test    edi, edi
        jne     .L20
        cmp     esi, 1
        mov     eax, edi
        cmovne  eax, esi
.L20:
        ret
```
Where especially the first one is terrible.

Reply via email to