ARM NEON: сравнение 128-битных значений

Мне интересно найти самый быстрый способ (наименьшее количество циклов) сравнения значений, хранящихся в регистрах NEON (скажем, Q0 и Q3) на ядре Cortex-A9 (разрешены инструкции VFP).

Пока у меня есть следующее:

(1) Использование сравнения VFP с плавающей запятой:

vcmp.f64        d0, d6
vmrs            APSR_nzcv, fpscr
vcmpeq.f64      d1, d7
vmrseq          APSR_nzcv, fpscr

Если 64-битные "поплавки" эквивалентны NaN, эта версия не будет работать.

(2) Используя сужение NEON и сравнение VFP (на этот раз только один раз и безопасным для NaN способом):

vceq.i32        q15, q0, q3
vmovn.i32       d31, q15
vshl.s16        d31, d31, #8
vcmp.f64        d31, d29
vmrs            APSR_nzcv, fpscr

Регистр D29 предварительно загружен правильным 16-битным шаблоном:

vmov.i16        d29, #65280     ; 0xff00

Мой вопрос: есть ли что-нибудь лучше, чем это? Я наблюдаю за каким-то очевидным способом сделать это?


person Mircea    schedule 30.01.2012    source источник


Ответы (1)


Я считаю, что вы можете уменьшить его на одну инструкцию. Используя сдвиг влево и вставку (VLSI), вы можете объединить 4 32-битных значения Q15 в 4 16-битных значения в D31. Затем вы можете сравнить с 0 и получить флаги с плавающей запятой.

vceq.i32  q15, q0, q3
vlsi.32   d31, d30, #16
vcmp.f64  d31, #0
vmrs      APSR_nzcv, fpscr
person BitBank    schedule 31.01.2012
comment
Первая инструкция перезаписывает весь Q15 (т.е. D30 и D31), а вторая имеет только D31 в качестве назначения, поэтому некоторая информация теряется, и сравнение не всегда дает правильный результат. - person Mircea; 01.02.2012
comment
Когда вы используете vceq.i32, он помещает все 1 или все 0 в каждую из 4 32-битных дорожек. Первая инструкция объединяет полезную информацию из D30 и D31 в D31 (младшие 16 бит всех 4 сравниваемых). Вторая инструкция сравнивает младшие 64-битные, которые содержат всю полезную информацию. - person BitBank; 01.02.2012
comment
Первая инструкция (т.е. vceq.i32) ничего не комбинирует. Кроме того, второй не использует D31 в качестве входа... - person Mircea; 01.02.2012
comment
Если вы изучите инструкцию СБИС, вы увидите, что она делает то, что вам нужно. В этом случае он берет младшие 16 бит каждого 32-битного слова из D30 и D31 (q15) и объединяет их в 4 16-битных полуслова в D31. Это означает, что у вас есть результаты сравнения всех 4 DWORDS, суженные до 16 бит каждое и сохраненные в D31. Оттуда вы можете выполнить vcmp.f64 для установки флагов. - person BitBank; 01.02.2012
comment
Страница 1054 Справочного руководства по архитектуре ARM (DDI0406C): Сдвиг вектора влево и вставка берут каждый элемент в векторе операнда, сдвигают их влево на непосредственное значение и вставляют результаты в целевой вектор. Биты, сдвинутые слева от каждого элемента, теряются. Вектор операнда в вашем коде — D30, а вектор назначения — D31, поэтому ничего не читается из D31. - person Mircea; 01.02.2012
comment
См. эту страницу (вторая диаграмма) blogs.arm.com/software-enablement/ - person BitBank; 01.02.2012
comment
Хорошо, вы правы, извините за спор. НО код по-прежнему имеет ту же проблему NaN, что и моя первая реализация: если Q0 и Q3 равны, D31 будет иметь все установленные биты (и, следовательно, NaN) => VCMP не будет работать. - person Mircea; 01.02.2012