Ответ 1
clang будет выделять add eax, 0
в -O0
, но ни один из gcc, ICC и MSVC не будет. См. Ниже.
gcc -O0
не означает "без оптимизации". gcc не имеет режима "braindead literal translation", где он пытается транслитерировать каждый компонент каждого выражения C непосредственно в инструкцию asm.
GCC -O0
не является полностью не оптимизированным. Он предназначен для "компиляции" и делает отладку ожидаемыми результатами (даже если вы изменяете переменные C с помощью отладчика или переходите к другой строке внутри этой функции). Таким образом, он разливает/перезагружает все вокруг каждого оператора C, предполагая, что память может быть асинхронно модифицирована отладчиком, остановленным до такого блока. (Интересный пример последствий и более подробное объяснение: Почему целочисленное деление на -1 (отрицательное) приводит к FPE?)
Для gcc -O0
не требуется большой спрос даже на более медленный код (например, забыв, что 0
является аддитивным идентификатором), поэтому никто не реализовал для этого вариант. И это может даже сделать gcc медленнее, если это поведение было необязательным. (Или, может быть, есть такой вариант, но он по умолчанию даже в -O0
, потому что он быстрый, не повредит отладку и полезен. Обычно людям нравится, когда их отладочные сборки работают достаточно быстро, чтобы их можно было использовать, особенно для больших или в режиме реального времени.)
Как @Basile Starynkevitch объясняет в Отключить все опции оптимизации в GCC, gcc всегда трансформирует свои внутренние представления на пути к созданию исполняемого файла. Просто все это приводит к некоторым видам оптимизаций.
Например, даже при -O0
, gcc "делить на константный" алгоритм использует мультипликативный с фиксированной точкой обратный или сдвиг (для степеней 2) вместо инструкции idiv
. Но clang -O0
будет использовать idiv
для x /= 2
.
Clang -O0
тоже оптимизирует меньше gcc в этом случае:
void foo(void) {
volatile int num = 0;
num = num + 0;
}
выход asm на Godbolt для x86-64
push rbp
mov rbp, rsp
# your asm block from the question, but with 0 instead of 10
mov dword ptr [rbp - 4], 0
mov eax, dword ptr [rbp - 4]
add eax, 0
mov dword ptr [rbp - 4], eax
pop rbp
ret
Как вы говорите, gcc не использует бесполезный add eax,0
. ICC17 хранит/перезагружает несколько раз. MSVC обычно является чрезвычайно буквальным в режиме отладки, но даже он избегает испускания add eax,0
.
Clang также является единственным из 4 компиляторов x86 на Godbolt, который будет использовать idiv
для return x/2;
. Остальные все SAR + CMOV или что-то другое, чтобы реализовать C подписанную семантику деления.