Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

Ähnliche Präsentationen


Präsentation zum Thema: "Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel."—  Präsentation transkript:

1 Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel

2 2 Aufgabe der Zielcodeerzeugung Erzeugung von Programmcode, der auf der gewünschten Zielarchitektur ausgeführt werden kann (oft Assemblercode). Das schließt ein: Übersetzung der Zwischencodeanweisungen in Assmeblercode (Code-Selection, Scheduling). Registerallokation. Erzeugung einer Laufzeitumgebung für das Programm. Speicherorganisation.

3 3 Einbettung der Zielcodeerzeugung in den Compiler Programmkode enthält den aus den Zwischenkodeanweisungen erzeugten Zielcode und statisch erzeugten Zielcode (z.B. Prolog zur Initialisierung der Laufzeitumgebung, Prozeduren zur dynamischen Speicherverwaltung) Erzeugung statischer Daten (globale Variablen, Konstanten) Heap speichert dynamisch erzeugte Objekte, die in einer Prozedur erzeugt werden und auch nach dem Verlassen der Prozedur erhalten bleiben sollen. Stack speichert Rücksprungadressen und lokale Variablen von Prozeduren. 3-Adress-Code t2 := t1 + t0 t3 := a t4 := t2 * t3 … Zielcode- erzeugung Zwischen- code- erzeugung Programmcode Statische Daten Heap Stack

4 4 Prinzipielles Vorgehen Für jede Anweisungsart des 3-Adress-Codes ist eine Schablone für den zu erzeugenden Zielcode bekannt. In dieser Schablone müssen noch die Speicherorte (i.Allg. Register), die die Werte der Variablen des 3-Adress-Codes enthalten, eingetragen werden. Die benötigten Werte werden durch die Registerallokation an geeigneten Orten zur Verfügung gestellt. Während der Zielcodeerzeugung wird in geeigneten Datenstrukturen dieser Speicherort mitprotokolliert. Registerallokation erzeugt auch den Zielcode zum Laden/Speichern von Registerwerten aus dem/in den Speicher. … t12 := a t13 := t5 + t12 b := t13 if t11 then goto next … add r?,r?,r? Ziel- register für t13 bereit- stellen Wert von t5 in Register bereit- stellen Anweisung- art identi- fizieren und Schablone erzeugen Registerinhalte ein-/auslagern Wert von t12 in Register bereit- stellen mov [0x1450],r4 mov r7,[0x1454] add r0,r?,r?add r0,r4,r?add r0,r4,r7

5 5 Registerallokation Ziel: Abbildung der temporären Variablen eines Zwischencodeprogramms auf eine beschränkte Anzahl von Prozessorregistern. Klassifizierung der Registerallokation: Lokal: Auf den Basisblock beschränkt. Global: Für Funktionen oder das gesamte Programm. Vorgehensweise bei der Registerallokation hängt stark von der Zielarchitektur ab: Register-/Register-Architektur oder Register-/Speicher-Architektur, 2-Adress- oder 3-Adress-Architektur, Universeller Registersatz oder Spezialregistersatz, Flache oder tiefe Registerhierarchie.

6 6 Fiktive Zielarchitektur Bei den weiteren Erläuterungen betrachten wir eine Zielarchitektur mit folgenden Eigenschaften: 32-Bit-Register: Stackpointer: sp Basepointer: bp Weitere allgemeine Register: r0,…,r15 Operationen und Bedeutung: mov rx,ry : ry := rx mov #imm, rx : rx := imm mov [addr],rx : rx := mem[addr] mov rx,[addr] : mem[addr] := rx add rx,ry,rz : rz := rx + ry add rx,#imm,rz : rz := rx + imm Dabei sind: rx, ry, rz {sp, bp, r0, …, r16}, imm ist ein 32-Bit-Wert, addr ist eine 32-Bit-Speicheradresse oder addr {sp, bp, r0, …, r16} oder addr = bp + imm

7 7 Lokale Registerallokation für 3-Adress-Register- /Register-Architektur: Verwaltungsstrukturen V ist die Menge aller Variablen im 3-Adress-Code. Registerdeskriptor rd : {0,…,RegNum – 1} (V {w,r}) speichert für jedes Register die Menge der Variablen, deren Werte sich im Register befinden sowie deren Lese-/Schreibzustand. Speicherdeskriptor: sd: V speichert für jede im Speicher abgelegte Variable die Speicheradresse (absolut für globale und relativ für lokale Variablen). Belegungssituationen der Verwaltungsstrukturen: Für jede globale Variable a ist durch sd(a) immer ein Speicherplatz festgelegt. Bei Übersetzung einer Funktion f ist außerdem für jede lokale Variable a in f durch sd(a) eine relative Adresse festgelegt. Für eine temporäre Variabel existiert kein Eintrag in rd oder sd, nur ein Eintrag in rd oder nur ein Eintrag in sd oder ein Eintrag in rd und sd. Für eine Programmvariable existiert immer ein Eintrag in sd möglicherweise auch ein Eintrag in rd; dann befindet sich der aktuelle Wert der Variablen im Register.

