assembly 小型阵列的最快偏移读取

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

为了提高速度,我希望读取第9个寄存器中的值所引用的8个寄存器中的一个。我认为最快的方法是使用3个条件跳转(检查第9寄存器中的3位)。这应该比用偏移存储器读取来进行此操作的标准方式具有更短的等待时间,但是这仍然需要至少6个时钟周期(至少一个测试加上每比特校验一个条件JMP)。
是否有任何商用CPU(最好是x86/x64)具有执行这种“偏移寄存器读取”的内在特性,延迟仅为一个时钟周期?
理论上,经过优化的CPU只需一次加法和一次移动就可以完成此操作,因此两个或一个时钟周期似乎很容易...架构不关心如何加快小型数组的偏移读取速度,这是不是有什么普遍原因?

dsekswqp

dsekswqp1#

把CPU寄存器当作一个数组来处理现在已经不常见了。我知道的最后一个允许这样做的架构是PDP 11,它在80年代末就消失了。为什么你不把你的数组像其他数组一样放在某个内存位置呢?
也就是说,您可以使用计算跳转,这也可以替代数据依赖关系(索引寻址模式),具有控制依赖性,因此乱序exec在开始运行使用最终RAX的代码之前甚至不必等待索引输入就绪。当然,这需要 * 正确 * 分支预测,如果索引经常变化,则不太可能发生这种情况。分支误预测会花费许多周期来完成很少的工作,但是命中L1 d缓存的加载的小延迟很容易与独立工作重叠。
吞吐量成本高于内存中的数组:一些寻址计算、一次跳转、一次移动和一个mov,而不仅仅是一个mov或者甚至是具有索引寻址模式存储器操作数。
要内联这段代码,只需将jmp *%rax替换为call *%rax,这会消耗另一个微操作;或者将ret指令替换为jmp,并将跳转表的跨距增加到8,以适应较长的编码。

# select a register from r8...r15 according to the value in rdi
select:
    lea labels-4*8(%rip),%rax # rdi = 8 is the first jump table entry
    lea (%rax,%rdi,4),%rax    # pointer to the appropriate entry
    jmp *%rax                 # computed jump

    .align 4
labels:
    mov %r8, %rax
    ret

    .align 4
    mov %r9, %rax
    ret

    .align 4
    mov %r10, %rax
    ret

    .align 4
    mov %r11, %rax
    ret

    .align 4
    mov %r12, %rax
    ret

    .align 4
    mov %r13, %rax
    ret

    .align 4
    mov %r14, %rax
    ret

    .align 4
    mov %r15, %rax
    ret

虽然这可能比三个条件跳转(取决于访问模式)要快,但肯定比不上只使用数组。
你也可以使用如下代码,假设索引是eax的,通过将索引位复制到CF、SF和PF中,然后使用一系列ALU操作来区分它们:

imul $0x4100, %eax, %eax
    lahf

    # bit 0
    mov %r8, %rax
    cmovc %r9, %rax
    mov %r10, %rcx
    cmovc %r11, %rcx
    mov %r12, %rdx
    cmovc %r13, %rdx
    mov %r14, %rbx
    cmovc %r15, %rbx

    # bit 1
    cmovs %rcx, %rax
    cmovs %rbx, %rdx

    # bit 2
    cmovp %rdx, %rax

结果在%rax中获得。由于此代码具有较高的指令级并行性并且没有分支,因此它的性能应该比上面的代码更好,除非索引几乎总是相同的。
(从this answer窃取)。

相关问题