x86 asm function: 14 byte di codice macchina
Versione uint64_t: 24 byte
x86-64 Convenzione di chiamata SysV ( x
in edi
), ma lo stesso codice macchina funzionerà anche in modalità 32 bit. (Dove lea
decodificherà come lea eax, [edi + eax*2]
, il che dà risultati identici ).
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 byte
Questo è l' output del compilatore dall'uso dell'eccellente idea di maschera di xnor, una volta al contrario. (E opposta terminologia: il bit basso è il bit 0, che è pari, non dispari.)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
Non ho trovato alcun miglioramento rispetto a quello che fa il compilatore. Potrei averlo scritto come mov eax, 0x555...
/ and eax, edi
, ma è della stessa lunghezza.
La stessa funzione per numeri interi a 64 bit richiede 24 byte (vedere il collegamento godbolt). Non vedo alcun modo inferiore a 10 byte movabs rax, 0x55...
per generare la maschera in un registro. (Le div
istruzioni di x86 sono goffe, quindi la divisione senza segno di tutti per 3 non aiuta.)
Ho creato un loop per generare la maschera in rax, ma è di 10 byte (esattamente la stessa lunghezza della 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 sapessimo che nessuno dei byte esistenti rax
ha il loro bit basso impostato, potremmo saltare il xor
, e questo sarebbe lungo 8 byte.
Una versione precedente di questa risposta aveva un loop di 10 byte che utilizzava l' loop
insn, ma aveva un tempo di esecuzione nel caso peggiore di 0xFFFFFFFFFFFFFF08
iterazioni, perché avevo impostato solo cl
.