Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Vorlesung Compilertechnik Sommersemester 2008 Optimierung M. Schölzel.

Ähnliche Präsentationen


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

1 Vorlesung Compilertechnik Sommersemester 2008 Optimierung M. Schölzel

2 2 Einbettung der Optimierung in den Compiler Gründe für die Optimierung: Vom Frontend generierter Zwischencode ist ineffizient, da er aus der Struktur des Quellprogramms entstanden ist und sich nicht an der Zielarchitektur orientiert. Programmierer schreiben "verbesserungsfähigen" Quellcode. Parser Quell- text Scanner Zwischen code und Symbol- tabelle Zwischen code und Symbol- tabelle Ziel- code Zielcode- erzeugung Zielcodeunab- hängige Optimierungen Kontext- prüfung Zielcodeabhängige Optimierungen Frontend Backend

3 3 Klassifizierung der Optimierung Eliminierung redun- danter Berechnungen, Berechnung konstanter Ausdrücke, Codeverschiebung LokalGlobal Maschinenunabhängig Maschinenabhängig Registerplanung Eliminierung redun- danter Berechnungen, Berechnung konstanter Ausdrücke Registerplanung, Zielcodeauswahl

4 4 Grundbegriffe (1) S = (N,E,q,s) sei ein Steuerflussgraph. N = {b 0,…,b n } sind die Basisblöcke im Steuerflussgraphen, wobei ir 0 (b i ),…,ir #(b i ) (b i ) die Folge der 3-Adress-Code-Anweisungen in b i ist. Über b 0 = q wird S betreten und über b 1 = s (z.B. return ) verlassen. Eine Programmposition ist ein Tupel (i,j) wobei damit die Position unmittelbar vor der 3-Adress-Code-Anweisung ir j (b i ) gemeint ist. Mit (0,0) wird Startposition und mit (1,0) Stoppposition bezeichnet. Ein Pfad im Steuerflussgraphen von Programmposition (i,j) zur Programmposition (m,n) ist eine Folge 0,…, k von 3-Adress-Code- Anweisungen, für die gilt: 0 … k kann in 3-Adress-Code-Folgen 0 … c = 0 … k zerlegt werden, so dass: z = ir 0 (b a z )…ir #(b a z ) (b a z ) für 1 z < c und ( 0 = ir j (b a 0 )…ir #(ba 0 ) (b a 0 ) und c = ir 0 (b a c )…ir n-1 (b a c ) falls c > 0) oder ( 0 = ir j (b a 0 )…ir n-1 (b a 0 ) falls c = 0) und (b a 0, b a 1 ),(b a 1, b a 2 ),…,(b a c-1, b a c ) E

5 5 Grundbegriffe (2) Verwendung einer Variablen v: Eine Variable v wird in der Zwischencodeanweisung ir i (j) verwendet, falls ir i (j) eine der Formen x := v, x := v, x := y v, x := v y, := x, return v, if v then goto label, x := (Type) v, x := call f(…,v,…) hat. Definition einer Variablen v: Eine Variable v wird in der Zwischencodeanweisung ir i (j) definiert, falls ir i (j) eine der Formen v := … hat. Eine definierende Anweisung für v ist eine Anweisung, die v definiert. Eine verwendende Anweisung für v ist eine Anweisung, die v verwendet.

6 6 Copy/Constant Propagation Ersetze die Verwendung der Variablen y in einer Anweisung ir i (j) durch z falls: auf allen Pfaden von Programmposition (0,0) zur Programmposition (j,i), eine Anweisung ir n (m) = "y := z" existiert und es auf allen Pfaden von Positionen (m,n+1) zur Position (j,i) keine definierende Anweisung für y und z gibt. Nach der Ersetzung kann es sein, dass die Variable y nicht mehr benutzt wird. z darf eine Variable (copy propagation) oder Konstante (constant propagation) sein. Constant Folding: Ersetze Zwischencodeanweisungen der Form x := y z bzw. x := z durch x := k, falls y und z konstant sind und k das Ergebnis der Operation ist. t0 := 7 x := t0 t1 := x t2 := y t3 := t1 + t2 z := t3 t0 := 8 y := t0 t1 := x t2 := y t3 := t1 + t2 z := t3 t0 := y t1 := x t0 := 7 x := 7 t1 := 7 t2 := 8 t3 := z := 15 t0 := 8 y := 8 t1 := x t2 := 8 t3 := t1 + 8 x := t3 t0 := 8 t1 := x …

