Waarom noteren x86-64-instructies op 32-bits registers het bovenste gedeelte van het volledige 64-bits register?

In de x86-64 Tour of Intel Handleidingen , heb ik lezen

Wellicht het meest verrassende feit is dat een instructie zoals MOV EAX, EBX automatisch de bovenste 32 bits van RAX registreert.

De Intel-documentatie (3.4.1.1 Registers voor algemene doeleinden in 64-bits modus in handmatige basisarchitectuur) die bij dezelfde bron wordt geciteerd, vertelt ons:

      
  • 64-bits operanden genereren een 64-bits resultaat in het doelalgemene register.
  •   
  • 32-bits operanden genereren een 32-bits resultaat, nul uitgebreid tot een 64-bits resultaat in het doelalgemene register.
  •   
  • 8-bit en 16-bit operands genereren een 8-bit of 16-bit resultaat. De bovenste 56 bits of 48 bits (respectievelijk) van het bestemmingsalgemene register kunnen niet door de bewerking worden gewijzigd. Als het resultaat van een 8-bits of 16-bits bewerking is bedoeld voor 64-bits adresberekening, moet u het register expliciet ondertekenen tot de volledige 64-bits.
  •   

In x86-32 en x86-64 assembly, 16 bit instructies zoals

mov ax, bx

laat dit soort 'vreemd' gedrag niet zien dat het bovenste woord van eax op nul wordt gezet.

Dus: wat is de reden waarom dit gedrag werd geïntroduceerd? Op het eerste gezicht lijkt het onlogisch (maar de reden kan zijn dat ik gewend ben aan de eigenaardigheden van de assemblage van x86-32).

79
Als u Google gebruikt voor "Gedeeltelijke registratie kraam", vindt u nogal wat informatie over het probleem dat zij (bijna zeker) probeerden te vermijden.
toegevoegd de auteur Jerry Coffin, de bron
toegevoegd de auteur Hans Passant, de bron
@HansPassant, de cirkelvormige referentie begint.
toegevoegd de auteur kchoi, de bron
toegevoegd de auteur Peter Cordes, de bron
Niet alleen "meest". AFAIK, alle instructies met een r32 bestemming operand zero de high 32, in plaats van samenvoegen. Sommige assemblers vervangen bijvoorbeeld pmovmskb r64, xmm met pmovmskb r32, xmm , waardoor een REX wordt opgeslagen, omdat de 64bit-bestemmingsversie zich identiek gedraagt. Hoewel de sectie Bediening van de handleiding alle 6 combinaties van 32/64bit dest en 64/128/256b-bron afzonderlijk, dupliceert de impliciete nul-uitbreiding van het r32-formulier de expliciete nul-extensie van de r64-vorm. Ik ben nieuwsgierig naar de HW-implementatie ...
toegevoegd de auteur Peter Cordes, de bron

2 antwoord

Ik ben geen AMD of spreek voor hen, maar ik had het op dezelfde manier gedaan. Omdat het op nul stellen van de hoge helft geen afhankelijkheid creëert van de vorige waarde, zou de cpu moeten wachten. Het registerherbenamingsmechanisme zou in wezen worden verslagen als het niet op die manier zou zijn gedaan. Op deze manier kun je snelle 32bit-code schrijven in 64-bits modus zonder de afhankelijkheden altijd expliciet te hoeven onderbreken. Zonder dit gedrag zou elke 32-bits instructie in de 64-bits modus moeten wachten op iets dat eerder was gebeurd, hoewel dat hoge deel bijna nooit zou worden gebruikt.

Het gedrag voor 16-bits instructies is de vreemde. De afhankelijkheidswaanzin is een van de redenen dat 16bit-instructies nu worden vermeden.

64
toegevoegd
@Bilow ja, vanwege het register hernoemen kan het niet alleen een gedeeltelijke schrijven doen, de oude hoge bytes bevinden zich nog niet in het nieuwe fysieke register, dus moeten ze worden gekopieerd, wat betekent dat de bewerking moet wachten tot die waarde is geproduceerd. Er bestaat enige bedriegerij die dit vermijdt, bijvoorbeeld door het lage gedeelte te hernoemen alsof het op zichzelf bestond, en vervolgens wanneer de dword wordt gelezen en er een gescheiden laag deel is, voeg dan een μop in om de delen samen te voegen. De meeste Intel-μarchen doen dat, behalve Netburst. AMD doet dat niet.
toegevoegd de auteur harold, de bron
@Alex, oh ik begrijp het. OK. Ik denk niet dat het vanuit dat perspectief vreemd is. Alleen al vanuit een "terugblik, misschien was het niet zo'n goed idee" -perspectief. Ik denk dat ik duidelijker had moeten zijn :)
toegevoegd de auteur harold, de bron
@Alex ja dat hebben ze bewaard, maar ik begrijp je punt niet ..
toegevoegd de auteur harold, de bron
@Alex bij de introductie van de 32-bits modus, was er geen oud gedrag voor het hoge gedeelte. Er was geen hoog gedeelte voor ... Natuurlijk kon het daarna niet meer worden veranderd.
toegevoegd de auteur harold, de bron
Ik denk niet dat het raar is, ik denk dat ze niet te veel wilden breken en het oude gedrag daar hielden.
toegevoegd de auteur Alexey Frunze, de bron
Ik had het over 16-bits operanden, waarom de bovenste bits in dat geval niet op nul worden gesteld. Ze doen dit niet in niet-64-bits modi. En dat wordt ook in de 64-bits modus bewaard.
toegevoegd de auteur Alexey Frunze, de bron
Ik interpreteerde uw "Het gedrag voor 16-bit instructies is het vreemde" als "het is vreemd dat nul-extensie niet gebeurt met 16-bit operanden in 64-bit modus". Vandaar mijn opmerkingen over het op dezelfde manier houden in de 64-bit modus voor een betere compatibiliteit.
toegevoegd de auteur Alexey Frunze, de bron
De logica voor 16-bit-opdrachten kan zijn: "Als we de compatibiliteit en dus afhankelijkheid van de bits 16-31 van de vorige registerwaarde moeten behouden, zullen de opschoonbits 32-63 ons niet redden. Dus laat deze opheffing helemaal weg." Dit is sowieso niet de meest x86-64-raarheid.
toegevoegd de auteur Netch, de bron
Waarom zou de CPU moeten wachten? Omdat het de twee nutteloze bovenste bytes zou moeten lezen om het hele register te schrijven?
toegevoegd de auteur Bilow, de bron

