加载8bit uint8_t作为uint32_t?

时间:2010-09-09 09:58:26

标签: arm neon intrinsics cortex-a

我的图像处理项目适用于灰度图像。我有ARM Cortex-A8处理器平台。我想利用NEON。

我有一个灰度图像(考虑下面的例子),在我的算法中,我只需要添加列。

如何将四个8位像素值并行加载到 uint8_t ,将四个uint32_t 加载到其中一个位NEON寄存器?我必须使用什么内在的东西?

我的意思是:

alt text

我必须将它们加载为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) 

5 个答案:

答案 0 :(得分:11)

答案 1 :(得分:5)

取决于您的编译器和(可能缺少)扩展。

IE中。对于海湾合作委员会来说,这可能是一个起点:http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html

答案 2 :(得分:3)

如果您需要总计480个8位值,那么技术上需要17位中间存储。但是,如果您分两个阶段执行添加,即前240行然后下240行,则可以每个16位执行。然后你可以添加两半的结果来得到最终答案。

实际上有一个适合你的算法的NEON指令叫做vaddw。它会将双向量添加到qword向量中,后者包含的元素宽度是前者的两倍。在您的情况下,vaddw.u8可用于向8个16位累加器添加8个像素。然后,vaddw.u16可用于将两组8个16位累加器添加到一组8个32位累加器中 - 请注意,必须使用该指令两次才能得到两半。

如有必要,您还可以使用vmovn或vqmovn将值转换回16位或8位。

答案 3 :(得分:2)

没有指令可以将4 8bit值加载到4个32位寄存器中。

您必须加载它们然后再使用vshl两次。 因为霓虹灯不能使用32个寄存器,你必须工作8个像素(而不是4个)

您只能使用16位寄存器。它应该够了......

答案 4 :(得分:0)

使用单通道加载指令(vld1 <register>[<lane>], [<address])将4个字节加载到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);