如果您想访问x8
,那么除了有一条编码指令之外别无他法x8
作为源寄存器。因此,除了在运行时发出指令之外,我能想到的唯一基于索引的解决方案是为每个寄存器设置一个存根,并像 switch-case 一样基于索引进行分支。假设您的数组跨度为 x8 到 x15:
.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 条指令来定位每个寄存器。 :/