7 7 Dead-Code Elimination Eine Zwischencodeanweisung ir i (j) = "x := e" kann aus dem Zwischencode entfernt werden, falls für alle Programmpositionen (m,n) an denen x verwendet wird und alle Pfade von (j,i+1) nach (m,n) gilt: x wird auf diesen Pfaden definiert. Dabei ist e ein beliebiger Ausdruck des Zwischencodes oder kein Pfad von (0,0) nach (j,i) existiert. Es kann neuer Dead-Code entstehen. t0 := 7 x := 7 t1 := 7 t2 := 8 t3 := z := 15 t0 := 8 y := 8 t1 := x t2 := 8 t3 := t1 + 8 x := t3 t0 := 8 t1 := x … x := 7 z := 15 y := 8 t1 := x t3 := t1 + 8 x := t3 t0 := 8 t1 := x …

8 8 Global Common-Subexpression Elimination Die Zuweisung ir i (j) = "x := e" mit dem Ausdruck e kann durch x := t ersetzt werden, falls: auf allen Pfaden von Programmposition (0,0) zur Programmposition (j,i), eine Anweisung ir n (m) = "y := e" existiert und es auf allen Pfaden von Positionen (m,n) zur Position (j,i) keine definierenden Anweisungen für die Verwendungen in e gibt und an allen Positionen (m,n+1) die Anweisung "t := y" eingefügt wird. Es entstehen neue Kopierbefehle. j := j +1 y := 4 * i x := 6 * j m := 5 * y n := 6 * j x := x * 5 i := i + 1 n := 6 * j m := i + 1 j := j +1 y := 4 * i x := 6 * j x' := x m := 5 * y n := x' x := x * 5 i := i + 1 n := 6 * j m := i + 1

9 9 Global Code Motion Es sei L die Menge der Knoten des Steuerflussgraphen, die auf einem Zykel liegen und d L der einzige Knoten der nicht zu L gehört und eine Kante zu einem Knoten in L besitzt. Eine Anweisung ir i (j) = "x := e" kann im Block b j L durch x := t ersetzt und am Ende des Blocks d t := e eingefügt werden, falls kein Block in L eine Definition einer Verwendung in e enthält. Es entstehen neue Kopierbefehle. j := j +1 y := 4 * i x := 6 * j x' := x m' := 5 * y m := m' n := x' x := x * 5 i := i + 1 n := 6 * j m := i + 1 j := j +1 y := 4 * i x := 6 * j x' := x m := 5 * y n := x' x := x * 5 i := i + 1 n := 6 * j m := i + 1

10 10 Strength-Reduction in Schleifen Suchen einer Variablen x (Induktionsvariablen), die in jedem Schleifendurchlauf um eine Konstante c erhöht wird. Suchen nach einer Berechnung y := f(x), wobei f(x + c) – f(x) = dx Statt f(x) in jeder Iteration zu berechnen, wird in jeder Iteration zu y dx addiert. j := j +1 y := 4 * i x := 6 * j x' := x m := 5 * y n := x' z := x * i i := i + 2 n := 6 * j m := i + 1 j := j +1 y := 4 * i x := 6 * j x' := x m := 5 * y n := x' x'' := x * i z := x'' t := 2 * x x'' := x'' + t i := i + 2 n := 6 * j m := i + 1

