假设在某个x86-64平台上,我们在某个64位寄存器中存储了一些64位值(让它成为RAX(。挑战在于在更少的指令调用中对所有初始值字节进行异或运算(将结果存储在哪里并不重要(。这是我的 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
这使用无进位乘法pclmullqlqdq
在一个指令中完成所有异值。 最后一条指令提取累积的结果并将其存储到 al
中。
支持System V x86_64 ABI(即可以直接从64b linux等中的C/C++调用(,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
可以代替获得 15B 长版本xor eax, edi
,但我会在第一个变体中保留"ax,di",以使其更明显地在做什么。
可能更快一点(根据Peter Cordes的说法,我相信他:)((但更长的机器代码和BMI2指令仅在Intel Haswell+ CPU和AMD Excavator(2015(上支持(变体(最后也使用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,否则这仍然只是第二种解决方案。