向量中的内在霓虹灯交换元素
Posted
技术标签:
【中文标题】向量中的内在霓虹灯交换元素【英文标题】:Intrinsics Neon Swap elements in vector 【发布时间】:2016-09-15 15:29:16 【问题描述】:我想使用 Neon Intrinsics 优化此类代码。基本上给定的输入
0 1 2 3 4 5 6 7 8
将产生输出,
2 1 0 5 4 3 8 7 6
void func(uint8_t* src, uint8_t* dst, int size)
for (int i = 0; i < size; i++)
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0]
dst = dst+3;
src = src+3;
我能想到的唯一方法就是使用
uint8x8x3_t src = vld3_u8(src);
获取 3 个向量,然后从 src[2]、src[1]、src[0] 访问每个元素并写入内存。
有人可以帮忙吗?
谢谢。
【问题讨论】:
可以分享示例代码吗? 我现在真的没有时间写一个完整的解决方案,但是看一下ARM文档上面的两条指令应该是不言而喻的。 【参考方案1】:这在底层指令集中非常容易,因为您正在交换 3 元素结构的两个元素,这实际上已经说明了相关指令:
vld3.u8 d0-d2, [r0]
vswp d0, d2
vst3.u8 d0-d2, [r0]
NEON Programmers Guide 中甚至还有这个确切的示例,因为它是 RGB-BGR 转换,而这正是 NEON 设计的处理类型。
使用内在函数有点棘手,因为 vswp
没有内在函数;你只需要用 C 来表达它并相信编译器会做正确的事:
uint8x8x3_t data = vld3_u8(src);
uint8x8_t tmp = data.val[0];
data.val[0] = data.val[2];
data.val[2] = tmp;
vst3_u8(dest, data);
也就是说,由于手头的编译器是各种版本的 GCC,我无法说服他们中的任何一个实际发出 vswp
- 代码生成范围从次优到愚蠢。 Clang 做得更好,但仍然没有vswp
;其他编译器可能更聪明。
【讨论】:
感谢您的回答。我使用“vld3q_u8”而不是“vld3_u8”,内在函数的结果似乎更好,但我在汇编中实现了它,但“vld3.u8 d0,d2,d4”只在每个寄存器中加载8个元素。查看引用“vld3q_u8”等效于“vld3.8d0,d2,d4” 使用vld3q_u8
内在函数一次执行 16 个元素实际上会导致 两个 vld3.u8
指令 - 即 vld3.8d0, d2, d4 [r0]!; vld3.8d1, d3, d5, [r0]
(因此最后会出现两个商店,但至少您仍然可以使用 Q 寄存器进行单次交换)。对于一些喜欢尽可能多地交替加载和存储而不是捆绑在一起的 CPU 而言,这可能最终会变得不太理想,但无论如何都要选择你机器上最快的。以上是关于向量中的内在霓虹灯交换元素的主要内容,如果未能解决你的问题,请参考以下文章
如何使用霓虹内在函数准确地将 uchar 转换为 float32 ,反之亦然