ulong -> float
Jakou binárku vygeneruje tenhle jednoduchý program?
float funx(ulong x) { return cast(float) x; }
Překvapivě dlouhou.
00000000000124c1 <_D5test24funxFmZf>: 124c1: c5 f8 57 c0 vxorps %xmm0,%xmm0,%xmm0 124c5: 48 85 ff test %rdi,%rdi 124c8: 78 06 js 124d0 <_D5test24funxFmZf+0xf> 124ca: c4 e1 fa 2a c7 vcvtsi2ss %rdi,%xmm0,%xmm0 124cf: c3 ret 124d0: 48 89 f8 mov %rdi,%rax 124d3: 48 d1 e8 shr %rax 124d6: 83 e7 01 and $0x1,%edi 124d9: 48 09 f8 or %rdi,%rax 124dc: c4 e1 fa 2a c0 vcvtsi2ss %rax,%xmm0,%xmm0 124e1: c5 fa 58 c0 vaddss %xmm0,%xmm0,%xmm0 124e5: c3 ret
Je to nutné, protože vcvtsi2ss
umí konvertovat pouze znaménková čísla. U ulongu (což je v případě jazyka D označení 64-bit intu) musí
kontrolovat, jestli by byla jeho binární reprezentace negativní, pokud ano
vydělí ho dvěma, půlky převede na float a pak zpátky vynásobí dvěma. Něco jako
tohle:
float funx(ulong x) { if (x & (1L << 63) == 0) { return vcvtsi2ss(x); } else { float f = vcvtsi2ss((x >> 1) | (x & 1)); return f + f; } }
Pokud ten ulong je délka nějakého pole nebo kolekce něčeho, problém to nejspíš nebude. Test je rychlý a skok bude perfektně předvídatelný. Přesto jde o pár instrukcí, které se musejí dekódovat a provést, a zabírají zdroje procesoru.
Naštěstí se to dá obejít velice jednoduše (i když to mírně změní význam).
float funx(ulong x) { return cast(float) cast(long) x; }
00000000000124c1 <_D5test24funxFmZf>: 124c1: c5 f8 57 c0 vxorps %xmm0,%xmm0,%xmm0 124c5: c4 e1 fa 2a c7 vcvtsi2ss %rdi,%xmm0,%xmm0 124ca: c3 ret
Přímo to umí převést až AVX512F, která přináší novou instrukci vcvtusi2ss
(všimněte si jednoho u v názvu navíc).
00000000000124c1 <_D5test24funxFmZf>: 124c1: c5 f8 57 c0 vxorps %xmm0,%xmm0,%xmm0 124c5: 62 f1 fe 08 7b c7 vcvtusi2ss %rdi,%xmm0,%xmm0 124cb: c3 ret
K tématu: