加载8bit uint8_t为uint32_t?
-
01-10-2019 - |
题
我的图像处理项目可与灰度图像一起使用。我有ARM Cortex-A8处理器平台。我想利用霓虹灯。
我有一个灰度图像(请考虑下面的示例),在我的alogorithm中,我只需添加列。
我如何加载 四个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-porn/
- http://blogs.arm.com/software-enablement/196-coding-for-neon-part-2-dealing-with-leftovers/
- http://blogs.arm.com/software-enablement/241-coding-for-neon-part-3-matrix-multiplication/
- http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-hifting-left-and-right/
让你开始。然后,您可以使用Inline Assembler或Domen推荐的相应的ARM内在物质实现SIMD代码。
其他提示
取决于您的编译器和(可能缺乏)扩展。
IE。对于GCC,这可能是一个起点: http://gcc.gnu.org/onlinedocs/gcc/arm-neon-intrinsics.html
如果您需要总结480个8位值,那么从技术上讲,您将需要17位中间存储。但是,如果您分两个阶段进行添加,即,前240行,则可以进行底部240行,则可以分别以16位进行操作。然后,您可以添加两半中的结果以获取最终答案。
实际上,有一个适合您的算法称为VADDW的霓虹灯指令。它将在QWORD向量中添加DWORD向量,后者包含的元素是前者的两倍。在您的情况下,vaddw.u8可用于将8个像素添加到8个16位蓄能器中。然后,VADDW.U16可用于将两组8个16位蓄能器添加到一组8 32位的累加器中 - 请注意,您必须使用两次指令才能获得两半。
如有必要,您还可以使用VMOVN或VQMOVN将值转换回16位或8位。
没有指示可以将您的4 8位值加载到4 32位寄存器中。
您必须加载它们,然后使用VSHL两次。因为霓虹灯不能使用32个寄存器,您必须在8个像素上工作(而不是4个像素)
您只能使用16bits寄存器。应该足够...
使用单车道负载指令加载4个字节(vld1 <register>[<lane>], [<address]
)进入Q-Register,然后使用两个移动的说明(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]
而是在负载指令中保存一两个周期。如果您这样做并且地址不一致,但是您会遇到错误。
嗯,我只是意识到您想使用内在的,而不是组装,所以这与Intrinsics是同一件事。
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);