Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

23
Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel

Transcript of Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

Page 1: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

Vorlesung CompilertechnikSommersemester 2009

Zielcodeerzeugung

M. Schölzel

Page 2: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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.

Page 3: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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 + t0t3 := at4 := t2 * t3 …

Zielcode-erzeugung

Zwischen-code-

erzeugung

Programmcode

Statische Daten

Heap

Stack

Page 4: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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 := at13 := t5 + t12b := t13if t11 then goto next…

add r?,r?,r?Ziel-

register für t13 bereit-stellen

Wert von t5 in

Registerbereit-stellen

Anweisung-art identi-

fizieren undSchablone erzeugen

Registerinhalte ein-/auslagern

Wert von t12 in

Registerbereit-stellen

mov [0x1450],r4

mov r7,[0x1454]

add r0,r?,r?add r0,r4,r?add r0,r4,r7

Page 5: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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.

Page 6: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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

Page 7: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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.

Page 8: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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.

Page 9: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

9

Implementierung von getFreeReg

Eingabe: keineAusgabe: Name eines Registers, dessen Inhalt überschrieben werden kannAlgorithmus getFreeReg:Falls ein i existiert mit 1 i RegNum und rd(i) = dann return iFalls ein i existiert mit 1 i RegNum und für alle (v,x) rd(i) gilt x = r, dann rd(i) := , return iWähle ein s mit 1 s RegNum und s ist nicht gesperrtSpill(s)return s

Eingabe: Registernummer sAusgabe: Zielcode zum Auslagern des RegisterwertesAlgorithmus 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 fiodrd(s) :=

Page 10: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

10

Beispiel: getFreeReg

Aufruf: getFreeReg() mit Registerdeskriptor:

Aufruf: getFreeReg() mit Registerdeskriptor:

i rd(i)

(t0,w), (a,r)

(t2,w), (c,r)

0

1

2

(t15,w), (p,r)15…

i rd(i)

(t0,w), (t16,w)

(t1,w), (a,w)

(t2,w), (t18,w)

0

1

2

(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)

0

1

2

(t15,w), (p,r)15…

i rd(i)

(t0,w), (t16,w)

(t2,w), (t18,w)

0

1

2

(t15,w), (t31,w)15…

Page 11: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

11

Implementierung von getVarInReg

Eingabe: Variable tAusgabe: Name des Registers, in dem der Wert der Variable bereitgestellt wurdeAlgorithmus 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 fifird(s) := {(t,r)}if t ist lokal then outCode("mov [bp-sd(t)],s") else outCode("mov [sd(t)],s") fireturn s

Page 12: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

12

Beispiel: getVarInReg

Aufruf: getVarInReg(t1) mit Registerdeskriptor:

Aufruf: getVarInReg(t16) mit Registerdeskriptor:

i rd(i)

(t1,w), (b,r)

(t2,w), (c,r)

0

1

2

(t15,w), (p,r)15…

i rd(i)

(t0,w), (a,w)

(t1,w), (b,w)

(t2,w), (c,w)

0

1

2

(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)

0

1

2

(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)

0

1

2

(t15,w), (p,r)15…

Page 13: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

13

Übersetzung binärer/unärer Anweisungen

Eingabe: 3-Adress-Code-Anweisung x := y zAusgabe: ZielcodeAlgorithmus:

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 := yAusgabe: ZielcodeAlgorithmus:

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)

Page 14: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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)

0

1

2

(t15,w), (p,w)15…

Rückgabewert:

r1 für t1r0 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)

0

1

2

(t15,w), (p,w)15…

Registerdeskriptor:

locked locked

0

0

0

0

1

1

0

0

i rd(i)

(b,w)

(t2,w), (c,w)

0

1

2

(t15,w), (p,w)15…

locked

1

1

0

0

Registerdeskriptor:

Rückgabewert:

r0

Erzeugter Spillcode:Keiner

i rd(i)

(t20,w)

(b,w)

(t2,w), (c,w)

0

1

2

(t15,w), (p,w)15…

locked

0

0

0

0

Zielcode:add

r1,r0,r0

Neuer Registerdeskriptor:

Page 15: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

15

Übersetzung von Kopieranweisungen (1)

