Рассмотрим следующую программу C:статического предсказания ветвлений/оптимизации GCC
void bar();
void baz();
void foo(int a) {
if (a) {
bar();
}
else {
baz();
}
}
На моем x86-64 на основе компьютера, инструкции, генерируемые НКУ с уровнем оптимизации -O1 дает:
0: sub $0x8,%rsp
4: test %edi,%edi
6: je 14 <foo+0x14>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to bar
12: jmp 1e <foo+0x1e>
14: mov $0x0,%eax
19: callq 1e <foo+0x1e> # relocation to baz
1e: add $0x8,%rsp
22: retq
, тогда как добавление параметра оптимизации -freorder-блоков (входит в -O2) превращает код в:
0: sub $0x8,%rsp
4: test %edi,%edi
6: jne 17 <foo+0x17>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to baz
12: add $0x8,%rsp
16: retq
17: mov $0x0,%eax
1c: callq 21 <foo+0x21> # relocation to bar
21: add $0x8,%rsp
25: retq
что в основном меняется от прыжок равен до прыжок не равен. Я знаю, что до Pentium 4 предсказание статической ветви на условной передовой ветви считалось не принятым процессором (кажется, что статические предсказания стали случайными на последующих процессорах Intel), поэтому я полагаю, что эта оптимизация имеет дело с этим.
Предполагая, что и отсылая к JNE оптимизированной версии, это будет означать, что блок еще является на самом деле считается, что более вероятно, чем выполнена если блока в процессе выполнения программы.
Но что это значит? Поскольку нет значения для значения a в функции компилятора foo, такая вероятность зависит только от писаний программиста (кто мог бы использовать if (!a)
вместо if (a)
и вызовы с перевернутыми функциями).
Означает ли это, что следует рассматривать как эффективную практику лечения , если условные блоки как исключительные случаи (а не нормальный поток выполнения)?
То есть:
if (!cond) {
// exceptional code
}
else {
// normal continuation
}
вместо:
if (cond) {
// normal continuation
}
else {
// exceptional code
}
(конечно, можно было бы предпочесть использовать оператор возврата внутри соответствующего блока, чтобы ограничить размер отступа).
Да ... Но разные точки возврата могли быть реализованы только в версии 'je'. И GCC делает это, если/else блокирует переупорядочение _consciously_: в исходной программе изменение 'if (a)' to 'if (! A)' компилируется точно противоположно: от 'jne' (не оптимизированной) версии до 'je' (оптимизированная по порядку) версия. Я не могу поверить, что GCC делает это только для того, чтобы высмеять меня! :) – lledr
Я думаю, что в любом случае __builtin_expect должен помочь этому ;-). http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html –