Wie werden Codezeilen von der CPU ausgeführt?


11

Ich versuche wirklich zu verstehen, wie genau eine Hochsprache in Maschinencode konvertiert und dann von der CPU ausgeführt wird.

Ich verstehe, dass der Code in Maschinencode kompiliert wird, der der Low-Level-Code ist, den eine CPU verwenden kann. Wenn ich eine Zuweisungserklärung habe, sagen Sie:

x = x + 5;
y = x - 3;

Führt die CPU jede Zeile einzeln aus? Es wird also zuerst x = x + 5 ausgeführt; Befehl und dann der nächste Befehl, den die CPU ausführen wird, ist y = x-3; Ich versuche wirklich zu verstehen, wie der Ausführungsprozess ausgeführt wird und wie der von mir geschriebene Code tatsächlich von der CPU ausgeführt wird.


Vielleicht möchten Sie versuchen, das Design einer der Open-Source-CPUs zu verstehen. Es gibt einige wirklich einfache stapelbasierte Implementierungen wie excamera.com/sphinx/fpga-j1.html - sie sind viel einfacher als die 3-Adressen-Architekturen wie in deinem Beispiel.
SK-Logik

3
Als ich in dieses Geschäft eingestiegen bin, hätte dies einfache und klar definierte Antworten gehabt. Heutzutage sind CPUs extrem kompliziert und tun alles Mögliche, um die Rechenleistung zu erhöhen.
David Thornley

Antworten:


12

Die Codezeilen haben nichts damit zu tun, wie die CPU sie ausführt. Ich würde empfehlen, sich über Assembler zu informieren, da Sie dadurch viel darüber lernen, wie die Hardware tatsächlich funktioniert. Sie können auch Assembler-Ausgaben von vielen Compilern erhalten.

Dieser Code könnte in etwas kompiliert werden (in einer zusammengesetzten Assemblersprache):

load R1, [x] ; meaning load the data stored at memory location x into register 1
add R1, 5
store [x], R1 ; store the modified value into the memory location x
sub R1, 3
store R1, [y]

Wenn der Compiler jedoch weiß, dass eine Variable nicht erneut verwendet wird, wird die Speicheroperation möglicherweise nicht ausgegeben.

Damit der Debugger weiß, welcher Maschinencode einer Zeile der Programmquelle entspricht, fügt der Compiler Anmerkungen hinzu, um anzuzeigen, welche Zeile wo im Maschinencode entspricht.


Warum nicht? Eine 3-Adressen-Architektur enthält Anweisungen wie ADD Rx, Rx, $5und SUB Ry, Rx, $3(unter der Annahme, dass x- und y-Variablen in Registern abgebildet wurden). Sie beschreiben einen RISC-Ansatz zum Laden / Speichern.
SK-Logik

1
@ SK-Logik: Während dies für sehr einfache Codezeilen in sehr einfachen Programmiersprachen mit Datentypen und Operationen passieren kann , die die CPU gut genug unterstützt, ist dies nirgends der allgemeine Fall. Es ist praktisch für Experten, aber zunächst ist es wichtig zu wissen, dass die Anweisungen für den Maschinencode im Allgemeinen wenig Ähnlichkeit mit Codezeilen in einer übergeordneten Sprache haben.

@ SK-Logic: Das funktioniert nur für dieses Beispiel. Im Allgemeinen ist maxpolun jedoch richtig. Hochsprachenanweisungen müssen in eine niedrigere Sprache übersetzt werden, wobei mehr "Bürokratie" erforderlich ist, um konzeptionell einfache Dinge zu erledigen. Ich denke, das OP hat nach einem Beispiel für diese Transformation gefragt.
Andres F.

1
@ SK-Logik: begann die OP seine Frage mit „Ich versuche zu verstehen , um wirklich , wie genau eine High-Level - Sprache [...]“
Andres F.

1
@ SK-Logik Der Kontext lautet "Wenn ich eine Zuweisungsanweisung habe, sagen Sie: [Code-Snippet] Führt die CPU jede Zeile einzeln aus?" - scheint mir, dass es Quellcode in einer Nicht-Assembler-Sprache sein soll. Im Allgemeinen sehe ich keinen Hinweis auf ein Verständnis dafür, wie einfach Maschinencode ist, und einige Formulierungen (z. B. das Sprechen von Zeilen) weisen auf falsche Vorstellungen hin. Das ist nicht so unmöglich, wie Sie meinen, nicht jeder hatte das Vergnügen, mit dem Kopf voran auf einige einfache Mikrocontroller geworfen zu werden (wie ich und anscheinend andere). Vielleicht sollte Frankie das klarstellen.

2

Es hängt davon ab, ob.

In den Anfängen wirklich einfacher Maschinen wurde Code zeilenweise ausgeführt. Als die Maschinen größer, schneller und komplexer wurden, stellten Sie fest, dass sowohl mehrere Befehle gleichzeitig ausgeführt werden können als auch Lese- und Schreibvorgänge im Speicher viel länger dauern als bei Operationen an Registern.

Bei der Optimierung von Compilern musste dies berücksichtigt werden, und die von Ihnen angegebenen Zeilen konnten "mehr oder weniger" parallel ausgeführt werden, wobei ein Teil des Prozessors an der Berechnung von y arbeitete, während ein anderer Teil den zuvor berechneten neuen Wert von speicherte x (und die Berechnung von y verwendete diesen neuen Wert aus dem Register).