Eingabe: 3-Adress-Code-Anweisung x := y, x := k, @x := y, x := @y oder x := &yAusgabe: ZielcodeAlgorithmus:

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;

Page 16: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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)

0

1

2

(t15,w), (p,w)15…

Erzeugter Spillcode:keiner

Neuer Registerdeskriptor:

Registerdeskriptor:

locked

0

0

0

0

i rd(i)

(b,w)

(t2,w), (c,w)

0

1

2

(t15,w), (p,w)15…

locked

0

0

0

0

Registerdeskriptor:

Rückgabewert:

r0

Erzeugter Spillcode:mov [bp-sd(t1)],r0

i rd(i)

(t16,w)

(b,w)

(t2,w), (c,w)

0

1

2

(t15,w), (p,w)15…

locked

0

0

0

0

Zwischencode:

Keiner

Neuer Registerdeskriptor:

i rd(i)

(t0,w), (a,w)

(z,w), (b,w), (t20,w)

(t2,w), (c,w)

0

1

2

(t15,w), (p,w)15…

locked

0

0

0

0

Page 17: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

17

Übersetzung von Kopieranweisungen (2)

Für @x := 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 := @y: 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");

Page 18: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

18

Übersetzung von Labels und Sprunganweisungen

Eingabe: 3-Adress-Code-Anweisung label:Ausgabe: ZielcodeAlgorithmus:

SaveRegs();outCode("label:");Clear();

Eingabe: 3-Adress-Code-Anweisung goto labelAusgabe: ZielcodeAlgorithmus:

SaveRegs();outCode("jmp label");

Eingabe: 3-Adress-Code-Anweisung if x then goto lAusgabe: ZielcodeAlgorithmus:

t := getVarInReg(x);Delete(x,t)SaveRegs();outCode("BNZ t,l");

… a := t7label: t8 := a …

… a := t7 goto label10label9: …

… 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.

Page 19: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

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

Akt

ivie

rungsb

lock

der

aufg

eru

fenen F

unkt

ion

Page 20: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

20

Übersetzung eines Funktionsaufrufs

Eingabe: 3-Adress-Code-Anweisung x := call f(t1,..,tn)Ausgabe: ZielcodeAlgorithmus:

for i := n downto 1 do p := getVarInReg(ti) outCode("push p") Delete(p,ti)od// SaveRegs() erforderlich, falls call einen Basisblock abschließtoutCode("add sp,#4,sp");outCode("call f");// Clear() erforderlich, falls call einen Basisblock abschließtr := getFreeReg()outCode("pop r") // Ergebniswert ladenrd(r) := rd(r) {(x,w)} // vorausgesetzt Stack wächst zu kleineren AdressenoutCode("add sp,#4*n,sp");

int g {…x = f(3,4);…}

t0 := 3t1 := 4t2 := call f(t0,t1)x := t2…

push r3push r2add sp,#4,spcall fpop r1add sp,#8,sp

4

undefiniert

Rücksprungadresse

Aktivierungsblock der Funktion g

bp

sp

3

spsp

Quelltext Zwischencode Zielcode Laufzeitstapel

Page 21: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

21

Übersetzung einer Funktionsdeklaration

Eingabe: 3-Adress-Code-Anweisung Function Label:Ausgabe: ZielcodeAlgorithmus:

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 bpmov sp,bpadd sp,#16,sp

3 (Parameter b)

undefiniert

Rücksprungadresse

Aktivierungsblock der Funktion g

bp

4 (Parameter a)

spQuelltext Zwischencode Zielcode

bp der rufenden Fkt.sp bp

Lokale Variablen

sp

Laufzeitstapel

Page 22: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

22

Übersetzung einer return-Anweisung

Eingabe: 3-Adress-Code-Anweisung return x:Ausgabe: ZielcodeAlgorithmus:

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,sppop bpreturn

4 (Parameter b)

undefiniert

Rücksprungadresse

Aktivierungsblock der Funktion g

3 (Parameter a)

Quelltext Zwischencode Zielcode

bp der rufenden Fkt.bp

Lokale Variablen

sp

sp

15

bp

sp

Laufzeitstapel

Page 23: Vorlesung Compilertechnik Sommersemester 2009 Zielcodeerzeugung M. Schölzel.

Ende der Zielcodeerzeugung

Weiter zur Optimierung