11 11 Datenflussanalyse Beobachtung: In den meisten Beispielen wurden Informationen der folgenden Art genutzt: auf allen Pfaden zur Programmposition (j,i) existiert eine Anweisung der Art … und auf allen Pfaden zwischen diesen Anweisungen und der Position (j,i) existiert keine Anweisung der Art …. … t3 := t1 + t2 … t0 := t1 – t9 … t2 := t3 * t5 … Erzeugt eine Information I Zerstört die Information I Information I gilt noch Information I gilt auch hier… … und hier… … und hier. Information I gilt hier nicht mehr. Information I gilt hier auch nicht mehr.

12 12 Grundprinzip der Datenflussanalyse Informationen I breiten sich entweder mit oder gegen den Steuerfluss aus. Für jeden Basisblock b gibt es: Eingehenden Informationen: in(b), ausgehende Informationen: out(b), erzeugte Informationen: gen(b), zerstörte Informationen: kill(b). Abhängig von der Ausbreitungsrichtung der Informationen sind: Vorwärtsanalyse: in(b) = out(b 1 ) out(b 2 ) … out(b n ), wobei die b i die Steuerflussvorgänger von b sind und out(b) = (in(b) – kill(b)) gen(b) (Transferfunktion genannt) Rückwärtsanalyse: out(b) = in(b 1 ) in(b 2 ) … in(b n ), wobei die b i die Steuerflussnachfolger von b sind und in(b) = (out(b) – kill(b)) gen(b) (Transferfunktion genannt) Durch den Steuerflussgraphen wird eine Mengengleichungssystem definiert. Falls der Steuerflussgraph Zyklen enthält, ist das Mengengleichungssystem rekursiv; Lösung durch Fixpunktiteration.

13 13 Beispiel: Reaching Definitions Bei Verwendung einer Programmvariablen an Position (i,j) interessiert, an welchen Programmpositionen der Wert der Variablen definiert wurde. Menge aller Informationen: (( ) V) Vorwärtsanalyse mit := gen(b i ) := {((i,j),v) | ir j (i) ist letzte Definition von v in b i } kill(b i ) := {((m,n),v) | m, n und b i enthält eine Definition von v} t0 := a t1 := b t2 := t0 + t1 t0 := t2 – t0 t0 := b t3 := t2 t4 := t3 * t2 t2 := t2 – t4 in(b 2 ) = in(b 3 ) = in(b 4 ) = in(b 1 ) = gen(b 3 ) = {((3,1),t0)} kill(b 3 ) = {((m,n),t0)} gen(b 4 ) = {((4,0),t3), ((4,1),t4), ((4,2),t2)} kill(b 4 ) = {((m,n),t3), ((m,n),t4), ((m,n),t2)} gen(b 2 ) = {((2,0),t0), ((2,1),t1), ((2,2),t2)} kill(b 3 ) = {((m,n),t0), ((m,n),t1), ((m,n),t2)} out(b 0 ) = out(b 2 ) = out(b 3 ) = out(b 4 ) = {((2,0),t0), ((2,1),t1), ((2,2),t2)} {((4,0),t3), ((4,1),t4), ((4,2),t2)} {((3,1),t0)} {((4,0),t3), ((4,1),t4), ((4,2),t2)} {((2,0),t0), ((2,1),t1), ((2,2),t2)} {((3,1),t0)} {((4,0),t3), ((4,1),t4), ((4,2),t2)} {((2,0),t0), ((2,1),t1), ((2,2),t2)} {((2,1),t1), ((2,2),t2), ((3,1),t0)} {((2,0),t0), ((2,1),t1)} {((4,0),t3), ((4,1),t4), ((4,2),t2)} {((2,0),t0), ((2,1),t1), ((2,2),t2)} {((4,0),t3), ((4,1),t4), ((4,2),t2)} {((2,1),t1), ((2,2),t2), ((3,1),t0), ((2,0),t0), ((4,0),t3), ((4,1),t4), ((4,2),t2)} b2b2 b3b3 b4b4 b1b1 b0b0

14 14 Anwendung Reaching Definition Erkennung der Benutzung einer Variablen vor ihrer Definition. Definiere out(b 0 ) := {((0,0),v) | v hat Verwendung im Steuerflussgraph}. Berechne Reaching Definitions. Falls bei einer Verwendung von v die Information ((0,0),v) vorhanden ist, dann kann es einen Pfad zu dieser Verwendung geben, auf dem v nicht initialisiert wird.

