Função x86 asm: 14 bytes de código de máquina
Versão uint64_t: 24 bytes
Convenção de chamada x86-64 SysV ( x
pol edi
), mas esse mesmo código de máquina também funcionará no modo 32 bits. (Onde o lea
decodificará como lea eax, [edi + eax*2]
, o que dá resultados idênticos ).
0000000000000040 <onemask_even>:
40: 89 f8 mov eax,edi
42: 25 55 55 55 55 and eax,0x55555555
47: 29 c7 sub edi,eax
49: d1 ef shr edi,1
4b: 8d 04 47 lea eax,[rdi+rax*2]
4e: c3 ret
4f: <end>
0x4f - 0x40
= 14 bytes
Esta é a saída do compilador do uso da excelente idéia de máscara única do xnor da maneira oposta. (E terminologia oposta: o bit baixo é o bit 0, que é par, não é ímpar.)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
Não encontrei nenhuma melhoria sobre o que o compilador faz. Eu poderia ter escrito como mov eax, 0x555...
/ and eax, edi
, mas esse é o mesmo comprimento.
A mesma função para números inteiros de 64 bits leva 24 bytes (veja o link godbolt). Não vejo uma maneira menor que 10 bytes movabs rax, 0x55...
para gerar a máscara em um registro. (As div
instruções do x86 são desajeitadas, portanto a divisão não assinada de todos por um por três não ajuda.)
Eu criei um loop para gerar a máscara em rax, mas são 10 bytes (exatamente o mesmo comprimento que o mov imm64
).
# since 0x55 has its low bit set, shifting it out the top of RAX will set CF
0000000000000000 <swap_bitpairs64>:
0: 31 c0 xor eax,eax ; old garbage in rax could end the loop early
0000000000000002 <swap_bitpairs64.loop>:
2: 48 c1 e0 08 shl rax,0x8
6: b0 55 mov al,0x55 ; set the low byte
8: 73 f8 jnc 2 <swap_bitpairs64.loop> ; loop until CF is set
000000000000000a <swap_bitpairs64.rest_of_function_as_normal>:
# 10 bytes, same as mov rax, 0x5555555555555555
# rax = 0x5555...
a: 48 21 f8 and rax,rdi
...
Se soubéssemos que nenhum dos bytes existentes rax
tem seu bit baixo definido, poderíamos pular o arquivo xor
e isso teria 8 bytes de comprimento.
Uma versão anterior desta resposta tinha um loop de 10 bytes usando o loop
insn, mas tinha um pior tempo de execução de 0xFFFFFFFFFFFFFF08
iterações, porque eu apenas o defini cl
.