以更少的指令对 64 位寄存器中的所有字节进行 XOR

XOR all bytes in 64 bit register in fewer instructions

假设在一些 x86-64 平台上我们有一些 64 位值存储在一些 64 位寄存器中(让它成为 RAX)。挑战是 XOR 在更少的指令调用中初始值的所有字节(结果存储在哪里并不重要)。这是我的 8 指令解决方案(在 NASM 中):

mov    rbx, rax
bswap  rbx
xor    eax, ebx
mov    ebx, eax
bswap  ebx
xor    ax, bx
mov    bx, ax
xor    al, bh

我在ASM编程方面不是很有经验,所以也许你们在指令量方面有更好的解决方案。 谢谢!

这个怎么样?

        movq xmm0,rax
        pclmullqlqdq xmm0,[mask]
        pextrb eax,xmm0,7


mask    dq 0101010101010101h, 0

这使用 carry-less 乘法 pclmullqlqdq 在一条指令中执行所有异或运算。最后一条指令提取累加结果存入al.

这是支持 System V x86_64 ABI(即可直接从 C/C++ 在 64b linux 等中调用),5 条指令(16 字节)(ret 除外)。

; input: rdi = 8x packed byte, output al = xorred value
xorAllRdiBytes:
    shld    rax, rdi, 32
    xor     eax, edi
    shld    edi, eax, 16
    xor     ax, di
    xor     al, ah
    ret

并且 xor ax,di 可以改为 xor eax, edi 以获得 15B 长版本,但我将在第一个变体中保留 "ax, di" 以使其更清楚它在做什么。

可能会快一点(根据 Peter Cordes 的说法,我相信他:))(但只有 Intel Haswell+ CPUs 和 AMD Excavator (2015) 支持更长的机器代码和 BMI2 指令)变体(最后也使用 32b xor):

; input: rdi = 8x packed byte, output al = xorred value
xorAllRdiBytes:
    rorx    rax, rdi, 32
    xor     eax, edi
    rorx    edi, eax, 16
    xor     eax, edi
    xor     al, ah
    ret

(第一个变体仅使用 80386 条指令,因此任何 x86_64 CPU 都会 运行 那个)

我猜 fuz 的 3 (2) 条指令可能稍微快一点,所以除非您正在优化代码大小,或者您没有 SSE4.1,否则这仍然只是第二种解决方案。