во время игры с godbolt.org я заметил, что gcc (6.2, снапшот 7.0), clang (3.9) и icc (17) при компиляции чего-то близкого к
int a(int* a, int* b) {
if (b - a < 2) return *a = ~*a;
// register intensive code here e.g. sorting network
}
компилирует (-O2/-O3) это примерно так:
push r15
mov rax, rcx
push r14
sub rax, rdx
push r13
push r12
push rbp
push rbx
sub rsp, 184
mov QWORD PTR [rsp], rdx
cmp rax, 7
jg .L95
not DWORD PTR [rdx]
.L162:
add rsp, 184
pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
ret
что, очевидно, имеет огромные накладные расходы в случае b - a ‹ 2. В случае -Os gcc компилируется в:
mov rax, rcx
sub rax, rdx
cmp rax, 7
jg .L74
not DWORD PTR [rdx]
ret
.L74:
Это наводит меня на мысль, что нет кода, который мешает компилятору выдать этот более короткий код.
Есть ли причина, почему компиляторы делают это? Есть ли способ компилировать их в более короткую версию без компиляции по размеру?
Here's an example on Godbolt that reproduces this. Кажется, это как-то связано с рекурсивностью сложной части.
if (__bultin_expect(b - a < 2, 1))
. Кроме того, доступность функции для встраивания (или использование оптимизации всей программы) может позволить GCC частично встроить оператор if. - person Ross Ridge   schedule 20.10.2016//... complicated-code-here
. - person Peter Cordes   schedule 20.10.2016__attribute__((noinline))
в ядре Linux: поместите общий регистр с интенсивным регистром с обработкой ошибок в другую функцию и предотвратите ее встраивание, чтобы не было push/pop на быстрый путь. (Где быстрый путь через функцию довольно короткий, как ваш ранний выход.) - person Peter Cordes   schedule 20.10.2016@cordes
не уведомляет меня. Я думаю, что это совпадает только с префиксами имен пользователей, а не с именами пользователей. Кстати, вот почему вы всегда должны публиковать полные ссылки, а не короткие ссылки Godbolt, если у вас есть место (т.е. не комментарий)< /а>. Вот почему я специально предложил опубликовать полную ссылку. - person Peter Cordes   schedule 20.10.2016