• Keine Ergebnisse gefunden

Praktikum Compilerbau Sitzung 10 – Codeerzeugung

N/A
N/A
Protected

Academic year: 2022

Aktie "Praktikum Compilerbau Sitzung 10 – Codeerzeugung"

Copied!
23
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktikum Compilerbau Sitzung 10 – Codeerzeugung

Lehrstuhl für Programmierparadigmen Universität Karlsruhe (TH)

1. Juli 2009

(2)

1 Letzte Woche

2 Backends

3 Scheduling

4 Vorgehen

5 Sonstiges

(3)

Letzte Woche

Was waren die Probleme?

Hat soweit alles geklappt?

(4)

Letzte Woche

Compilerphasen

Lexer Parser Semantik Zwischencodeerzeugung

Optimierung Codeerzeugung

Tokens

AST

attributierter AST

Zwischencode

Zwischencode

(5)

Aufbau eines Compilerbackends - Befehlsauswahl

Abbilden von Befehlen der Zwischensprache auf Befehle der Zielmaschiene. Meist werdenn Zwischensprachbefehle auf einen

Zielmaschinenbefehl abgebildet.

Bei uns bis auf 1 Konstrukt eine 1:1

Abbildung. (bei welchem Konstrukt haben wir n:1?)

Deshalb bei uns keine separate Codeauswahlphase!

(Codeauswahl)

Befehlsanordnung

Registerallokation

Peephole Opt.

Codeausgabe

(6)

Backends

Aufbau eines Compilerbackends - Befehlsanordnung

Bestimme abhängigkeiten zwischen Befehlen und ordne diese neu an.

Anordnungsziel: Minimiere Resourcenbedarf und nutze Hardwareeigenschaften (Pipelining) aus.

(Codeauswahl)

Befehlsanordnung

Registerallokation

Peephole Opt.

Codeausgabe

(7)

Aufbau eines Compilerbackends - Registerallokation

Behandlung von Resourcenbeschränkungen:

Register, Stackframe, etc. zuteilen.

Bei Registermangel erzeugung von Auslagerungscode.

Registerallokation bei uns nicht als separate Phase nötig (unbeschränkte Zahl von Variablen vorhanden).

(Codeauswahl)

Befehlsanordnung

Registerallokation

Peephole Opt.

Codeausgabe

(8)

Backends

Aufbau eines Compilerbackends - Peephole Optimierungen

Ersetze Muster von Zielsprachbefehlen durch billigere.

Typisches Beispiele

Jmp L1; L1:weglassen

iconst 1durchiconst_1ersetzen Ausnutzen von speziellen Adressierunsmodi Bei uns nicht (oder nur wenig) nötig.

(Codeauswahl)

Befehlsanordnung

Registerallokation

Peephole Opt.

Codeausgabe

(9)

Aufbau eines Compilerbackends - Codeausgabe

Ausgaben von Assembler oder direktes erzeugen des Maschinencodes.

Auflösen von Sprungmarken (beim direkten Erzeugen)

(Codeauswahl)

Befehlsanordnung

Registerallokation

Peephole Opt.

Codeausgabe

(10)

Scheduling

Befehlsreihenfolge in einem Grundblock

Abhängigkeiten ergeben Halbordnung der Befehle

Bilden einer Totalordnung nötig (Topologisches Sortieren) Die einfachste Möglichkeit für DAGs: Reverse Postorder (für alle Wurzeln).

(11)

Reverse Postorder

Für jede Wurzel Tiefensuche auf dem Graph, Nummern beim verlassen von Knoten vergeben.

C D

A B Call

neg *

+ M

(12)

Scheduling

Reverse Postorder

Für jede Wurzel Tiefensuche auf dem Graph, Nummern beim verlassen von Knoten vergeben.

C D

A B Call

neg *

+ M

1 2

3

4 5

6

7

8 9

(13)

Resourcenverteilung

Bytecode ist stackbasiert.

Anordnung garantiert aber nicht, dass die Operanden für jeden Befehl auf der Spitze des Stacks liegen.⇒ Ausweichen auf Variablen.

Naive Lösung: Eine Variable für jeden Firm-Knoten. Vor Operation Operanden aus Variablen laden, nach Operation Variable schreiben.

(14)

Scheduling

Verfeinerung: Erzeugen von Stackcode aus Bäumen

Erzeugung von Stackcode aus Bäumen durch Postfixform:

Für jeden Knoten, rufe Erzeugerfunktion rekursiv für alle Kinder auf und erzeuge dann die Operation.

Beispiel:

+

e f

+ +

a b

neg +

c d

Schematisch:

e f add a b add c d add

(15)

Φ-Knoten Behandlung

Teile Variablen für Φ-Knoten zu.

