优化arm64的simd指令(mov),将交替字节打包成连续字节

问题描述 投票:0回答:1

我有这个V6.16b寄存器:

0a,0b,0c,0d,0e,0f,07,08,0a,0b,0c,0d,0e,0f,07,08

目标是:
ab,cd,ef,78,ab,cd,ef,78

我是这样做的:

movi v7.8h,   0x04            // 04,00,04,00,04,00,04,00,04,00,04,00,04,00,04,00
ushl v6.16b,  v6.16b,  v7.16b // a0,0b,c0,0d,e0,0f,70,08,a0,0b,c0,0d,e0,0f,70,08
movi v8.8h,   0xf8            // f8,00,f8,00,f8,00,f8,00,f8,00,f8,00,f8,00,f8,00
ushl v10.8h,  v6.8h,   v8.8h  // 0b,00,0d,00,0f,00,08,00,0b,00,0d,00,0f,00,08,00
orr  v10.16b, v10.16b, v6.16b // ab,0b,cd,0d,ef,0f,78,08,ab,0b,cd,0d,ef,0f,78,08

mov v10.b[1], v10.b[2]
mov v10.b[2], v10.b[4]
mov v10.b[3], v10.b[6]
mov v10.b[4], v10.b[8]
mov v10.b[5], v10.b[10]
mov v10.b[6], v10.b[12]
mov v10.b[7], v10.b[14] // ab,cd,ef,78,ab,cd,ef,78,ab,0b,cd,0d,ef,0f,78,08

它确实有效,但是有没有办法用更少的指令来做到这一点? (特别是mov)

macos assembly simd arm64 neon
1个回答
1
投票

所以你有零扩展半字节以大尾数顺序解压缩以打包为字节?
就像 strtol 的十六进制 -> 整数一样,经过一些初始处理将 ASCII 十六进制数字映射到它们表示的整数数字。

而不是 2x ushl + orr 的第一个块,也许

ushl v10.8h, v6.8h, #12
/
orr
可以在奇数元素中获取所需的字节,在偶数元素中获取垃圾(未修改)。 (从 0 开始计数,
0a
元素,因为我认为您正在以最低有效优先顺序编写向量,其中更宽的左移将数据跨字节边界移动到右侧)。

对于打包步骤,

UZP2
应该能够获取奇数向量元素(从 1 开始)并将它们打包到低 8 字节中。 (如果使用相同的向量作为两个源操作数,则在高 8 字节中重复。)
对于您的原始设置,您最终会在偶数位置获得所需的字节,
UZP1

如果这是半字节对之间的顺序,那么这将使您的数据保持大端字节顺序;要解决这个问题,您可能需要

tbl
,即字节洗牌,以便在打包时将顺序反转为
uint64_t


对于打包字节对,右移并通过 usra

 累加 
#4
 可以在一条指令中完成(移位和累加),因为当设置的位不重叠时,ORR 和 ADD 是等效的。但它会给你 
0xba
而不是
0xab
,将第二个字节向下移动成为 u8 的高半部分。
rev16
+
usra
可以工作,但是
ushl
+
orr
也是 2 条指令,而且可能更便宜,可能至少在某些 CPU 上运行在更多执行单元上。

没有

usla
,但是我不太了解NEON/ASIMD,也许有更好的东西。如果在某些 CPU 上速度不是太慢并且设置向量常数不会抵消其优势,那么乘法累加可能对 2 次方乘法器有用。

© www.soinside.com 2019 - 2024. All rights reserved.