Рассмотрим следующий фрагмент кода:
int* find_ptr(int* mem, int sz, int val) {
for (int i = 0; i < sz; i++) {
if (mem[i] == val) {
return &mem[i];
}
}
return nullptr;
}
GCC -O3 компилирует это так:
find_ptr(int*, int, int):
mov rax, rdi
test esi, esi
jle .L4 # why not .L8?
lea ecx, [rsi-1]
lea rcx, [rdi+4+rcx*4]
jmp .L3
.L9:
add rax, 4
cmp rax, rcx
je .L8
.L3:
cmp DWORD PTR [rax], edx
jne .L9
ret
.L8:
xor eax, eax
ret
.L4:
xor eax, eax
ret
В этой сборке блоки с метками .L4
и .L8
идентичны. Не лучше ли переписать переходы с .L4
на .L8
и сбросить .L4
? Я думал, что это может быть ошибкой, но clang также дублирует последовательность xor
- ret
. Тем не менее, ICC и MSVC используют совершенно разные подходы.
Является ли это оптимизацией в этом случае, и если нет, то есть ли моменты, когда это будет? В чем причина такого поведения?