Am Ende der Vorgängerblöcke eines Φ-Knotens speichere Argumente in (die gleiche) Variable.

ErsetzeΦ-Knoten durch Ladebefehl für die Variable.

(16)

Scheduling

Teilgraphen mit Baumstruktur

DAGs haben aufspannende Bäume als Teilgraphen. („Bäume mit Querkanten ;-)”)

Codeerzeugung also durch Tiefensuche/Postfixform mit Sonderbehandlung der Kanten die nicht zum Baum gehören.

Diese Kanten haben mehrere Benutzer oder sind Wurzel eines

Teilbaums. Variablen nur für Knoten an einer solchen Kanten zuweisen.

(17)

Grobes Schema

Suche alle Klassen im Programm:

for(Type type : Program.getTypes()) {

if(! (typeinstanceofClassType)) {continue; } /∗ ...∗/

}

Gib für jede Klasse einen Klassenheader und Standardkonstruktor aus.

Erzeuge jasmin Definition für alle Felder und Methoden in der Klasse.

for(Entity entity : classType.getMembers()) {

if(entity.getType()instanceofMethodType) {continue; } emitField(entity);

}

for(Entity entity : classType.getMembers()) {

if(! (entity.getType()instanceofMethodType)) {continue; }

(18)

Vorgehen

Methoden: Erzeugen von Befehlslisten

BenutzeGraph.walkPostOrderum Graph in reverse Postorder zu durchlaufen. (Firm-Graph ist bereits in umgekehrter Reihenfolge) Ordne Befehle dabei in Befehlslisten ein. Eine Liste pro Block.

Achtung: Sprungbefehle sind in Firm nicht geordnet, müssen bei der Ausgabe aber als letztes im Grundblock erscheinen.

(19)

Methoden: Baumwurzeln markieren

Als Wurzel markieren und Zuteilung von Variablennummern an:

Alle Knoten mit mehreren Verwendern (BackEdge.getNOuts(node)>1) Verwender aus anderen Grundblöcken

Paramter-Projs – Paramter liegen in (vorgegebenen) Variablen Φ-Knoten benötigen eine Variable.

Vorsicht bei Proj-Knoten vonCall/Load/Store: Diese erzeugen nicht wirklich Code/Werte. Hier kommt es auf den entsprechenden mode_TKnoten an.

Als Wurzeln markieren ohne eigene Variablennummer: Store,

(20)

Vorgehen

Ausgabe

Für jeden Grundblock:

BlockXX:ausgeben

Befehlsliste durchgehen. Für Wurzelknoten Code erzeugen:

Sprungbefehle ausgeben Für Store:

pushValue(skipSel(store.getPtr()));

pushValue(store.getValue());

printf("putfield %s\n", getFieldSpec(store.getPtr()));

Sonst:createValue(node); /* emit astore/istore */

createValue(node);

String storecmd = node.getMode().isReference() ? "astore" : "istore";

printf("%sstore %d\n", storecmd, varnum);

(21)

Schema create/pushValue

private voidpushValue(Node node) { if(varAssigned(node)) {

/∗emit aload/iload varnumber ∗/

return;

}

createValue(node);

}

private voidcreateValue(Node node) { switch(node.getOpCode()) { caseiro_Const:/∗... ∗/ break;

caseiro_Add:

Add add = (Add) node;

pushValue(add.getLeft());

pushValue(add.getRight());

println("\tiadd");

(22)

Sonstiges

1 Letzte Woche

2 Backends

3 Scheduling

4 Vorgehen

5 Sonstiges

(23)

Feedback! Fragen? Probleme?

Anmerkungen?

Probleme?

Fragen?

Referenzen

ÄHNLICHE DOKUMENTE

aload_0 // Parameter0 (this) auf Stack aconst_null // null − Referenz auf den Stack putfield field:Lfield; // Schreibe Wert (null). // auf Feld field:Lfield; von Objekt(this) return

Ergebnisse werden nach der Präsentation bekannt gegeben Gewinner erhalten Ruhm und

Vereinfachung des Automaten möglich wenn man Schlüsselwörter in Stringtabelle einträgt und Regeln für IDENTIFIER benutzt. Starke Reduktion

Operatoren lassen sich dynamisch anlegen (z.B. für

Nicht jede Produktion der Grammatik muss ein eigener AST-Knoten werden. Gemeinsame Basisklassen sinnvoll wo Alternativen in der Grammatik

Lese-Tipp: „Generierung lokaler Optimierungen“ Diplomarbeit von Thomas

Korrektheit: Optimierungen sollen Semantik erhalten Effizienz: Optimierung muss auch große Programme in angemessener Zeit verarbeiten können... Optimierungen

Knoten auf Offsets im Activation Record zuweisen Phase 2 – Assembler