Загрузите 8bit uint8_t как uint32_t?
-
01-10-2019 - |
Вопрос
Мой проект обработки изображений работает с изображениями в оттенках серого. У меня есть процессорная платформа ARM Cortex-A8. Я хочу использовать неон.
У меня есть изображение серого (рассмотрим пример ниже) и в моем алогоритеме, я должен добавить только столбцы.
Как я могу загрузить четыре 8-битных значения пикселей параллельно, которые uint8_t., так как четыре uint32_t. в один из 128-битных неоновых регистров? Какой внутренний я должен использовать для этого?
Я имею в виду:
Я должен загрузить их как 32 бита, потому что если вы посмотрите внимательно, в тот момент, когда я делаю 255 + 255, составляет 512, который не может быть проведен в 8-битном регистре.
например
255 255 255 255 ......... (640 pixels)
255 255 255 255
255 255 255 255
255 255 255 255
.
.
.
.
.
(480 pixels)
Решение
Я порекомендую, чтобы вы проведете немного времени, понимая, как Simd работает на руке. Смотреть на:
Взгляни на:
- http://blogs.arm.com/software-enablement/161-coding-for-neon-part-1-load-and-stores/
- http://blogs.arm.com/software-enablement/196-coding-for-neon-part-d-dealing-with-leftevers/
- http://blogs.arm.com/software-enablement/241-coding-for-neon-part-3-matrix-multipplication/
- http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-shifting-left-and-right/
чтобы начать. Затем вы можете реализовать свой код SIMD, используя встроенный ассемблер или соответствующие внутренние силы руки, рекомендованные Domen.
Другие советы
Зависит от вашего компилятора и (возможному отсутствию) расширений.
Т.е. Для GCC это может быть отправной точкой: http://gcc.gnu.org/onlinedocs/gcc/arm-neon-intrinsics.html.
Если вам нужно суммировать до 480 8-битных значений, то вы будете технически нужны 17 бит промежуточного хранения. Однако, если вы выполняете дополнения в два этапа, т. Е. Топ 240 строк, затем нижние 240 строк, вы можете сделать это в 16-битах каждый. Затем вы можете добавить результаты с двух половинок, чтобы получить окончательный ответ.
На самом деле есть неоновая инструкция, которая подходит для вашего алгоритма, называемого VADDW. Он добавит вектор DWORD на вектор QWord, с последними содержащими элементами, которые в два раза шире, как у первого. В вашем случае VADDW.U8 можно использовать для добавления 8 пикселей до 8 16-битных аккумуляторов. Затем Vaddw.u16 можно использовать для добавления двух наборов из 8 16-битных аккумуляторов в один набор из 8 32-битных - обратите внимание, что вы должны использовать инструкцию дважды, чтобы получить обе половины.
При необходимости вы также можете преобразовать значения обратно в 16-битную или 8-битное, используя VMOVN или VQMOVN.
Там нет инструкции, которые могут загрузить ваше 4 8-битное значение на 4 32-битного реестра.
Вы должны загрузить их, а затем использовать VSHL дважды. Потому что неон не может использовать 32 регистров, которые вам придется работать на 8 пикселей (а не 4)
Вы можете использовать только 16bits Register. Это должно быть достаточно ...
Загрузить 4 байта с использованием однополосной нагрузки (vld1 <register>[<lane>], [<address]
) в Q-реестр, затем используйте две инструкции по длине движения (vmovl
) Продвигать их первым до 16, а затем до 32 бит. Результатом должно быть что-то вроде (в синтаксисе GNU)
vld1 d0[0], [<address>] @Now d0 = (*<addr>, *<addr+1>, *<addr+2>, *<addr+3>, <junk>, ... <junk> )
vmovl.u8 q0, d0 @Now q1 = (d0, d1) = ((uint16_t)*<addr>, ... (uint16_t)*<addr+3>, <junk>, ... <junk>)
vmovl.u16 q0, d2 @Now d0 = ((uint32_t)*<addr>, ... (uint32_t)*<addr+3>), d1 = (<junk>, ... <junk>)
Если вы можете гарантировать, что <address>
4-байт выровнен, то напиши [<address>: 32]
Вместо этого в инструкции нагрузки, чтобы сохранить цикл или два. Если вы это сделаете, и адрес не выровнен, вы получите ошибку, однако.
Хм, я только что понял, что вы хотите использовать внутренние, а не в сборе, так что вот то же самое с внутренними лицами.
uint32x4_t v8; // Will actually hold 4 uint8_t
v8 = vld1_lane_u32(ptr, v8, 0);
const uint16x4_t v16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(v8)));
const uint32x4_t v32 = vmovl_u16(v16);