Funkcja asm x86: 14 bajtów kodu maszynowego
wersja uint64_t: 24 bajty
Konwencja wywoływania SysV x86-64 ( x
in edi
), ale ten sam kod maszynowy będzie również działał w trybie 32-bitowym. (Gdzie lea
dekoduje jako lea eax, [edi + eax*2]
, co daje identyczne wyniki ).
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 bajtów
Jest to wynik kompilatora wynikający z zastosowania doskonałej idei maski xnor - kiedyś w odwrotny sposób. (I przeciwna terminologia: niski bit to bit 0, który jest parzysty, a nie nieparzysty.)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
Nie znalazłem żadnych ulepszeń w stosunku do kompilatora. Mógłbym napisać to jako mov eax, 0x555...
/ and eax, edi
, ale to ta sama długość.
Ta sama funkcja dla liczb całkowitych 64-bitowych zajmuje 24 bajty (patrz łącze godbolt). Nie widzę krótszego niż 10 bajtów sposobu movabs rax, 0x55...
na wygenerowanie maski w rejestrze. ( div
instrukcja x86 jest nieporęczna, więc niepodpisany podział wszystkich przez 3 nie pomaga).
Wymyśliłem pętlę, aby wygenerować maskę w rax, ale ma ona 10 bajtów (dokładnie takiej samej długości jak 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
...
Gdybyśmy wiedzieli, że żaden z istniejących bajtów rax
nie ma ustawionego niskiego bitu, moglibyśmy pominąć ten xor
, a miałby on długość 8 bajtów.
Poprzednia wersja tej odpowiedzi miała 10-bajtową pętlę używającą loop
insn, ale miała najgorszy czas wykonywania 0xFFFFFFFFFFFFFF08
iteracji, ponieważ ja tylko ustawiłem cl
.