assembly 在ARMv8(标量或 neon )中,是否有办法将寄存器文件视为数组?

dz6r00yl  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(125)

假设我有一个8 int64_t的短数组v,我有一个算法需要访问该数组的不同元素,这些元素不是编译时常量,例如v[(i + j)/2] += ...,其中ij是不受任何常量传播影响的变量。
通常我会将数组保存在内存中,计算数组索引,从内存中加载数组到该位置,然后存储结果。
但是假设,出于我不会深入讨论的合理原因,我想在寄存器中保留完整的数组--数组大小有限,适合寄存器组。
如果我只是从数组中阅读而不是写入数组,我可以使用(在ARMv 8 neon 中)TBL指令来执行表查找。
我所能想到的就是自修改代码,将数组索引直接编码到指令中并执行它。我知道这在第一次运行时会带来性能损失,但如果反复执行相同的代码,它甚至可能会起作用。
除此之外,还有什么想法吗?这可能吗?我回顾了ARMv 8架构参考手册中与指令集和编码相关的部分,到目前为止,我倾向于说不可能,但也许有人知道一个晦涩的指令或寻址模式,在这里会有所帮助。

yi0zb3m4

yi0zb3m41#

如果你想访问x8,那么除了用一条指令将x8编码为源寄存器之外,没有其他方法,所以除了在运行时发出指令之外,我能想到的唯一基于索引的解决方案是为每个寄存器提供一个存根,并像switch case一样基于索引进行分支。

.p2align 2 // maybe change this to align to cacheline size?
read_reg:
    adr x2, 1f
    add x2, x0, lsl 3
    br x2
1:
    mov x0, x8
    ret
    mov x0, x9
    ret
    mov x0, x10
    ret
    mov x0, x11
    ret
    mov x0, x12
    ret
    mov x0, x13
    ret
    mov x0, x14
    ret
    mov x0, x15
    ret

写操作也是一样的,当然这也有可能打乱分支预测,我能想到的另一个根本不使用分支的“技巧”是将csel与直接移动到nzcv系统寄存器结合起来:

.p2align 2
read_reg:
    lsl x0, x0, 28
    msr nzcv, x0
    csel x4, x8, x9, vc // bit 0
    csel x5, x10, x11, vc
    csel x6, x12, x13, vc
    csel x7, x14, x15, vc
    csel x4, x4, x5, lo // bit 1
    csel x5, x6, x7, lo
    csel x0, x4, x5, ne // bit 2
    ret

这可以扩展到最多16个寄存器。我不太确定msr的性能限制,也不确定它在某些架构上是否需要isb--至少在Apple M1上不需要。而且编写的情况也不会那么紧凑,因为您需要至少8条指令来定位每个寄存器。:/

相关问题