ARM может сделать это за один vsri
инструкция (спасибо @Jake'Alquimista'LEE).
Учитывая новый вектор, из которого вы хотите получить биты знака, замените младшие 15 бит каждого элемента на аккумулятор, сдвинутый вправо на 1.
Вы должны развернуться на 2, чтобы компилятору не нужна была инструкция mov
для копирования результата обратно в тот же регистр, потому что vsri
— это инструкция с двумя операндами, и то, как мы должны использовать ее здесь, дает нам результат в другом регистр, чем старый sign0
аккумулятор.
sign0 = vsriq_n_u16(r0, sign0, 1);
// insert already-accumulated bits below the new bit we want
После 15 вставок (или 16, если вы начинаете с sign0 = 0
вместо очистки первой итерации и использования sign0=r0) все 16 битов (на элемент) sign0
будут битами знака из значений r0
.
Предыдущее предложение: И с константой вектора, чтобы изолировать бит знака. Это более эффективно, чем две смены.
Ваша идея накопления с помощью VSRA для сдвига аккумулятора и добавления нового бита хороша, поэтому мы можем сохранить это и сократить общее количество инструкций до 2.
tmp = r0 & 0x8000; // VAND
sign0 = (sign0 >> 1) + tmp; // VSRA
или используя неоновые свойства:
uint16x8_t mask80 = vmovq_n_u16(0x8000);
r0 = vandq_u16(r0, mask80); // VAND
sign0 = vsraq_n_u16(r0, sign0, 1); // VSRA
Реализуйте с помощью встроенных функций или ассемблера, как вам нравится, и напишите скалярную версию таким же образом, чтобы дать компилятору больше шансов на автоматическую векторизацию.
Для этого нужна векторная константа в регистре. Если вы очень ограничены в регистрах, то 2 смены могут быть лучше, но всего 3 смены, вероятно, будут узким местом в пропускной способности переключателей, если только чипы ARM обычно не тратят много места на переключатели SIMD.
В этом случае, возможно, используйте эту общую идею SIMD без ARM shift+accumulate или shift+insert.
tmp = r0 >> 15; // logical right shift
sign0 += sign0; // add instead of left shifting
sign0 |= tmp; // or add or xor or whatever.
Это дает вам биты в обратном порядке. Если вы можете произвести их в обратном порядке, то отлично.
В противном случае, есть ли у ARM бит-реверс SIMD или только для скаляра? (Сгенерируйте в обратном порядке и переверните их в конце, с некоторой дополнительной работой для каждого векторного растрового изображения, надеюсь, только с одной инструкцией.)
Обновление: да, AArch64 имеет rbit
, поэтому вы можете поменять местами биты внутри байта, а затем перетасовать байты, чтобы расположить их в правильном порядке. x86 может использовать pshufb
LUT для реверсирования битов внутри байтов в двух 4-битных фрагментах. Однако это может не произойти раньше, чем дополнительная работа, поскольку вы накапливаете биты на x86.
person
Peter Cordes
schedule
19.04.2018
vsraq
арифметическим сдвигом, а не логическим? Зачем это использовать? Кроме того, вы можете использовать меньше сдвигов, если перед сдвигом используете И для обнуления незнаковых битов. какsign0 |= (r0 & 0x8000) >> (15-i);
Или с фиксированным количеством смен:sign0 |= (r0 & 0x8000); sign0 >>= 1;
Последнее должно быть легко и эффективно реализовано с помощью SIMD, но я плохо знаю ARM. - person Peter Cordes   schedule 19.04.2018_u16
vs_s16
будет определять логический и арифметический сдвиг. - person Pavel P   schedule 19.04.2018(x >> 15) << 15
вместоx & 0x8000
. Похоже, вы могли бы использоватьvsra
, чтобы легко реализовать 2-е предложение в моем предыдущем комментарии в 2 инструкциях:tmp = r0 & 0x8000; sign0 = (sign0 >> 1) + tmp;
- person Peter Cordes   schedule 19.04.2018clang -target arm64
на Godbolt!! Кроме того, разве VSRA не настоящая инструкция? Или clang просто пессимизирует встроенную функцию в отдельные инструкцииvshr
иvorr
? - person Peter Cordes   schedule 19.04.2018vshl.s16 q4, q4, q9
, поэтому я думаю, что вы ошибаетесь. Или вы имели в виду, что это не так эффективно? - person Peter Cordes   schedule 19.04.2018i
в q-регистр, чтобы использовать переменный сдвиг - person Pavel P   schedule 19.04.2018vadd
для увеличения векторного счетчика отдельно от счетчика циклов регистра GP, а не фактически копирует + транслирует счетчик циклов на каждой итерации. - person Peter Cordes   schedule 19.04.2018src
,dst
иrotate
были добавлены только для примера. Дело в том, что часть цикла при вычислении других вещей мне нужно накапливать знаки в два отдельных q-вектора. - person Pavel P   schedule 19.04.2018vsra
, а такжеvsri
. Оба они очень медленные и не позволяют использовать отдельный целевой регистр, поэтому не очень гибкие. Интересно, зачем кому-то нужен либо для сбора битов. - person Jake 'Alquimista' LEE   schedule 20.04.2018vsra
, он позволяет сдвигать вправо + накапливать в одной инструкции, но тогда результатvsra
нужно переместить вsign0
. в любом случае. - person Pavel P   schedule 20.04.2018vld2
,vzip8
,vmovn.16
и т. д., тогда вам придется иметь дело только с половиной данных. - person Jake 'Alquimista' LEE   schedule 20.04.2018vclt.s8
с #0, чтобы получить 0xff для отрицательных значений. Затем выполнитеand
с {1, 2, 4, 8, 16, 32, 64, 128}. И, наконец, вы можете сделать горизонтальную сумму.vpadd' or
addv` наaarch64
- person Jake 'Alquimista' LEE   schedule 20.04.2018