8 8 Hilfsfunktionen und Schnittstelle der Registerallokation Hilfsfunktionen für eine Variable v: isLocal(v) = True gdw. der Speicherplatz für v im Stapel ist. addr(v) ist die Adresse des Speicherplatzes von v oder die relative Adresse, die während des Aufbaus der Symboltabelle festgelegt wurde. getNextFreeLocalAddress(): Liefert die nächste freie relative Adresse im Stapel getFreeReg(): liefert den Namen eines Registers, in das ein neuer Wert geschrieben werden kann. getVarInReg(v): Erzeugt den erforderlichen Zielcode, um den Wert der Variablen v in einem Register bereitzustellen. lockReg(r): Verhindert, dass der Inhalt des Registers r bei folgenden Registeranforderungen ausgelagert wird. unlockReg(r): Klar setRegDeskr(r,x): Danach gilt (x,w) = rd(r) und für alle i: 1 i RegNum und i r (x,w) rd(i) und (x,r) rd(i). delete(x,r): Danach gilt: (x,w) rd(r) und (x,r) rd(r). clear(): Löscht Einträge im Speicher- und Registerdeskriptor. saveRegs(): Sichert Register im Speicher, die aktualisierte Werte von Programmvariablen enthalten.

9 9 Implementierung von getFreeReg Eingabe: keine Ausgabe: Name eines Registers, dessen Inhalt überschrieben werden kann Algorithmus getFreeReg: Falls ein i existiert mit 1 i RegNum und rd(i) = dann return i Falls ein i existiert mit 1 i RegNum und für alle (v,x) rd(i) gilt x = r, dann rd(i) :=, return i Wähle ein s mit 1 s RegNum und s ist nicht gesperrt Spill(s) return s Eingabe: Registernummer s Ausgabe: Zielcode zum Auslagern des Registerwertes Algorithmus Spill: for each (v,w) rd(s) do if sd(v) undefiniert then addr = getNextFreeLocalAddr() outCode("mov s,[bp-addr]") sd(v) := addr else if v ist global then outCode("mov s,[sd(v)]") else outCode("mov s,[bp-sd(v)]") fi od rd(s) :=

10 10 Beispiel: getFreeReg Aufruf: getFreeReg() mit Registerdeskriptor: i rd(i) (t0,w), (a,r) (t2,w), (c,r) (t15,w), (p,r)15 … i rd(i) (t0,w), (t16,w) (t1,w), (a,w) (t2,w), (t18,w) (t15,w), (t31,w)15 … Rückgabewert: r1 Erzeugter Spillcode: mov r1,[bp-sd(t1)] mov r1,[sd(a)] Neuer Registerdeskriptor:Registerdeskriptor: Rückgabewert: r1 Erzeugter Spillcode: Keiner Neuer Registerdeskriptor:Registerdeskriptor: i rd(i) (t0,w), (a,r) (t2,w), (c,r) (t15,w), (p,r)15 … i rd(i) (t0,w), (t16,w) (t2,w), (t18,w) (t15,w), (t31,w)15 …

11 11 Implementierung von getVarInReg Eingabe: Variable t Ausgabe: Name des Registers, in dem der Wert der Variable bereitgestellt wurde Algorithmus getVarInReg: if x {r,w} i :1 i RegNum und (t,x) rd(i) then retrun i fi if i :1 i RegNum und rd(i) = then s := i else if i :1 i RegNum und (v,x) rd(i): x=r then s := i else Wähle ein Register i mit geringen Kosten beim Auslagern und i ist nicht gesperrt Spill(i) s := i fi rd(s) := {(t,r)} if t ist lokal then outCode("mov [bp-sd(t)],s") else outCode("mov [sd(t)],s") fi return s