15 15 Beispiel: Lebendige Variablen An einer Programmposition (i,j) interessiert für eine Variable v, ob es einen Pfad zu einer Programmposition gibt, an der v verwendet wird, ohne auf diesem Pfad definiert zu werden. Menge aller Informationen: (V) Rückwärtsanalyse mit := gen(b i ) := {v | ir j (i) ist Verwendung von v und für alle 0 k < j gilt: ir k (i) ist keine Defintion von v} kill(b i ) := {v | v wird in b i definiert} t0 := a t1 := b t2 := t0 + t1 t0 := t2 – t0 t0 := b t3 := t2 t4 := t3 * t2 t2 := t2 – t4 gen(b 3 ) = {b, t2, t0} kill(b 3 ) = {t0} gen(b 4 ) = kill(b 4 ) = gen(b 2 ) = {a,b} kill(b 2 ) = {t0,t1,t2} gen(b 4 ) = {t2} kill(b 4 ) = {t2,t3,t4} in(b 0 ) = in(b 2 ) in(b 2 ) = (in(b 3 ) in(b 4 ) – kill(b 2 )) gen(b 2 ) in(b 3 ) = (in(b 1 ) – kill(b 3 )) gen(b 3 ) in(b 4 ) = ((in(b 4 ) in(b 1 )) – kill(b 4 )) gen(b 4 ) b2b2 b3b3 b4b4 b1b1 b0b0

16 16 Anwendung Lebendige Variablen Registerallokation: Treffen der Spill-Entscheidung in Basisblöcken. Bestimmung der zu sichernden Variablen am Ende eines Basisblocks. Globale Registerallokation durch Graphfärbung: Konstruktion eines Interferenzgraphen Variablen sind Knoten Eine Kante zwischen zwei Knoten existiert gdw. es eine Programmposition gibt, an der beide Variablen lebendig sind. Färbung des Interferenzgraphen liefert eine Registerallokation (Jede Farbe entspricht einem Prozessorregister). Details…

17 17 Beispiel: Reaching Copies An einer Position (i,j) interessiert, ob auf allen Pfaden von (0,0) nach (i,j) eine Anweisung x := y liegt und auf allen Pfaden von diesen Anweisungen nach (i,j) weder x noch y definiert werden. Menge aller Informationen: ({x := y | x ist Variable, y ist Variable oder Konstante}) Vorwärtsanalyse mit := gen(b i ) := {x := y | nach ir j (i) = "x := y" folgt keine Definition von x oder y in b i } kill(b i ) := {x := y, y := x | b i enthält eine Definition von x und y ist Konstante oder Variable} Ist an einer Programmposition ir j (i) = "z := e" die Information x := y verfügbar und e enthält eine Verwendung von x, dann kann x durch y ersetzt werden.