Het bespaart eenvoudigweg ruimte in de instructies en de instructieset. U kunt kleine directe waarden verplaatsen naar een 64-bits register met behulp van bestaande (32-bits) instructies.

Het bespaart u ook van het coderen van 8 bytewaarden voor MOV RAX, 42 , wanneer MOV EAX, 42 kan worden hergebruikt.

Deze optimalisatie is niet zo belangrijk voor 8 en 16 bit ops (omdat ze kleiner zijn), en het veranderen van de regels daar zou ook oude code doorbreken.

8
toegevoegd
Ik heb instructies gezien zoals mov (rax), rax waarbij beide operanden rax zijn. Wat betekent het om mov te coderen van rax naar rax ? Ik voel dat de haakjes hier een speciale betekenis hebben.
toegevoegd de auteur Nawaz, de bron
In x32 assembly is dit waar de MOVZX-instructie voor is. Dus ik geloof niet dat dit het laatste antwoord is.
toegevoegd de auteur Nubok, de bron
@Nawas - (rax) , of [rax] , afhankelijk van de assembler, is vergelijkbaar met verwijzingsinterferentie, dus laadt het een waarde van het adres in rax en vervang de aanwijzer door de geladen waarde.
toegevoegd de auteur Bo Persson, de bron
@Damien - Waarschijnlijk niet. AMD verzamelde veel statistieken van bestaande programma's bij het ontwerpen van de x64-instructieset. Eén doel was om het zo compact mogelijk te houden, om te besparen op de grootte van het programma (rekening houdend met cache en geheugenbandbreedte).
toegevoegd de auteur Bo Persson, de bron
Sign extensie is langzamer, zelfs in hardware. Nuluitbreiding kan parallel worden uitgevoerd met elke berekening die de onderste helft oplevert, maar tekenuitbreiding kan niet worden gedaan totdat (ten minste het teken van) de onderste helft is berekend.
toegevoegd de auteur Jerry Coffin, de bron
@Alex: nee, dat is het niet. Het zou wat langzamer zijn als het in de software zou worden gedaan, zeker, maar in hardware kost het in het ergste geval nog een paar transistors, wat op een chip de grootte en de complexiteit van een moderne CPU is, dat is echt geen probleem.
toegevoegd de auteur jalf, de bron
@Alex: En sign-extension is dat niet? Beide kunnen heel goedkoop in hardware worden gedaan.
toegevoegd de auteur jalf, de bron
Als dat klopt, zou het dan niet verstandiger zijn geweest om het te ondertekenen, uit te breiden in plaats van 0 uit te breiden?
toegevoegd de auteur Damien_The_Unbeliever, de bron
@Nubok: Natuurlijk, ze hadden een codering van movzx/movsx kunnen toevoegen die een onmiddellijk argument opeist. Meestal is het meer handig om de bovenste bits op nul te zetten, dus je kunt een waarde gebruiken als een array-index (omdat alle regs dezelfde grootte moeten hebben in een effectief adres: [ rsi + edx] is niet toegestaan). Natuurlijk is het vermijden van valse afhankelijkheden/partial-register-boxen (het andere antwoord) een andere belangrijke reden.
toegevoegd de auteur Peter Cordes, de bron
@jalf zero-extension is goedkoper dan sign-extension, niet veel, maar toch.
toegevoegd de auteur Alexey Frunze, de bron
@Damien_The_ Unbeliever Mogelijk. Maar zero-extension is extreem goedkoop.
toegevoegd de auteur Alexey Frunze, de bron
Een andere gerelateerde truc is om XOR EAX, EAX te gebruiken omdat XOR RAX, RAX een REX-voorvoegsel nodig zou hebben.
toegevoegd de auteur Neil, de bron