Существует два известных способа установки целочисленного регистра на нулевое значение на x86.
Либо
mov reg, 0
или
xor reg, reg
Есть мнение, что второй вариант лучше, поскольку значение 0 не сохраняется в коде и что сохраняет несколько байтов полученного машинного кода. Это, безусловно, хорошо - меньше кэша команд используется, и иногда это может привести к более быстрому выполнению кода. Многие компиляторы производят такой код.
Однако формально существует зависимость между инструкциями между инструкцией xor и любой предыдущей инструкцией, которая меняет один и тот же регистр. Так как там депиляция, последняя инструкция должна ждать до тех пор, пока первая не завершится, и это может снизить нагрузку на процессор и снизить производительность.
add reg, 17
;do something else with reg here
xor reg, reg
Очевидно, что результат xor будет точно таким же, независимо от исходного значения регистра. Но это процессор способен распознать это?
Я пробовал следующий тест в VС++ 7:
const int Count = 10 * 1000 * 1000 * 1000;
int _tmain(int argc, _TCHAR* argv[])
{
int i;
DWORD start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
xor eax, eax
};
}
DWORD diff = GetTickCount() - start;
start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
mov eax, 0
};
}
diff = GetTickCount() - start;
return 0;
}
С оптимизацией обе петли берут ровно одно и то же время. Означает ли это обоснованное обоснование того, что процессор распознает, что нет никакой зависимости от команды xor reg, reg
в предыдущей инструкции mov eax, 0
? Что может быть лучшим испытанием для проверки этого?