x86 asm-Funktion: 14 Byte Maschinencode
uint64_t version: 24 bytes
x86-64-SysV-Aufrufkonvention ( x
in edi
), aber dieser Computercode funktioniert auch im 32-Bit-Modus. (Wobei der lea
Wille als dekodiert lea eax, [edi + eax*2]
, was identische Ergebnisse ergibt ).
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
Dies ist die Compiler-Ausgabe , wenn die einmalige Masken-Idee von xnor umgekehrt verwendet wird. (Und entgegengesetzte Terminologie: Das niedrige Bit ist Bit 0, das gerade und nicht ungerade ist.)
unsigned onemask_even(unsigned x) {
unsigned emask = ~0U/3;
unsigned e = (x & emask);
return e*2 + ((x - e) >> 1);
}
Ich habe keine Verbesserungen gegenüber dem Compiler gefunden. Ich hätte es vielleicht als mov eax, 0x555...
/ geschrieben and eax, edi
, aber das ist die gleiche Länge.
Dieselbe Funktion für 64-Bit-Ganzzahlen benötigt 24 Byte (siehe Godbolt-Link). Ich sehe keinen Weg, der kürzer als 10 Byte ist movabs rax, 0x55...
, um die Maske in einem Register zu erzeugen. (Die div
Anweisung von x86 ist klobig, daher hilft eine Division der Einsen durch drei ohne Vorzeichen nicht.)
Ich habe mir eine Schleife ausgedacht, um die Maske in Rax zu generieren, aber es sind 10 Bytes (genau die gleiche Länge wie die 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
...
Wenn wir wüssten, dass keines der vorhandenen Bytes rax
sein niedriges Bit gesetzt hat, könnten wir das überspringen xor
, und dies wäre 8 Bytes lang.
Eine frühere Version dieser Antwort hatte eine 10-Byte-Schleife mit dem loop
Befehl insn, aber die Laufzeit der 0xFFFFFFFFFFFFFF08
Iterationen war im schlimmsten Fall , da ich nur festgelegt habe cl
.