0xDEADBEEF

RSS odkazy
««« »»»

ulong -> float

5. 11. 2021 #x86 #protip #low level

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:

píše k47 (@kaja47, k47)