0xDEADBEEF

RSS odkazy
««« »»»

Kolik registrů má x86?

29. 8. 2020 #CPU

To je přece snadné, má jich 16: RAX až R16.

Ano, šestnáct obecných (general purpose) registrů a k tomu pár dalších: zastaralé x87 a MMX, vektorové XMM, YMM a ZMM registry, AVX512 masky, debug registry, segmentové registry, FLAGS a další specializované, kterým nikdy nemůžu porozumět. V budoucnu k nim ještě přibude AMX, pokud tedy kilobajtu paměti stále můžeme říkat registr.

To ale není celá pravda. Ty nahoře vyjmenované jsou architektonické registry definované ISA, které přeložený program může přímo jmenovat a používat. Uvnitř každého out-of-order procesoru, který sjel z výrobních linek za posledních ±20 letech, se nachází mnohem víc fyzických registrů.

Zen 2 z dílny AMD disponuje 180 integer registry a 160 floating point registry o šířce 256 bitů. Intelí Cascade Lake má pod kapotou 180 int a 168 FP registrů.

Důvodem pro bohatou sadu vnitřních registrů neviditelných zvenku je pochopitelně out-of-order exekuce. Aby mohly být některé operace prováděny spekulativně, procesor nemůže starý výsledek, k němuž se možná bude muset vrátit v případě chybných odhadů, jednoduše přepsat. Spekulativní operace zapíše výsledek do jiného fyzického registru, přičemž se tváří, že to je daný architektonický registr v dané spekulativní budoucnosti. O mechanismech out-of-order procesorů jsem tu psal už dřív.

Přemapování je důvod proč přesun z registru do registru má (v určitých případech) nulovou latenci. Operace nikdy nedojde na backend, je vyřízena v jednotce, která má na starosti o mapování logických registrů na fyzické. Změní se pointer, žádná data se nepřesouvají.

Agner Fog nedávno objevil zajímavé chování v procesorech Zen 2, kdy kombinace store + load instrukcí do/ze stejné adresy mají velice malou latenci. Podle dostupných informací to vypadá na něco zcela nového. Zen 2, když zapíše do paměti (resp. přidá data do store queue pro zapsání od L1 cache později), zároveň je zapíše do jednoho fyzického registru a udržuje mapování mezi adresou a registrem. Při čtení sleduje, zdali program nevyžaduje právě tu proměnnou a pokud ano, poskytne ji z registru s nulovou prodlevou, namísto několika taktů, kolik by trvalo čtení z L1 cache.

Jde tedy o jakousi formu virtuálního rozšíření počtu registrů. Určitá malá část paměti se z hlediska výkonu tváří jako další registry. To se hodí, když jich program potřebuje hodně, ale kompilátor je nedokáže (nebo nemá čas, pokud jde o JIT) alokovat na 16 architektonických a musí udělat spill na zásobník.

Materiály AMD naznačují, že podobný mechanismus omezený na paměť zásobníku a registr RSP byl přítomen už v prvním Zenu. („Memory File for Store to Load Forwarding“) V druhé generaci (dle Angerových tabulek) to využijí jen některé jednoduché instrukce (MOV, ADD, SUB, ADC, SBB, INC, DEC, NEG, AND, OR, XOR, NOT), ale jde o obecný mechanismus, který se netýká jen zásobníku. V podstatě jde o cachování 8B paměti v jednom z pár stovek fyzických registrů. Ty jsou na čipu přítomné tak jako tak a ne vždy musejí být ideálně využité. Ne každý kód dokáže spekulovat dvě stě instrukcí dopředu. Tohle může být způsob, jak je využít v případě, kdy by jinak ležely ladem a dále to komplikují odpověď na otázku kolik má x86 registrů.


Poznámky & odkazy:

píše k47 (@kaja47, k47)