Die Control Data 6600 war die erste mir bekannte Maschine, die solche Dinge tat. Die Ganzzahladdition dauerte 300 ns, die Speicherreferenz (Lesen oder Schreiben) dauerte 1000 ns, Multiplikationen und Divisionen dauerten viel länger. Je nachdem, welche Funktionseinheiten benötigt wurden, konnten bis zu zehn Befehle parallel ausgeführt werden. Die CDC 6600 FORTRAN-Compiler waren sehr gut darin, all dies zu planen.


In diesem Fall hängt die Eingabe des nächsten Befehls vom ersten Befehlsergebnis ab und muss daher nacheinander ausgeführt werden.
SK-Logik

@ SK-Logik: Nicht ganz. Die Eingabe der zweiten Zeile hängt vom Ergebnis auf der rechten Seite der ersten Zeile ab, aber basierend auf dem, was wir im ursprünglichen Beispielcode sehen können, hängt sie möglicherweise NICHT von der Speicherung des Ergebnisses von ab die erste Zeile. Wenn x als flüchtig deklariert worden wäre (in C / C ++), müsste der Compiler zuerst das Ergebnis speichern und es dann aus dem Speicher neu laden, bevor er mit der Berechnung des neuen Werts von y beginnt, da "flüchtig" etwas bedeutet (z. B. ein Interrupt-Handler) könnte hereinkommen und x zwischen den beiden Zeilen zappen.
John R. Strohm

Ich nahm an, dass x und y Register sind (und der Code ist in einer Pseudoassemblierungssprache mit 3 Adressen und nicht in C). In diesem Fall sind beide Anweisungen unvermeidlich sequentiell. Andernfalls musste OP zwei oder mehr verschiedene Fragen anstelle dieser stellen.
SK-Logik

Ich frage mich, ob Prozessoren versuchen würden, den Wert von zu "spekulieren" x. Auf diese Weise hat es den Code bereits ausgeführt und im Cache gespeichert.
Kolob Canyon

Selbst wenn es sich um Register handelt, die von der Maschine abhängen, können Sie nicht davon ausgehen, dass die Anweisungen vollständig nacheinander ausgeführt werden. Der 6600 hatte eine Planungslogik (die "Anzeigetafel"), die eine sequentielle Semantik erzwingen würde, basierend auf der Annahme, dass der Programmierer das Offensichtliche tun wollte. Spätere Maschinen haben diese Hardware weggelassen und sich stattdessen darauf verlassen, dass die Compiler die Anweisungen sorgfältig planen. Menschliche Programmierer, die Assembler-Programme für diese Bestien programmierten, waren auf sich allein gestellt.
John R. Strohm

1

Nein, es gibt keine Eins-zu-Eins-Zuordnung zwischen Codezeilen / Anweisungen in höheren und niedrigeren Sprachen. Tatsächlich werden beide obigen Zeilen in mehrere Maschinencode- Anweisungen übersetzt, wie z

  1. Laden Sie einen Wert von einer bestimmten Speicheradresse in ein Register
  2. Ändern Sie den Wert
  3. schreibe es zurück in den Speicher

Die tatsächlichen Details dieser Anweisungen variieren zwischen den Plattformen.

Dies ist die Grundansicht der Dinge. Um die Probleme weiter zu verkomplizieren, wenden moderne CPUs unter anderem Techniken wie Ausführungspipelines , Ausführung außerhalb der Reihenfolge und mehrere Kerne an . Diese führen dazu, dass die CPU mehrere Dinge gleichzeitig ausführt, z. B. verarbeiten Pipelines verschiedene Phasen nachfolgender Anweisungen parallel innerhalb derselben Verarbeitungseinheit, während mehrere Kerne unabhängige Anweisungen parallel verarbeiten können.


0

Sie sollten in einem Buch ausführlich nachsehen, um weitere Informationen zur Funktionsweise zu erhalten, möglicherweise auch in einer Compiler-Klasse.

Grundsätzlich konzentriert sich Ihre Frage auf zwei verschiedene Aspekte.

1) Wie wird der Code in Maschinencode übersetzt?

2) Wann / wie wird der Code mittels Parallelisierung berechnet?

Die Antwort auf 1) hängt von der Sprache ab, die Sie verwenden (obwohl dies für Ihr Beispiel trivial ist, sodass die Ausgabe dieselbe wäre). Die Art und Weise, wie der Compiler die Übersetzung in Maschinencode durchführt, ist eine der Stärken der Sprache. Außerdem gibt es einige Bedenken, die in Ihrem Beispiel berücksichtigt werden müssen. Der Code sollte die Daten in den Speicher laden, speichern usw.

Schließlich ist Parallelisierung eine Funktion, die Sie aus programmtechnischer Sicht erzwingen können. Kurz gesagt, einige Prozessoren versuchen möglicherweise zu glauben, dass ein Teil des Codes gleichzeitig ausgeführt werden kann, da sie unabhängig sind. In Ihrem Fall ist dies natürlich nicht der Fall, da Sie die Anweisungen nacheinander ausführen müssen. Nein, sie werden nicht gleichzeitig ausgeführt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.