>> mov edx, 0 ; Зачем?
> Так быстрее, хотя можно поспорить о том стоит ли игра свеч.
> Насколько помню, вариант кода от GCC в 2 раза (или даже в
> 3) быстрее на нулях.Про быстрее при 0 я писал https://www.opennet.ru/openforum/vsluhforumID3/122094.html#67 (у popcnt на ряде архитектур Latency=3 Throughput=1, тогда как у cmove Latency=1 Throughput=0.5)
Вопрос именно в обнулении edx. cmove выполняется, если в edi ноль. То есть нужные данные и так есть. И зависимость cmove по данным (ZF) от test и так есть.
test edi, edi
mov edx, 0
cmove eax, edx
test edi, edi
cmove eax, edi
Т.е не ясно, почему 1й вариант, а не 2й.
> Т.е. если считать кол-во единичных бит в массиве, то "магия" добавленная gcc
> позволяет экономить по такту на каждом слове.
На массиве нулей. А если данные случайны? На каждом одном слове из 256, то есть 1/256 такта. При этом кеш инструкций расходуется непропорционально. Тут надо иметь ввиду, что у разработчиков премиальные процессоры с большим кешем, а в реальности у пользователя Целерон и многозадачная система, где крутится 68 онлайн-мессенджеров.
> Кроме этого, при последующих вычислениях разница может быть еще более значительной (cmov
> может порождать два пути спекулятивного выполнения).
> При этом, поведение актуального gcc 10.2 очень прецизионное. Добавляемая "магия" меняется
> в зависимости от целевого ядра (опция -march=), всего 4 варианта не
> считая цикла при отсутствии popcnt.
> Ну и вишенка - gcc можно было-бы упрекнуть в генерации лишнего кода,
> но если задать -Os, то останется только popcnt.
> Собственно, поэтому я говорю что сейчас gcc умеет больше чем llvm.
Дело может быть в области применения, а так же в том, что в Ваши задачи входит писать быстрый код, потому в конкретных и оптимизированных решениях GCC выигрывает, присваивая себе заслуги автора кода. А вот эта моя поделка https://www.opennet.ru/opennews/art.shtml?num=53778 собранная GCC, выполняется в 2 раза медленнее (согласно и top, и perf). Написал как попало, принципиально не заморачиваясь оптимизацией (ну, только синус табличный), в цикле считаются float-ы, примерно так:
if (!i) {
vert->color = src;
} else {
vert->color.r = src.r * (1.0f + fsin(vert->pos.x + omega_bk + i));
vert->color.g = src.g * (1.0f + fsin(vert->pos.y + omega_bk + i));
vert->color.b = src.b * (1.0f + fsin(vert->pos.x + vert->pos.y + omega_bk + i));
vert->color.a = src.a;
}
Причину не искал, потому не могу пока говорить про данный случай предметно.
Просто пример, когда первый попавшийся чайник берёт Clang и выигрывает.