我有一个循环,进行一些计算,然后将符号位存储到 vector 中:
uint16x8_t rotate(const uint16_t* x);
void compute(const uint16_t* src, uint16_t* dst)
{
uint16x8_t sign0 = vmovq_n_u16(0);
uint16x8_t sign1 = vmovq_n_u16(0);
for (int i=0; i<16; ++i)
{
uint16x8_t r0 = rotate(src++);
uint16x8_t r1 = rotate(src++);
// pseudo code:
sign0 |= (r0 >> 15) << i;
sign1 |= (r1 >> 15) << i;
}
vst1q_u16(dst+1, sign0);
vst1q_u16(dst+8, sign1);
}
在该伪代码之后的 NEON 中累积符号位的最佳方法是什么?
Here's what I came up with:
r0 = vshrq_n_u16(r0, 15);
r1 = vshrq_n_u16(r1, 15);
sign0 = vsraq_n_u16(vshlq_n_u16(r0, 15), sign0, 1);
sign1 = vsraq_n_u16(vshlq_n_u16(r1, 15), sign1, 1);
另外,请注意,“伪代码”实际上是有效的,并且在性能方面几乎生成相同的代码。这里有什么可以改进的?注意,在实际代码中,循环中没有函数调用,因此我整理了实际代码以使其易于理解。
另一点:在 NEON 中,不能将变量用于 vector 移位(例如
i
不能用于指定移位数)。 最佳答案
ARM可以在一个 vsri
指令中完成此操作(感谢@ Jake'Alquimista'LEE)。
给定要从中获取符号位的新 vector ,将每个元素的低15位用累加器右移1。
您应该按2展开,这样编译器就不需要mov
指令将结果复制回相同的寄存器,因为vsri
是2个操作数的指令,在这里我们使用它的方式可以使我们得到不同的结果比旧的sign0
累加器注册。
sign0 = vsriq_n_u16(r0, sign0, 1);
// insert already-accumulated bits below the new bit we want
插入15次之后(或者如果从
sign0 = 0
开始而不是剥离第一个迭代并使用sign0 = r0开始,则为16),sign0
的所有16位(每个元素)将是r0
值中的符号位。先前的建议:与 vector 常数AND隔离符号位。它比两类制效率更高。
您使用VSRA进行累加以转移累加器并添加新位的想法很好,因此我们可以保留该累加器,最多减少2条指令。
tmp = r0 & 0x8000; // VAND
sign0 = (sign0 >> 1) + tmp; // VSRA
或使用 NEON 内在函数:
uint16x8_t mask80 = vmovq_n_u16(0x8000);
r0 = vandq_u16(r0, mask80); // VAND
sign0 = vsraq_n_u16(r0, sign0, 1); // VSRA
您可以根据需要使用内在函数或asm来实现,并以相同的方式编写标量版本,以使编译器有更好的机会进行自动向量化。
这确实需要寄存器中的 vector 常量。如果您对寄存器的要求非常严格,那么2个移位可能会更好,但是除非ARM芯片通常在SIMD桶形移位器上花费大量房地产,否则总计3个移位似乎会成为移位器吞吐量的瓶颈。
在这种情况下,可以使用这种通用SIMD想法,而无需ARM shift + accumulate或shift + insert
tmp = r0 >> 15; // logical right shift
sign0 += sign0; // add instead of left shifting
sign0 |= tmp; // or add or xor or whatever.
这会给您以相反顺序的位。如果您可以按相反的顺序生产它们,那就太好了。
否则,ARM是否具有SIMD位反转或仅用于标量? (以相反的顺序生成并在最后翻转它们,为每个 vector 位图做一些额外的工作,希望只有一条指令。)
更新:是的,AArch64具有
rbit
,因此您可以反转一个字节中的位,然后按字节顺序将它们按正确的顺序排列。 x86可以使用pshufb
LUT对两个4位块中的字节进行位反转。但是,随着您在x86上的积累,这可能无法做更多的工作。关于c++ - 在 ARM NEON 中有效地积累符号位,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49918746/