swi*_*one 12 c assembly bit-manipulation arm64 swar
假设我有两个uint16_t[4]数组,a并且b. 这些数组中的每个整数都在 [0, 16383] 范围内,因此未设置第 14 和 15 位。a[i]然后我有一些代码来查找每个b[i]之间的最小值和最大值i:
uint16_t min[4], max[4];
for (int i = 0; i < 4; i++) {
if (a[i] < b[i]) {
min[i] = a[i];
max[i] = b[i];
} else {
min[i] = b[i];
max[i] = a[i];
}
}
Run Code Online (Sandbox Code Playgroud)
假设由于某种原因我不能/不会使用 SIMD,但我仍然想在 64 位平台上尽可能快地计算它。因此,一个自然的解决方案是在 64 位寄存器上使用 SIMD 寄存器内 (SWAR) 范例,在单次迭代中计算这 4 个值,而不是使用 16 位算术进行超过 4 次迭代。
可以使用哪些位操作技巧来使用 SWAR 范例来实现(最小或最大)或理想情况下这两种操作,以便生成的代码比上面的循环更快?我的目标架构是 ARMv8,因此请随意使用任何有助于减少指令数量的 ARMv8 指令。
C、汇编或 C+ 内联汇编解决方案都受欢迎。
您可以使用这样的代码,尽管它实际上比仅使用 SIMD 长很多:
orr x2, x0, #0x8000800080008000 // x2 = 0x8000 | x0
sub x2, x2, x1 // x2 = (0x8000 | x0) - x1
and x2, x2, #0x8000800080008000 // x2 = x0 < x1 ? 0x0000 : 0x8000
mov x3, #0x7fff7fff7fff7fff
add x2, x3, x2, lsr #15 // x2 = x0 < x1 ? 0x7fff : 0x8000
eor x4, x0, x1 // x4 = x0 ^ x1
and x3, x4, x2 // x3 = x0 < x1 ? x0 ^ x1 : 0x0000
eor x4, x1, x3 // x4 = x0 < x1 ? x0 : x1
eor x3, x0, x3 // x3 = x0 < x1 ? x1 : x0
Run Code Online (Sandbox Code Playgroud)
该算法的关键路径有6条指令。说明
mov x3, #0x7fff7fff7fff7fff
eor x4, x0, x1 // x4 = x0 ^ x1
Run Code Online (Sandbox Code Playgroud)
不在关键路径上。如果在循环中执行,则恒定负载可能会被提升。最后两条指令可以独立评估,以相同的延迟产生最小值和最大值。
| 归档时间: |
|
| 查看次数: |
409 次 |
| 最近记录: |