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.