Используйте не древнюю версию clang / LLVM .Apple clang / LLVM отличается от mainline clang / LLVM, но они имеют общую кодовую базу.
Mainline clang3.3 и новее автоматически векторизуют ваш цикл на -O3
. Clang3.4 и более новые автоматически векторизируют его даже при -O2
.
Без restrict
, clang делает испускает asm, который проверяет перекрытие между пунктом назначения идва источника (с откатом к скаляру), так что вы получите более эффективный asm из float *restrict s
.
#include <stdlib.h>
void add_float_good(float *restrict s, float *restrict ap, float *restrict bp)
{
for(size_t i=0;i<64;++i) {
s[i] = ap[i]+bp[i];
}
}
компилирует с помощью clang3.4 -O3 (в проводнике компилятора Godbolt) к этому упрощенному асму с худшим из индексированных режимов адресации и накладных расходов цикла, но по крайней мере он векторизован.Новому clang нравится разворачиваться, особенно при настройке на последние версии Intel (например, -march=skylake
)
# clang3.4 -O3
add_float_good:
xor eax, eax
.LBB0_1: # %vector.body
movups xmm0, xmmword ptr [rsi + 4*rax]
movups xmm1, xmmword ptr [rdx + 4*rax]
addps xmm1, xmm0
movups xmmword ptr [rdi + 4*rax], xmm1
add rax, 4
cmp rax, 64
jne .LBB0_1
ret
Обратите внимание, что без AVX он не может использовать операнд источника памяти для addps
, потому что нет компиляции-временная гарантия выравнивания.
clang8.0 -O3 -march = skylake полностью разворачивается с векторами YMM, например, gcc с теми же параметрами.