ฟังก์ชัน asm x86: 14 ไบต์ของรหัสเครื่อง
รุ่น uint64_t: 24 ไบต์
x86-64 SysV เรียกแบบแผน ( x
ในedi
), แต่รหัสเครื่องเดียวกันนี้จะทำงานในโหมด 32 บิต (ในกรณีที่lea
ประสงค์ถอดรหัสเป็นlea eax, [edi + eax*2]
, ซึ่งจะช่วยให้ผลเหมือนกัน )
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 ไบต์
นี่คือเอาท์พุทคอมไพเลอร์จากการใช้หน้ากากที่ยอดเยี่ยมของ xnor เมื่อคิดในทางตรงกันข้าม (และคำศัพท์ตรงข้าม: บิตต่ำคือบิต 0 ซึ่งเป็นเลขคู่ไม่แปลก)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
ฉันไม่พบการปรับปรุงใด ๆ เกี่ยวกับสิ่งที่คอมไพเลอร์ทำ ฉันอาจจะเขียนมันเป็นmov eax, 0x555...
/ and eax, edi
แต่นั่นคือความยาวเท่ากัน
ฟังก์ชั่นเดียวกันสำหรับจำนวนเต็ม 64 บิตใช้เวลา 24 ไบต์ (ดูลิงค์ godbolt) ฉันไม่เห็นวิธีที่สั้นกว่า 10 ไบต์movabs rax, 0x55...
ในการสร้างรูปแบบในการลงทะเบียน ( div
คำสั่งของ x86 นั้น clunky ดังนั้นการหารที่ไม่ได้รับการลงนามของทุกคนด้วย 3 จึงไม่ได้ช่วย)
ฉันขึ้นมาพร้อมกับวนรอบเพื่อสร้างมาสก์ใน rax แต่มันมีขนาด 10 ไบต์ (ความยาวเท่ากันกับ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
...
หากเรารู้ว่าไม่มีไบต์ที่มีอยู่ในrax
ชุดบิตต่ำของพวกเขาเราสามารถข้ามxor
และนี่จะมีความยาว 8 ไบต์
รุ่นก่อนหน้าของคำตอบนี้มีห่วง 10 ไบต์ใช้loop
insn แต่มันมีความเลวร้ายที่สุดกรณีระยะเวลาของการทำซ้ำเพราะผมตั้งเท่านั้น0xFFFFFFFFFFFFFF08
cl