Die Antwort von @ jalf deckt die meisten Gründe ab, aber es gibt ein interessantes Detail, das nicht erwähnt wird: Der interne RISC-ähnliche Kern ist nicht dafür ausgelegt, einen Befehlssatz wie ARM / PPC / MIPS auszuführen. Die x86-Steuer wird nicht nur in den stromhungrigen Decodern gezahlt, sondern bis zu einem gewissen Grad im gesamten Kern. dh es ist nicht nur die x86-Befehlskodierung; Es ist jede Anweisung mit seltsamer Semantik.
Stellen wir uns vor, Intel hätte einen Betriebsmodus erstellt, in dem der Anweisungsstrom etwas anderes als x86 war, mit Anweisungen, die direkter auf uops abgebildet wurden. Stellen wir uns auch vor, dass jedes CPU-Modell für diesen Modus eine eigene ISA hat, sodass sie die Interna jederzeit ändern können, wenn sie möchten, und sie mit einer minimalen Anzahl von Transistoren für die Befehlsdecodierung dieses alternativen Formats belichten können.
Vermutlich haben Sie immer noch nur die gleiche Anzahl von Registern, die dem x86-Architekturstatus zugeordnet sind, sodass x86-Betriebssysteme diese auf Kontextschaltern speichern / wiederherstellen können, ohne den CPU-spezifischen Befehlssatz zu verwenden. Aber wenn wir diese praktische Einschränkung aufheben, könnten wir ja noch ein paar Register haben, weil wir die versteckten temporären Register verwenden können, die normalerweise für Mikrocode 1 reserviert sind .
Wenn wir nur alternative Decoder ohne Änderungen an späteren Pipeline-Stufen (Ausführungseinheiten) haben, hätte diese ISA immer noch viele x86-Exzentrizitäten. Es wäre keine sehr schöne RISC-Architektur. Keine einzelne Anweisung wäre sehr komplex, aber ein Teil der anderen Verrücktheit von x86 wäre immer noch da.
Beispiel: Links- / Rechtsverschiebungen lassen das Überlauf-Flag undefiniert, es sei denn, die Verschiebungszahl ist eins. In diesem Fall ist OF = die übliche Vorzeichenüberlauferkennung. Ähnliche Verrücktheit für Rotationen. Die exponierten RISC-Anweisungen können jedoch Flag-freie Verschiebungen usw. bereitstellen (sodass nur ein oder zwei der mehreren Uops verwendet werden können, die normalerweise in einigen komplexen x86-Anweisungen enthalten sind). Dies ist also nicht das Hauptgegenargument.
Wenn Sie einen völlig neuen Decoder für eine RISC-ISA erstellen möchten, können Sie Teile von x86-Anweisungen auswählen, die als RISC-Anweisungen verfügbar gemacht werden sollen. Dies verringert die x86-Spezialisierung des Kerns etwas.
Die Befehlskodierung hätte wahrscheinlich keine feste Größe, da einzelne Uops viele Daten enthalten können. Viel mehr Daten als sinnvoll, wenn alle Insns gleich groß sind. Ein einzelnes mikrofusioniertes UOP kann einen 32-Bit-Sofort- und einen Speicheroperanden hinzufügen, der einen Adressierungsmodus mit 2 Registern und einer 32-Bit-Verschiebung verwendet. (In SnB und höher können nur Einzelregister-Adressierungsmodi mit ALU-Operationen mikrosicher werden.)
Uops sind sehr groß und ARM-Anweisungen mit fester Breite nicht sehr ähnlich. Ein 32-Bit-Befehlssatz mit fester Breite kann jeweils nur 16-Bit-Befehle sofort laden. Das Laden einer 32-Bit-Adresse erfordert daher ein Paar mit sofortiger Last, niedriger Hälfte und hoher Höhe. x86 muss das nicht tun, was dazu beiträgt, dass es nicht schrecklich ist, wenn nur 15 GP-Register die Fähigkeit einschränken, Konstanten in Registern zu halten. (15 ist eine große Hilfe gegenüber 7 Registern, aber ein erneutes Verdoppeln auf 31 hilft viel weniger, ich denke, einige Simulationen wurden gefunden. RSP ist normalerweise kein allgemeiner Zweck, daher ähnelt es eher 15 GP-Registern und einem Stapel.)
TL; DR Zusammenfassung:
Wie auch immer, diese Antwort läuft darauf hinaus, "der x86-Befehlssatz ist wahrscheinlich der beste Weg, um eine CPU zu programmieren, die in der Lage sein muss, x86-Befehle schnell auszuführen", wirft aber hoffentlich etwas Licht auf die Gründe.
Interne UOP-Formate im Front-End vs. Back-End
Siehe auch Mikrofusions- und Adressierungsmodi für einen Fall von Unterschieden in den Front-End- und Back-End-UOP-Formaten auf Intel-CPUs.
Fußnote 1 : Es gibt einige "versteckte" Register, die als temporäre Register per Mikrocode verwendet werden können. Diese Register werden genau wie die x86-Architekturregister umbenannt, sodass Multi-UOP-Anweisungen nicht in der richtigen Reihenfolge ausgeführt werden können.
Beispiel: xchg eax, ecx
Auf Intel-CPUs werden 3 Uops dekodiert ( warum? ), und wir vermuten, dass dies MOV-ähnliche Uops sind, die dies tun tmp = eax; ecx=eax ; eax=tmp;
. In dieser Reihenfolge, weil ich die Latenz der dst-> src-Richtung bei ~ 1 Zyklus messe, gegenüber 2 für die andere Richtung. Und diese Bewegungen sind keine normalen mov
Anweisungen. Sie scheinen keine Kandidaten für die Eliminierung von Bewegungen ohne Latenz zu sein.
Unter http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ wird auch erwähnt, dass versucht wird, die PRF-Größe experimentell zu messen, und dass physische Register berücksichtigt werden müssen, die zum Halten des Architekturstatus verwendet werden, einschließlich versteckter Register.
Im Front-End nach den Decodern, jedoch vor der Ausgabe- / Umbenennungsphase, in der Register in die physische Registerdatei umbenannt werden, verwendet das interne UOP-Format Registernummern, die den x86-Registrierungsnummern ähneln, jedoch Platz zum Adressieren dieser versteckten Register bieten.
Das UOP-Format ist innerhalb des nicht in Ordnung befindlichen Kerns (ROB und RS), auch bekannt als Back-End (nach der Ausgabe- / Umbenennungsphase), etwas anders. Die physischen int / FP-Registerdateien haben jeweils 168 Einträge in Haswell , daher muss jedes Registerfeld in einem UOP breit genug sein, um so viele zu adressieren.
Da der Renamer in der HW vorhanden ist, ist es wahrscheinlich besser, ihn zu verwenden, als statisch geplante Anweisungen direkt an das Back-End zu senden. Wir würden also mit einer Reihe von Registern arbeiten, die so groß sind wie die x86-Architekturregister + Mikrocode-Provisorien, nicht mehr.
Das Back-End ist so konzipiert, dass es mit einem Front-End-Renamer arbeitet, der WAW / WAR-Gefahren vermeidet. Daher könnten wir es nicht wie eine in Ordnung befindliche CPU verwenden, selbst wenn wir dies wollten. Es gibt keine Verriegelungen, um diese Abhängigkeiten zu erkennen. Dies wird durch Ausgabe / Umbenennung behandelt.
Es könnte ordentlich sein, wenn wir Uops in das Back-End einspeisen könnten, ohne den Engpass der Problem- / Umbenennungsphase (der engste Punkt in modernen Intel-Pipelines, z. B. 4-breit bei Skylake vs. 4 ALU + 2 Lade- + 1 Speicherports in) das Backend). Aber wenn Sie das getan haben, können Sie Code nicht statisch planen, um die Wiederverwendung von Registern zu vermeiden und auf ein Ergebnis zuzugreifen, das noch benötigt wird, wenn ein Cache-Miss eine Last für längere Zeit blockiert.
Wir müssen also so ziemlich Uops in die Issue / Rename-Phase einspeisen und wahrscheinlich nur die Dekodierung umgehen, nicht den UOP-Cache oder die IDQ. Dann erhalten wir normale OoO-Execs mit vernünftiger Gefahrenerkennung. Die Registerzuordnungstabelle dient nur zum Umbenennen von 16 + einigen Ganzzahlregistern in die Ganzzahl-PRF mit 168 Einträgen. Wir konnten nicht erwarten, dass die HW einen größeren Satz logischer Register in dieselbe Anzahl physischer Register umbenennt. das würde eine größere RAT erfordern.