12 12 Beispiel: getVarInReg Aufruf: getVarInReg(t1) mit Registerdeskriptor: Aufruf: getVarInReg(t16) mit Registerdeskriptor: i rd(i) (t1,w), (b,r) (t2,w), (c,r) (t15,w), (p,r)15 … i rd(i) (t0,w), (a,w) (t1,w), (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … Rückgabewert: r0 Erzeugter Spillcode: mov r0,[bp-sd(t0)] mov r0,[sd(a)] mov [bp-sd(t16)],r0 Neuer Registerdeskriptor: i rd(i) (t16,r) (t1,w), (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … Registerdeskriptor: Rückgabewert: r1 Erzeugter Spillcode: Keiner Neuer Registerdeskriptor:Registerdeskriptor: i rd(i) (t1,w), (b,r) (t2,w), (c,r) (t15,w), (p,r)15 …

13 13 Übersetzung binärer/unärer Anweisungen Eingabe: 3-Adress-Code-Anweisung x := y z Ausgabe: Zielcode Algorithmus: l := getVarInReg(y); lockReg(l); r := getVarInReg(z); lockReg(r); if isTemp(y) then Delete(y,l); if isTemp(z) then Delete(z,r); t := getFreeReg(x); unlock(l); unlock(r); asmmnem := Assembleropertion für outCode("asmmnem l,r,t"); setRegDeskr(t,x) Eingabe: 3-Adress-Code-Anweisung x := y Ausgabe: Zielcode Algorithmus: r := getVarInReg(y); lookReg(r); if isTemp(y) then Delete(y,r); t := getFreeReg(); unlook(r); asmmnem := Assembleropertion für outCode("asmmnem r,t"); setRegDeskr(t,x)

14 14 Beispiel Übersetzung von t20 := t1 + t16; Aufruf von getVarInReg(t1) und getVarInReg(t16): Aufruf von getFreeReg() i rd(i) (t0,w), (a,w) (t1,w), (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … Rückgabewert: r1 für t1 r0 für t16 Erzeugter Spillcode: mov r0,[bp-sd(t0)] mov r0,[sd(a)] mov [bp-sd(t16)],r0 Neuer Registerdeskriptor: i rd(i) (t16,r) (t1,w), (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … Registerdeskriptor: locked i rd(i) (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … locked Registerdeskriptor: Rückgabewert: r0 Erzeugter Spillcode: Keiner i rd(i) (t20,w) (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … locked Zielcode: add r1,r0,r0 Neuer Registerdeskriptor:

15 15 Übersetzung von Kopieranweisungen (1) Eingabe: 3-Adress-Code-Anweisung x := y, x := := y, x oder x := &y Ausgabe: Zielcode Algorithmus: Für x := y: if ein i und ein k {r,w} ex. mit (y,k) rd(i) then rd(i) := rd(i) {(x,w)}; else i := getVarInReg(y) rd(i) := rd(i) {(x,w)}; fi if isTemp(y) then Delete(y,i) Für x := k: r := getFreeReg() outCode("mov #k,r") setRegDesk(r,x); return; Für x := &y: r := getFreeReg() if isLocal(y) then outCode("mov bp,r"); outCode("add r,#addr(y),y"); else outCode("mov #addr(y),r") setRegDesk(r,x); return;

16 16 Beispiel Übersetzung von t20 := z Übersetzung von t16 := t1 i rd(i) (t0,w), (a,w) (z,w), (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … Erzeugter Spillcode: keiner Neuer Registerdeskriptor:Registerdeskriptor: locked i rd(i) (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … locked Registerdeskriptor: Rückgabewert: r0 Erzeugter Spillcode: mov [bp-sd(t1)],r0 i rd(i) (t16,w) (b,w) (t2,w), (c,w) (t15,w), (p,w)15 … locked Zwischencode: Keiner Neuer Registerdeskriptor: i rd(i) (t0,w), (a,w) (z,w), (b,w), (t20,w) (t2,w), (c,w) (t15,w), (p,w)15 … locked

17 17 Übersetzung von Kopieranweisungen (2) := y: l := getVarInReg(x); lockReg(l); r := getVarInReg(y); unlock(l); if(isTemp(y) then Delete(y,r); if(isTemp(x) then Delete(x,l); outCode("mov r,[l]"); Für x r := getVarInReg(y); lockReg(r); l := getFreeReg() unlock(r); if(isTemp(y) then Delete(y,r); rd(l) := rd(l) {(x,w)} outCode("mov [r],l");

18 18 Übersetzung von Labels und Sprunganweisungen Eingabe: 3-Adress-Code-Anweisung label: Ausgabe: Zielcode Algorithmus: SaveRegs(); outCode("label:"); Clear(); Eingabe: 3-Adress-Code-Anweisung goto label Ausgabe: Zielcode Algorithmus: SaveRegs(); outCode("jmp label"); Eingabe: 3-Adress-Code-Anweisung if x then goto l Ausgabe: Zielcode Algorithmus: t := getVarInReg(x); Delete(x,t) SaveRegs(); outCode("BNZ t,l"); … a := t7 label: t8 := a … a := t7 goto label10 label9: … a := t7 if t8 then goto label20 b := t9 … Aktualisieren der Werte im Speicher. Einsprung von verschiedenen Position möglich; Belegung der Register unklar. Sprung zu einer Position an der der Registerdeskriptor gelöscht wird; Aktualisieren der Wert eim Speicher nötig. Hier wird die Registerallokation fortgesetzt. Sprung zu einer Position an der der Registerdeskriptor gelöscht wird; Aktualisieren der Wert eim Speicher nötig. Fortsetzung der Registeralloka- tion. Belegung der Register für jede Programmausführung fest. Kein Sichern erforderlich.

19 19 Aktivierungsblock Die Aktivierung einer Funktion durch einen Aufruf erfordert im Allgemeinen die Erzeugung eines Aktivierungsblocks im Laufzeitstapel. Möglicher Aufbau eines Aktivierungsblocks: Aktuelle Parameter Rückgabewerte Rücksprungadresse Zugriffsverweis Maschinenregister Lokale Daten Aktivierungsblock der rufenden Funktion Lokale Daten Temporäre Daten … Ausgelagerte Registerwerte im aktuellen Block Lokale Variablen im aktuellen Block Lokale Variablen in Blöcken, die den aktuellen Block enthalten Gesicherter Maschinenstatus der rufenden Funktion (z.B. Registerinhalte, Statusregister) Verweis auf den Aktivierungsblock der rufenden Funktion Adresse des rufenden call-Befehls Rückgabewert, falls vorhanden (kann sich aber auch in einem Register befinden) Aktuelle Parameter der aufgerufenen Funktion Aktivierungsblock der aufgerufenen Funktion

20 20 Übersetzung eines Funktionsaufrufs Eingabe: 3-Adress-Code-Anweisung x := call f(t1,..,tn) Ausgabe: Zielcode Algorithmus: for i := n downto 1 do p := getVarInReg(ti) outCode("push p") Delete(p,ti) od // SaveRegs() erforderlich, falls call einen Basisblock abschließt outCode("add sp,#4,sp"); outCode("call f"); // Clear() erforderlich, falls call einen Basisblock abschließt r := getFreeReg() outCode("pop r") // Ergebniswert laden rd(r) := rd(r) {(x,w)} // vorausgesetzt Stack wächst zu kleineren Adressen outCode("add sp,#4*n,sp"); int g { … x = f(3,4); … } t0 := 3 t1 := 4 t2 := call f(t0,t1) x := t2 … push r3 push r2 add sp,#4,sp call f pop r1 add sp,#8,sp 4 undefiniert Rücksprungadresse Aktivierungsblock der Funktion g bp sp 3 QuelltextZwischencodeZielcodeLaufzeitstapel

21 21 Übersetzung einer Funktionsdeklaration Eingabe: 3-Adress-Code-Anweisung Function Label: Ausgabe: Zielcode Algorithmus: outCode("push bp") outCode("mov sp,bp"); // aktuelle Parameter sind über positive Offsets // größer gleich 12 erreichbar // lokale Variablen mit negativen Offsets outCode("add sp,#frameSize,sp") int f(int a, int b) { … } … Function f: … push bp mov sp,bp add sp,#16,sp 3 (Parameter b) undefiniert Rücksprungadresse Aktivierungsblock der Funktion g bp 4 (Parameter a) sp QuelltextZwischencodeZielcode bp der rufenden Fkt. spbp Lokale Variablen sp Laufzeitstapel

22 22 Übersetzung einer return-Anweisung Eingabe: 3-Adress-Code-Anweisung return x: Ausgabe: Zielcode Algorithmus: r := getVarInReg(x) outCode("mov r,[bp+8]"); SaveRegs(); outCode("mov bp,sp"); outCode("pop bp"); outCode("return"); int f(int a, int b) { … return 15; } … return t20 … mov r5,[bp+8] mov bp,sp pop bp return 4 (Parameter b) undefiniert Rücksprungadresse Aktivierungsblock der Funktion g 3 (Parameter a) QuelltextZwischencodeZielcode bp der rufenden Fkt. bp Lokale Variablen sp 15 bp sp Laufzeitstapel

23 Ende der Zielcodeerzeugung Weiter zur OptimierungOptimierung


Herunterladen ppt "Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel."

Ähnliche Präsentationen


Google-Anzeigen