Загрузить 8-битный uint8_t как uint32_t?

мой проект обработки изображений работает с изображениями в градациях серого. У меня процессорная платформа ARM Cortex-A8. Я хочу использовать НЕОН.

У меня есть изображение в градациях серого (рассмотрите пример ниже), и в моем алгоритме мне нужно добавить только столбцы.

Как я могу загрузить четыре 8-битных значения пикселей параллельно, которые являются uint8_t, как четыре uint32_t в один из 128-битных регистров NEON ? Какой внутренний я должен использовать, чтобы сделать это?

Я имею в виду:

альтернативный текст

Я должен загрузить их как 32-битные, потому что, если вы посмотрите внимательно, момент, когда я делаю 255 + 255, составляет 512, что не может храниться в 8-битном регистре.

e.g.

255 255 255 255 ......... (640 pixels)
255 255 255 255
255 255 255 255
255 255 255 255
.
.
.
.
.
(480 pixels) 

person HaggarTheHorrible    schedule 09.09.2010    source источник


Ответы (5)


Я рекомендую вам потратить немного времени на понимание того, как SIMD работает на ARM. Смотреть на:

Взгляни на:

  1. http://blogs.arm.com/software-enablement/161-coding-for-neon-part-1-load-and-stores/
  2. http://blogs.arm.com/software-enablement/196-coding-for-neon-part-2-dealing-with-leftovers/
  3. http://blogs.arm.com/software-enablement/241-coding-for-neon-part-3-matrix-multiplication/
  4. http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-shifting-left-and-right/

чтобы вы начали. Затем вы можете реализовать свой код SIMD, используя встроенный ассемблер или соответствующие встроенные функции ARM, рекомендованные доменом.

person doron    schedule 09.09.2010

Зависит от вашего компилятора и (возможно, отсутствия) расширений.

Т.е. для GCC это может быть отправной точкой: http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html

person domen    schedule 09.09.2010

Если вам нужно суммировать до 480 8-битных значений, то технически вам потребуется 17 бит промежуточного хранилища. Однако, если вы выполняете сложения в два этапа, т. е. 240 верхних строк, а затем 240 нижних, вы можете сделать это по 16 бит каждый. Затем вы можете сложить результаты двух половин, чтобы получить окончательный ответ.

На самом деле существует инструкция NEON, подходящая для вашего алгоритма, которая называется vaddw. Он добавит вектор двойного слова к вектору qword, причем последний будет содержать элементы вдвое шире первого. В вашем случае vaddw.u8 можно использовать для добавления 8 пикселей к 8 16-битным аккумуляторам. Затем можно использовать vaddw.u16 для добавления двух наборов из 8 16-битных аккумуляторов в один набор из 8 32-битных — обратите внимание, что вы должны использовать эту инструкцию дважды, чтобы получить обе половины.

При необходимости вы также можете преобразовать значения обратно в 16-битные или 8-битные с помощью vmovn или vqmovn.

person Exophase    schedule 25.10.2010

Нет инструкции, которая может загрузить ваше 4 8-битное значение в 4 32-битный регистр.

вы должны загрузить их, а затем дважды использовать vshl. поскольку неон не может использовать 32 регистра, вам придется работать с 8 пикселями (а не с 4)

Вы можете использовать только 16-битный регистр. должно хватить...

person Etienne    schedule 09.04.2011

Загрузите 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);
person fgp    schedule 07.08.2012