Мне нужно написать оптимизированный код NEON для проекта, и я совершенно счастлив писать на ассемблере, но для переносимости / ремонтопригодности я использую инстринсики NEON. Этот код должен быть как можно более быстрым, поэтому я использую свой опыт в оптимизации ARM, чтобы правильно чередовать инструкции и избегать остановок конвейера. Независимо от того, что я делаю, GCC работает против меня и создает более медленный код, полный киосков.
Кто-нибудь знает, как заставить GCC уйти с дороги и просто перевести мои встроенные функции в код?
Вот пример: у меня есть простой цикл, который инвертирует и копирует значения с плавающей запятой. Он работает с 4 наборами по 4 за раз, чтобы дать некоторое время для загрузки памяти и выполнения инструкций. Осталось много регистров, так что нет причин так сильно портить вещи.
float32x4_t f32_0, f32_1, f32_2, f32_3;
int x;
for (x=0; x<n-15; x+=16)
{
f32_0 = vld1q_f32(&s[x]);
f32_1 = vld1q_f32(&s[x+4]);
f32_2 = vld1q_f32(&s[x+8]);
f32_3 = vld1q_f32(&s[x+12]);
__builtin_prefetch(&s[x+64]);
f32_0 = vnegq_f32(f32_0);
f32_1 = vnegq_f32(f32_1);
f32_2 = vnegq_f32(f32_2);
f32_3 = vnegq_f32(f32_3);
vst1q_f32(&d[x], f32_0);
vst1q_f32(&d[x+4], f32_1);
vst1q_f32(&d[x+8], f32_2);
vst1q_f32(&d[x+12], f32_3);
}
Это код, который он генерирует:
vld1.32 {d18-d19}, [r5]
vneg.f32 q9,q9 <-- GCC intentionally causes stalls
add r7,r7,#16
vld1.32 {d22-d23}, [r8]
add r5,r1,r4
vneg.f32 q11,q11 <-- all of my interleaving is undone (why?!!?)
add r8,r3,#256
vld1.32 {d20-d21}, [r10]
add r4,r1,r3
vneg.f32 q10,q10
add lr,r1,lr
vld1.32 {d16-d17}, [r9]
add ip,r1,ip
vneg.f32 q8,q8
Больше информации:
- GCC 4.9.2 для Raspbian
- флаги компилятора:
-c -fPIE -march=armv7-a -Wall -O3 -mfloat-abi=hard -mfpu=neon
Когда я пишу цикл в коде ASM, построенном в точном соответствии с моими внутренними функциями (даже без использования дополнительных регистров src / dest для получения некоторых свободных циклов ARM), он все равно быстрее, чем код GCC.
Обновление: я ценю ответ Джеймса, но, по сути, это не помогает решить проблему. Самые простые из моих функций работают немного лучше с опцией cortex-a7, но большинство не изменилось. Печальная правда заключается в том, что оптимизация встроенных функций GCC невелика. Когда я работал с компилятором Microsoft ARM несколько лет назад, он постоянно создавал хорошо продуманный вывод для встроенных функций NEON, в то время как GCC постоянно спотыкался. В GCC 4.9.x ничего не изменилось. Я, конечно, ценю FOSS-характер GCC и большие усилия GNU, но нельзя отрицать, что он не так хорош, как компиляторы Intel, Microsoft или даже ARM.
-mcpu=cortex-a7
, чтобы изменить модель планирования инструкций, которую использует компилятор. Если вы хотите попробовать более экстремальный флаг, вы можете попросить GCC вообще не пытаться планировать выполнение инструкций с-fno-schedule-insns -fno-schedule-insns2
. - person James Greenhalgh   schedule 20.01.2016-mtune=cortex-a7
(Linaro GCC 5.1) делает вывод очень похожим на ввод ... - person Notlikethat   schedule 20.01.2016asm volatile("");
между каждым внутренним? это перестанет перемещать вещи. - person auselen   schedule 20.01.2016