18 18 Beispiel: Available Expressions An einer Programmposition (i,j) ist ein Ausdruck e verfügbar, falls e auf allen Pfaden von Position (0,0) nach (i,j) berechnet wurde und für jeden dieser Pfade gilt, dass nach der letzten Berechnung von e die verwendeten Variablen in e bis zur Position (i,j) nicht definiert wurden. Menge aller Informationen: Menge aller Teilmengen von Ausdrücken. Vorwärtsanalyse mit :=. gen(b i ) := {e | ir j (i) = "t := e" und für alle j < k #(b i ) gilt: ir k (i) ist keine Definition einer Verwendung in e} kill(b i ) := {e | eine Verwendung in e wird in b i definiert}

19 19 Rahmenwerk zur Datenflussanalyse (DFA) DFA-Rahmenwerk: (D, I,, F) besteht aus: Der Richtung D der Analyse (vorwärts oder rückwärts) Einem Halbverband (I, ), d.h. für alle x, y, z I x x = x x y = y x x (y z) = (x y) z es ex. ein I, so dass für alle x I gilt x = x Einer Menge F, die für jeden Basisblock des Steuerflussgraphen eine Transferfunktion f : I I enthält, die monoton und stetig ist. Induzierte Ordnung auf I: x y gdw. x y = y Voraussetzungen für den Fixpunktsatz von Tarski und Knaster sind erfüllt. Damit existiert der kleinste Fixpunkt und kann durch Iteration berechnet werden, weil: (I, ) ist eine vollständig geordnete Menge, weil für alle x, y I gilt: x y ist kleinste oberer Schranke von x und y. Jedes f F ist monoton und stetig.

20 20 (I, ) ist eine geordnete Menge Reflexivität: x x gilt wegen x x = x. Antisymmetrisch: x y und y x x y = y und y x (= x y) = x x = y. Transitivität: x y und y z x y = y und y z = z z = (x y) z = x (y z) = x z x z.

21 21 (I, ) ist eine vollständig geordnete Menge Wir zeigen: Für alle x, y I ist z = x y die kleinste obere Schranke von x und y: x z x z = x (x y) = (x x) y) = x y = z. y z y z = y (x y) = y (y x) = (y y) x) = y x = x y = z. Angenommen x u und y u, dann x u = u und y u = u und z u = u u = u u = x u y u = x u y = z u z u Damit ist für jede endliche nicht leere Kette K I mit K = {k 1, k 2, k 3,…,k n } k 1 k 2 k 3 … k n die kleinste obere Schranke von K.

22 22 Fixpunktiteration Es ist der Fixpunkt einer Funktion F (out(b 0 ),…,out(b m )) = F((out(b 0 ),…,out(b m ))) bzw. (in(b 0 ),…,in(b m )) = F((in(b 0 ),…,in(b m ))) gesucht. Durch den Steuerflussgraphen wird für jede Komponente out(b i ) bzw. in(b i ) eine Mengengleichung erzeugt: Vorwärtsanalyse: out(b i ) = f i (out(b k 1 ) … out(b k n )), wobei b k 1,…,b k n die Steuerflussvorgänger von b i sind und 0 k j m. Rückwärtsanalyse: in(b i ) = f i (in(b k 1 ) … in(b k n )), wobei b k 1,…,b k n die Steuerflussvorgänger von b i sind und 0 k j m. Wir schreiben kurz: (b 0,…,b m ) = F((b 0,…,b m )) und abstrahieren von der Richtung. Die induzierte Ordnung auf I wird zu einer Ordnung auf I m+1 erweitert: (a 0,…,a m ) (b 0,…,b m ) gdw. j: 0 j m a j b j. Analog wird der Operator für einen Vektor erweitert. Unter der Voraussetzung, dass die Transferfunktionen f i monoton und stetig sind, ist es F auch (Beweis folgt).

23 23 Monotonie von F F monoton gdw. aus (a 0,…,a m ) (b 0,…,b m ) folgt F(a 0,…,a m ) F(b 0,…,b m ). a = (a 0,…,a m ) (b 0,…,b m ) = b gdw. i: a i b i. Für jedes a i und b i gilt nun: Es seien a k 1,…,a k n bzw. b k 1,…,b k n die Komponenten in a bzw. b, die den in/out-Resultaten der Steuerflussvorgänger/-nachfolger von a i bzw. b i entsprechen. Wegen a k j b k j ist a k 1 … a k n b k 1 … b k n. (Bew. durch Induktion; im Schritt: a b a b = b und a' b' a' b' = b' b b' = a b a' b' = (a a') (b b') (a a') (b b')). Wegen der Monotonie der Transferfunktion f i gilt dann f i (a k 1 … a k n ) f i (b k 1 … b k n ) Und damit F(a 0,…,a m ) F(b 0,…,b m )

