Fungsi as86 x86: 14 byte kode mesin
versi uint64_t: 24 byte
x86-64 SysV calling convention ( x
in edi
), tetapi kode mesin yang sama ini juga akan berfungsi dalam mode 32bit. (Di mana lea
akan memecahkan kode sebagai lea eax, [edi + eax*2]
, yang memberikan hasil yang identik ).
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
Ini adalah keluaran kompiler dari penggunaan ide topeng-sekali xnor yang sangat baik sebaliknya. (Dan terminologi yang berlawanan: bit rendah adalah bit 0, yang genap, tidak aneh.)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
Saya tidak menemukan perbaikan apa pun yang dilakukan oleh kompiler. Saya mungkin menulisnya sebagai mov eax, 0x555...
/ and eax, edi
, tapi itu panjangnya sama.
Fungsi yang sama untuk integer 64bit membutuhkan 24 byte (lihat tautan godbolt). Saya tidak melihat cara yang lebih pendek dari 10-byte movabs rax, 0x55...
untuk menghasilkan topeng dalam register. ( div
Instruksi x86 adalah kikuk, sehingga pembagian yang tidak ditandatangani oleh semua oleh 3 tidak membantu)
Saya memang datang dengan loop untuk menghasilkan topeng di rax, tapi 10 byte (panjangnya persis sama dengan 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
...
Jika kita tahu bahwa tidak ada byte yang ada dalam rax
set bit yang rendah, kita bisa melewatkan xor
, dan ini akan menjadi 8 byte.
Versi sebelumnya dari jawaban ini memiliki loop 10 byte menggunakan loop
insn, tetapi memiliki 0xFFFFFFFFFFFFFF08
iterasi run-time terburuk , karena saya hanya mengatur cl
.