我有这个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)
1条答案
按热度按时间b4qexyjb1#
所以你有零扩展的半字节解压缩在big-endian顺序打包成字节?
就像strtol for hex -> integer,经过一些初始处理,将ASCII十六进制数字Map到它们表示的整数数字。
对于您想要从偶数位置打包字节的原始设置,
UZP1
,但您也可以优化shift/orr步骤。而不是2x ushl + orr的第一个块,也许是
shl v10.8h, v6.8h, #12
/orr
来获得奇数元素中想要的字节,垃圾(未修改)偶数元素。(从0开始计数,0a
元素,因为我认为您正在以最低有效位优先顺序编写向量,其中较宽的左移位将数据向右移动跨越字节边界)。sli v6.8h, v6.8h, #12
**(Shift-Left and Insert,其中位在左移创建零的位置保持其原始值。)对于打包步骤,
UZP2
应该将奇数向量元素(从1开始)打包到低8个字节中。(如果使用相同的向量作为两个源操作数,则在高8个字节中重复。)字符串
(我注意到你有一个
e0
字节。(0xe0 as u16) << 12
移出位变成0,如果这不是0x0e
的错别字的话)如果这是跨半字节对的顺序,则这会使数据保持big-endian字节顺序。**在打包时,您可能需要使用字节混洗
tbl
或uzp2
**将顺序反转为uint64_t
。或者如果您一次只对一个数字执行此操作(所以加载一个shuffle-control常量需要另一条不能从循环中提升出来的指令)可能是uzp2
之后的rev64 v10.8b, v10.8b
。或者是rev64
和v10.16b
在向量的两半中做两个u64整数。对于字节对的打包,右移和
usra
乘以#4
的累加也可以在一条指令中完成(移位和累加),因为当设置位不重叠时,ORR、ADD和插入是等效的。但它会给你给予0xba
而不是0xab
,将第二个字节向下移位以成为U8.rev16
+usra
的高半部分将起作用,但是shl
+orr
也是2个指令并且可能更便宜,可能至少在一些CPU上运行更多的执行单元。sli
甚至更好,谢谢@fuz。没有
usla
。乘法累加可以与2的幂乘法器一起使用,但在某些CPU上可能比shl
+orr
慢,并且需要一个向量常数。当然比sli
更糟糕。