24 24 Stetigkeit von F F stetig gdw. F(a 0,…,a m ) F(b 0,…,b m ) = F(a 0 b 0,…,a m b m ). Es seien a i ' und b i ' die i-ten Komponenten des Resultats von F(a) bzw. F(b), d.h.: b' i = f i (b k 1,…,b k n ) und a' i = f i (a k 1,…,a k n ) Wegen der Stetigkeit von f i gilt: a' i b' i = f i (a k 1,…,a k n ) f i (b k 1,…,b k n ) = f i (a k 1 ) … f i (a k n ) f i (b k 1 ) … f i (b k n ) = f i (a k 1 ) f i (b k 1 ) … f i (a k n ) f i (b k n ) = f i (a k 1 b k 1 ) … f i (a k n b k n ) = f i (a k 1 b k 1,…,a k n b k n ). f i (a k 1 b k 1,…,a k n b k n ) ist auch die i-te Komponente des Resultats von F(a 0 b 0,…,a m b m )

25 Ende der Optimierung Ende der Vorlesung

26 26 Beispiel Steuerflussgraph/Interferenzgraph d := 0 a := 1 c := 3 f := c d:= d+1 r := 2*d s := 3*c t := r+s e := t+5 d:= a+f u := c v := u+1 w := v+1 e := v c:= d+3 a := e*c z:= a+d (d) (a,d) (a,d,c) (a,c,f,d) (c,d) (c,d,r) (d,s,r) (d,t) (d,e) (c,d) (d,u) (d,v) (d,w) (d,e) (d,c) (d,c,a) (z) ads fcr v u w t e z

27 27 Färbung des Interferenzgraphen Gesucht Färbung I : V R mit I (u) I (v) gdw. {u,v} E, wobei R die Menge der Prozessorregister ist. Finden einer Färbung durch schrittweises Entfernen von Knoten v mit adjazenten Kanten, falls v mit echt weniger als |R| Knoten adjazent ist: Falls kein Knoten mit weniger als |R| Nachbarn existiert, dann Spillentscheidung treffen. Falls I zum leeren Graphen reduziert wurde, Einfügen der Knoten mit Kanten in umgekehrter Reihenfolge und Färben der Knoten. ad s fcr v u w t e I = (V, E), R = {0,1,2} ads fcr vuwte z z d4 d1d2d3 vuwted4zd1d2d3srcfa ads f c r vuwte z d4 d1d2d3

28 28 Spillen d := 0 a := 1 c := 3 f := c d:= d+1 r := 2*d s := 3*c t := r+s e := t+5 d:= a+f u := c v := u+1 w := v+1 e := v c:= d+3 a := e*c z:= a+d (d) (a,d) (a,d,c) (a,c,f,d) (c,d) (c,d,r) (d,s,r) (d,t) (d,e) (c,d) (d,u) (d,v) (d,w) (d,e) (d,c) (d,c,a) (z) d := := d a := 1 c := 3 f := c d1 d1:= := d1 r := 2*d s := 3*c t := r+s e := t+5 d2 := := d2 u := c v := u+1 w := v+1 e := v d3 c:= d3+3 a := e*c d4 z:= a+d (d) () (a,d) (a,c) (a,c,f) (c,d1) (c) (c,r) (s,r) (t) (e) (c,d2) (c) (u) (v) (w) (e) (d3,c) (c) (c,a) (d4) (z) Spillen von d

29 29 Auswahl der Spillvariablen Falls ein Interferenzgraph nicht weiter reduziert werden kann, dann wird aus den verbleibenden Knoten der ausgewählt, für den minimal ist. Dabei sind DefUse(v) alle Programmpositionen, an denen v verwendet/definiert wird. und deepth(p) die Schachtelungstiefe der innersten Schleife, die die Programmposition p enthält. Vor/nach allen Verwendungen/Definitionen von v wird Spillcode in den Zwischencode eingefügt. Interferenzgraph muss neu konstruiert werden. Es können mehrere solcher Iterationen erforderlich sein, bis eine Färbung des Interferenzgraphen gefunden wird. Variablen zwischen deren Definition und Verwendung keine anderen Variablen sterben, werden nicht gespillt.


Herunterladen ppt "Vorlesung Compilertechnik Sommersemester 2008 Optimierung M. Schölzel."

Ähnliche Präsentationen


Google-Anzeigen