我有这个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)
所以你有零扩展半字节以大尾数顺序解压缩以打包为字节?
就像 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 次方乘法器有用。