Я вижу, что компилятор может исключить вычисление одного из E2 или E3 в зависимости от условия E1 (если у E2 / E3 нет побочных эффектов) для троичного оператора.
Компилятор не исключает это;он просто никогда не оптимизирует его до cmov
. Абстрактная машина C ++ не оценивает неиспользуемую сторону троичного оператора.
int a, b;
void foo(int sel) {
sel ? a++ : b++;
}
компилируется так ( Godbolt ):
foo(int):
test edi, edi
je .L2 # if(sel==0) goto
add DWORD PTR a[rip], 1 # ++a
ret
.L2:
add DWORD PTR b[rip], 1 # ++b
ret
Тернарный оператор может оптимизировать до asm cmov
, только если ни один из входов не имеет побочных эффектов.В противном случае они не совсем эквивалентны.
В абстрактной машине C ++ (т. Е. Вход в оптимизатор gcc) ваш foo2
всегда вызывает f()
, а ваш foo1
не делает. Не удивительно, что foo1 компилирует так, как он делает.
Чтобы foo2 компилировал таким образом, ему пришлось бы оптимизировать вызов до f()
. Он всегда вызывается для создания аргумента для ternary()
.
Здесь есть пропущенная оптимизация, о которой вы должны сообщить в bugzilla GCC (используйте ключевое слово missed-optimization
в качестве тега).https://gcc.gnu.org/bugzilla/enter_bug.cgi?product=gcc
Вызов int f() __attribute__ ((pure));
должен быть оптимизированным.Он может читать глобальных переменных, но не должен иметь побочных эффектов. (https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html)
Как обнаружил @melpomene в комментариях, int f() __attribute__ ((const));
действительно дает вам оптимизациюищите. Функция __attribute__((const))
не может даже читать глобальные переменные, только ее аргументы. (Таким образом, без аргументов, она всегда должна возвращать константу.)
HVD указывает, что gcc не требует никаких затратинформация для f()
. Даже если бы мог оптимизировать вызов до ((pure)) f()
, а также до ((const)) f
, возможно, этого не произошло, потому что он не знал, что это дороже, чемусловная ветвь? Возможно, компиляция с оптимизацией по профилю убедит gcc что-то сделать?
Но, учитывая, что он сделал условный вызов ((const)) f
в foo2
, gcc может просто не знать, что он может оптимизироватьвызовы ((pure))
функций? Может быть, он может только CSE их (если глобальные не были написаны), но не оптимизировать полностью от базового блока? Или, может быть, текущий оптимизатор просто не в состоянии воспользоваться. Как я уже сказал, выглядит какмиошибка ssed-opt.