Преобразование между SSE и NEON Intrinsics-Shuffling - PullRequest
5 голосов
/ 01 ноября 2011

Я пытаюсь преобразовать код, написанный во встроенных функциях SSE3, в NEON SIMD и застрял из-за функции случайного воспроизведения. Я посмотрел Встроенные инструкции GCC s, Руководства по ARM идругие форумы, но не смогли найти решение.

КОД:

_m128i upper = _mm_loadu_si128((__m128i*)p1);

register __m128i mask1 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1);
register __m128i mask2 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1,0x80);
__m128i temp1_upper = _mm_or_si128(_mm_shuffle_epi8(upper,mask1),_mm_shuffle_epi8(upper,mask2));

Хотя инструкция vtbl1_u8 (uint8x8_t, uint8x8_t) создает таблицу поиска, которую можно использовать для назначения значенийрегистр назначения, он работает только на 64-битных регистрах. Также при случайном выполнении выполняется операция случайного сравнения, которая должна быть выполнена в NEON, и я не знаю, как это сделать эффективно.

r0 = (mask0 & 0x80)?0: SELECT (a, mask0 & 0x0f) // SELECT (a, n) извлекает n-й 8-битный параметр из a.

r1 = (mask1 & 0x80)?0: SELECT (a, mask1 & 0x0f)

...

Я не могу найти инструкцию, которая сначала проверяет старший бит маски, а затем выбирает младшие 4 битамаску эффективно. Я знаю, что мы можем сравнить каждый бит в регистре, а затем выбрать младшие 4 бита, если указано условие, но я надеялся сделать это эффективно. Надеюсь, кто-то может помочь или предоставить ссылку.

Большое спасибо,

Ура!

Ответы [ 2 ]

3 голосов
/ 13 октября 2012

Вам просто нужно использовать vtbl2_u8 дважды, разделив вход и соответствующим образом соединив выход:

#define uint8x16_to_8x8x2(v) ((uint8x8x2_t) { vget_low_u8(v), vget_high_u8(v) })

uint8x16_t a = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8x16_t b = { 0x80, 0x0f, 0x01, 0x0e, 0x02, 0x0d, 0x03, 0x0c, 0x04, 0x0b, 0x05, 0x0a, 0x06, 0x09, 0x07, 0x08 };
uint8x16_t c = vcombine_u8(vtbl2_u8(uint8x16_to_8x8x2(a), vget_low_u8(b)), vtbl2_u8(uint8x16_to_8x8x2(a), vget_high_u8(b)));
// c = 00 ff 11 ee 22 dd 33 cc 44 bb 55 aa 66 99 77 88

Как сказал Джейк, vtbl возвращает 0, когда индекс выходит за пределы диапазона, поэтому выне нужно никакой специальной обработки для случая 0x80.

2 голосов
/ 01 ноября 2011

VTBL возвращает 0, когда индекс выходит за пределы диапазона.

Поскольку он поддерживает до двух регистров Q в качестве таблицы поиска, это будет довольно просто:

  1. загрузить справочную таблицу в регистр Q (например, Q8)
  2. vtbl.8 d0, {q8}, d0 (где d0 содержит вашу маску)

Это сработает.

Если вы хотите, чтобы биты 4 ~ 6 не мешали, вы можете замаскировать их до vtbl.

К сожалению, VBIC абсолютно бесполезен для немедленного 8-битного.

Следовательно, вы должны пожертвовать регистром, инициализированным как операнд битовой маски.

  1. vmov.u8, d1, # ​​0x70
  2. загрузить справочную таблицу в регистр Q (например, Q8)
  3. vbic.i8 d0, d0, d1
  4. vtbl.8 d0, {q8}, d0 (где d0 содержит вашу маску)
...