Vorlesung compilertechnik sommersemester 2009
Sponsored Links
This presentation is the property of its rightful owner.
1 / 48

Vorlesung Compilertechnik Sommersemester 2009 PowerPoint PPT Presentation


  • 90 Views
  • Uploaded on
  • Presentation posted in: General

Vorlesung Compilertechnik Sommersemester 2009. Optimierung M. Schölzel. Einbettung der Optimierung in den Compiler. Gründe für die Optimierung:

Download Presentation

Vorlesung Compilertechnik Sommersemester 2009

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Vorlesung CompilertechnikSommersemester 2009

Optimierung

M. Schölzel


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.

Kontext-

prüfung

Zielcodeabhängige

Optimierungen

Backend

Quell-text

Zwischencode und

Symbol- tabelle

Ziel-code

Scanner

Parser

Zielcode-

erzeugung

Zielcodeunab-

hängige

Optimierungen

Frontend


Klassifizierung der Optimierung

Eliminierung redun-

danter Berechnungen,

Berechnung konstanter

Ausdrücke

Eliminierung redun-

danter Berechnungen,

Berechnung konstanter

Ausdrücke,

Codeverschiebung

Maschinenunabhängig

Registerplanung,

Zielcodeauswahl

Registerplanung

Maschinenabhängig

Lokal

Global


Grundbegriffe (1)

  • S = (N,E,q,s) sei ein Steuerflussgraph.

  • N = {b0,…,bn} sind die Basisblöcke im Steuerflussgraphen, wobei ir0(bi),…,ir#(bi)(bi) die Folge der 3-Adress-Code-Anweisungen in bi ist.

  • Über b0 = q wird S betreten und über b1 = s (z.B. return) verlassen.

  • Eine Programmposition ist ein Tupel (i,j) wobei damit die Position unmittelbar vor der 3-Adress-Code-Anweisung irj(bi) 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= ir0(baz)…ir#(baz)(baz) für 1  z < c und

      • (0 = irj(ba0)…ir#(ba0)(ba0) und c= ir0(bac)…irn-1(bac) falls c > 0) oder (0 = irj(ba0)…irn-1(ba0) falls c = 0) und

      • (ba0, ba1),(ba1, ba2),…,(bac-1, bac)  E


Beispiel

0

3

0: Function f:

1: t0 := 1

2: fak = t0

3: while_0_cond:

4: t1 := n

5: t2 := 0

6: t3 := t1 > t2

7: t4 := not t3

8: if t4 then while_0_end

9: t5 := fak

10: t6 := n

11: t7 := t5 * t6

12: fak := t7

13: t8 := n

14: t9 := 1

15: t10 := t8 – t9

16: n := t10

17: goto while_0_cond

18: while_0_end:

19: t11 := fak

20: return t11

t0 := 1

4

fak = t0

6

t1 := n

7

t2 := 0

8

t3 := t1 > t2

9

t4 := not t3

10

if t4 then 21

11

21

t5 := fak

t11 := fak

12

22

t6 := n

f = t11

13

1

t7 := t5 * t6

return f

14

fak := t7

15

t8 := n

16

t9 := 1

17

t10 := t8 – t9

18

n := t10


Qualität des Modells

  • Steuerflussgraph modelliert alle möglichen Abarbeitungspfade des Programms, unabhängig davon, ob alle diese Pfade bei der Ausführung des Programms betreten werden können.

  • Falls Turingmaschine i auf Eingabe i nach n Schritten stoppt, dann gibt es eine Eingabe n, so dass 4 nach 2 ausgeführt wird, sonst nicht.

0

Eingabe von n

2

if (TMi(i)n) then 4

3

4

1


Grundbegriffe (2)

  • Verwendung einer Variablen v:Eine Variable v wird in der Zwischencodeanweisung iri(j) verwendet, falls iri(j) eine der Formen x := v, x :=  v, x := y v, x := v y, x := @v, @v := 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 iri(j) definiert, falls iri(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.

  • Erreichende Definition: Die Definition einer Programmvariablen v erreicht eine Verwendung von v, falls es einen Pfad im Steuerflussgraphen von dieser Definition zur Verwendung gibt, auf dem keine andere Definition von v liegt.


Beispiel Erreichende Definitionen

0

3

t0 := 1

4

fak = t0

6

t1 := n

7

0

t2 := 0

8

3

t3 := t1 > t2

t0 := 1

9

t4 := not t3

4

fak = t0

10

6

if t4 then while_0_end

t1 := n

7

11

21

t2 := 0

t11 := fak

t5 := fak

8

12

22

t3 := t1 > t2

t6 := n

kgv = t11

9

13

1

t4 := not t3

t7 := t5 * t6

return kgv

10

14

if t4 then while_0_end

fak := t7

Definition zu einer Verwendung ist in unverzweigtem Steuerfluss einfach zu finden.

15

t8 := n

16

t9 := 1

17

t10 := t8 – t9

18

n := t10

Definition zu einer Verwendung ist bei Verzweigungen im Steuerfluss schwieriger zu finden.


Grundidee Datenflussanalyse am Beispiel der Erreichenden Definitionen

Es gibt eingehende Informationen I in einen Knoten: I = in(2)

0

t2 := 2

Durch die Anweisung(en) in einem Knoten werden Informationen zerstört: I := I – Kill(2)

1

t1 := 1

in(2) = {(t2,0),(t1,1)}

Kill(2) = {(t1,i) | i }

2

t1 := n

Gen(2) = {(t1,2)}

Durch die Anweisung(en) in einem Knoten werden neue Informationen generiert: I := IGen(2)

out(2) = {(t2,0),(t1,2)}

3

t3 := t1 > t2

Es entstehen ausgehende Informationen an einen Knoten: out(2)

4

if t3 then while_0_end


Transferfunktion für einen Basisblock

  • Steuerfluss in einem Basisblock i mit den Anweisungen ir0(i),…,ir#i(i) ist bekannt.

  • Damit ist die Transferfunktion für diesen Basisblock:

  • Vereinfachung der Transferfunktion zu out(i) = (in(i) – kill(i))  gen(i).

in(i)

- Kill(0)  Gen(0)

0

t2 := 2

1

- Kill(1)  Gen(1)

t1 := 1

2

- Kill(2)  Gen(2)

t1 := n

- Kill(3)  Gen(3)

3

t3 := t1 > t2

- Kill(4)  Gen(4)

4

if t3 then while_0_end

out(i)


Datenflussanalyse bei Verzweigungen im Steuerflussgraphen

  • Ausgehende Informationen out(i) gelangen zu jedem Steuerflussnachfolger von i.

  • Treffen Informationen von mehreren Steuerflussvorgängern zusammen, müssen diese zu einer eingehenden Information zusammengefasst werden.

Transformiert eingehende Informationen

t3 := t1 + t2

Ausgehende Informationen I

I

Transformiert eingehende Informationen

I

t0 := t1 – t9

t2 := t3 * t5

Transformiert eingehende Informationen

Hier müssen Informationen kombiniert werden


Grundprinzip Datenflussanalyse

  • Informationen I breiten sich entweder mit oder gegen den Steuerfluss aus.

  • Für jeden Knoten 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(b1)  out(b2)  …  out(bn), wobei die bi die Steuerflussvorgänger von b sind und

      • out(b) = (in(b) – kill(b))  gen(b) (Transferfunktion genannt)

    • Rückwärtsanalyse:

      • out(b) = in(b1)  in(b2)  …  in(bn), wobei die bi 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.


Information Erreichende Definitionen

  • An einer Programmposition (i,j) interessiert für eine Variable v, an welchen Programmpositionen der Wert der Variablen v definiert und bis zur Position (i,j) nicht mehr verändert wurde.

  • Menge aller Informationen: (()V)

  • Vorwärtsanalyse mit  := 

  • gen(bi) := {((i,j),v) | irj(i) ist letzte Definition von v in bi}

  • kill(bi) := {((m,n),v) | m, n   und bi enthält eine Definition von v}

gen(b2) = {((2,0),t0), ((2,1),t1), ((2,2),t2)}

kill(b3) = {((m,n),t0), ((m,n),t1), ((m,n),t2)}

in(b2) =

in(b3) =

in(b4) =

in(b1) =

{((2,0),t0), ((2,1),t1), ((2,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)}

{((2,0),t0), ((2,1),t1), ((2,2),t2)}

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

b0

t0 := a

t1 := b

t2 := t0 + t1

b2

gen(b3) = {((3,1),t0)}

kill(b3) = {((m,n),t0)}

out(b0) =

out(b2) =

out(b3) =

out(b4) =

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

b3

t0 := t2 – t0

t0 := b

b4

t3 := t2

t4 := t3 * t2

t2 := t2 – t4

b1

gen(b4) = {((4,0),t3), ((4,1),t4), ((4,2),t2)}

kill(b4) = {((m,n),t3), ((m,n),t4), ((m,n),t2)}


Information 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(bi) := {v | irj(i) ist Verwendung von v und für alle 0  k < j gilt: irk(i) ist keine Definition von v}

  • kill(bi) := {v | v wird in bi definiert}

gen(b2) = {a,b}

kill(b2) = {t0,t1,t2}

b0

in(b0) = in(b2)

in(b2) = (in(b3)  in(b4) – kill(b2))  gen(b2)

in(b3) = (in(b1) – kill(b3))  gen(b3)

in(b4) = ((in(b4)  in(b1)) – kill(b4))  gen(b4)

b2

t0 := a

t1 := b

t2 := t0 + t1

gen(b4) = {t2}

kill(b4) = {t2,t3,t4}

gen(b3) = {b, t2, t0}

kill(b3) = {t0}

b3

t0 := t2 – t0

t0 := b

b4

t3 := t2

t4 := t3 * t2

t2 := t2 – t4

b1

gen(b4) = 

kill(b4) = 


Kopier- / Konstanten-Popagierung

  • Ersetze die Verwendung der Variablen y in einer Anweisung iri(j) durch zfalls:

    • auf allen Pfaden von Programmposition (0,0) zur Programmposition (j,i), eine Anweisung irn(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 := 8

y := t0

t0 := 7

x := t0

t1 := x

t2 := y

t3 := t1 + t2

z := t3

t1 := x

t2 := y

t3 := t1 + t2

z := t3

y darf durch t0 ersetzt werden

y darf nicht durch t0 ersetzt werden

t0 := y

t1 := x


Information für Kopier-/Konstanten-Propagierung

  • Berechnung der Information Erreichende Kopien RC(x) = in(x) für Knoten x im Steuerflussgraphen S = (N,E,q,s) durch eine Datenflussanalyse mit den Parametern:

    • Menge aller Informationen: ({x:=y | x:=y ist Kopierbefehl im Programm})

    • Vorwärtsanalyse mit  := 

    • gen(bi) := {x:=y | x:=y ist Zwischencodebefehl irk(bi) und in allen Zwischencodebefehlen irk+1(bi)… ir#bi(bi) wird weder x noch y definiert}

    • kill(bi) := {x:=z | x wird in Block bi definiert und x:=z ist Kopieranweisung im Programm}  {z:=x | x wird in Block bi definiert und z:=x ist Kopieranweisung im Programm}

2:

t0 := 8

y := t0

"t0:=8","y:=t0"

"t0:=8","y:=t0"

3:

t0 := 7

x := t0

t1 := x

t2 := y

t3 := t1 + t2

z := t3

4:

t1 := x

t2 := y

t3 := t1 + t2

z := t3

"t1:=x","t2:=y","z:=t3"

1:

t0 := y

t1 := x


Kopier-/Konstanten-Propagierung im Basisblock

  • In einem Basisblock b wird die Verwendung von x in Anweisung i durch y ersetzt, falls:

    • x := y in(b) und in allen Anweisungen k mit 0  k < i weder x noch y definiert werden oder

    • Anweisung j < i die Form x := y hat und in allen Anweisungen k mit j < k < i weder x noch y definiert werden.

  • Diese Ersetzung muss gegebenenfalls wiederholt werden, bis keine weiteren Ersetzungen möglich sind.

2:

t0 := 8

y := t0

2:

t0 := 8

y := 8

"t0:=8","y:=t0"

Erneute Informationssammlung ergibt, dass y durch 8 ersetzt werden darf

"t0:=8","y:=t0"

3:

t0 := 7

x := t0

t1 := x

t2 := y

t3 := t1 + t2

z := t3

4:

t1 := x

t2 := y

t3 := t1 + t2

z := t3

3:

t0 := 7

x := 7

t1 := 7

t2 := y

t3 := 7 + y

z := t3

4:

t1 := x

t2 := 8

t3 := x + 8

z := t3

t1 := x

t2 := t0

t3 := t1 + t2

z := t3

"t1:=x","t2:=y","z:=t3"

1:

t0 := y

t1 := x

1:

t0 := y

t1 := x


Eliminierung toten Codes

  • Eine Zwischencodeanweisung iri(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 toter Code entstehen.

2:

t0 := 8

y := 8

Darf nicht gestrichen werden.

3:

t0 := 7

x := 7

t1 := 7

t2 := 8

t3 := 7 + 8

z := 15

4:

t1 := x

t2 := 8

t3 := t1 + 8

x := t3

Kann gestrichen werden.

1:

t0 := 8

t1 := x


Information zur Eliminierung toten Codes

  • Berechnung der Information Lebendig: LE(x) = out(x) für Knoten x im Steuerflussgraphen S = (N,E,q,s) durch eine Datenflussanalyse mit den Parametern:

    • Menge aller Informationen: (V)

    • Rückwärtsanalyse mit  := 

    • gen(bi) := {v | irj(i) ist Verwendung von v und für alle 0 k < j gilt: irk(i) ist keine Definition von v}

    • kill(bi) := {v | v wird in bi definiert}

2:

t0 := 8

y := 8

"x"

3:

t0 := 7

x := 7

t1 := 7

t2 := 8

t3 := 7 + 8

z := 15

4:

t1 := x

t2 := 8

t3 := t1 + 8

x := t3

"x"

"x"

1:

t0 := 8

t1 := x


Eliminierung toten Codes im Basisblock

  • Entferne die Anweisung x := expr an Position i im Basisblock b, falls:

    • x an Position j > i definiert wird und für alle Anweisungen irk(b) mit i < kj gilt: irk(b) verwendet x nicht oder

    • x out(b) und in keiner Anweisung irk(b) mit i < k < #b wird x verwendet.

  • Durch das Entfernen einer Anweisung x := expr entfällt die Verwendung der Variablen in expr.

  • Konsequenz: Wiederholung der Eliminierung toten Codes erforderlich.

2:

t0 := 8

y := 8

2:

"x"

3:

t0 := 7

x := 7

t1 := 7

t2 := 8

t3 := 7 + 8

z := 15

4:

t1 := x

t2 := 8

t3 := t1 + 8

x := t3

3:

x := 7

4:

t1 := x

t3 := t1 + 8

x := t3

"x"

"x"

1:

t0 := 8

t1 := x

1:

t0 := 8

t1 := x


Weitere Anwendung der Information Lebendig

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


Globale Eliminierung gemeinsamer Teilausdrücke

  • Die Zuweisung iri(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 irn(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.

  • Konsequenz: Es entstehen neue Kopierbefehle.

y := 4 * i

x := 6 * j

Hier darf 6 * j ersetzt werden.

j := j +1

m := 5 * y

n := 6 * j

x := x * 5

i := i + 1

Hier darf 6 * j nicht ersetzt werden.

n := 6 * j

m := i + 1


Information zur globalen Eliminierung gemeinsamer Teilausdrücke

  • Berechnung der Information Verfügbare Ausdrücke AE(x) = in(x) für Knoten x im Steuerflussgraphen S = (N,E,q,s) durch eine Datenflussanalyse mit den Parametern:

    • Menge aller Informationen: ({e | e ist Ausdruck in einem Zwischencodebefehl})

    • Vorwärtsanalyse mit  := 

    • gen(bi) := {e | irj(i) hat die Form x := e und für alle jk < #bi gilt: irk(i) definiert keine in e verwendete Variable}

    • kill(bi) := {e | Variable im Ausdruck e wird in bi definiert}

6*j

2:

y := 4 * i

x := 6 * j

4*i, 6*j

3:

j := j +1

4:

m := 5 * y

n := 6 * j

x := x * 5

i := i + 1

1:

n := 6 * j

m := i + 1


Globale Eliminierung gemeinsamer Teilausdrücke in Basisblöcken

  • Ersetze die Anweisung x := e an Position i im Basisblock b durch x := t falls:

    • die Anweisung irj(b) die Form y := e hat und j < i und für alle Anweisungen irk(b) mit jk < i gilt: irk(b) definiert keine Variable, die in e verwendet wird oder

    • e in(b) und in keiner Anweisung irk(b) mit 0 k < i wird eine Variable definiert, die in e verwendet wird.

  • Nach den Anweisungen y := e, die e berechnen, wird t := e eingefügt (t ist neue Variable).

  • Durch Ersetzung mit x := t entstehen neue Kopieranweisungen.

  • Konsequenz: Wiederholung der Copy-/Constant-Propagation erforderlich.

y := 4 * i

x := 6 * j

t := x

6*j

2:

y := 4 * i

x := 6 * j

4*i, 6*j

3:

j := j +1

4:

m := 5 * y

n := 6 * j

x := x * 5

i := i + 1

j := j +1

m := 5 * y

n := t

x := x * 5

i := i + 1

1:

n := 6 * j

m := i + 1

n := 6 * j

m := i + 1


Entfernen schleifeninvarianter Berechnungen

  • Es sei L die Menge der Knoten des Steuerflussgraphen, die auf einem Zykel liegen und d Lder einzige Knoten der nicht zu L gehört und eine Kante zu einem Knoten in L besitzt (d dominiert L).

  • Eine Anweisung iri(j) = "x := e" kann im Block bj Ldurch 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.

  • Um eine spekulative Ausführung von e zu vermeiden, Einfügen eines neuen Basisblocks auf der Kante von d nach L und Einfügen von t := e in diesen neuen Basisblock.

y := 4 * i

x := 6 * j

t := x

5*y ist schleifeninvariant

i und x sind nicht schleifeninvariant

j := j +1

m := 5 * y

n := t

x := x * 5

i := i + 1

n := 6 * j

m := i + 1


Informationen zum Finden schleifeninvarianter Berechnungen

  • Berechnung der Information Erreichende Definiton RD(x) = in(x) für Knoten x im Steuerflussgraphen S = (N,E,q,s) durch eine Datenflussanalyse mit den Parametern:

    • Menge aller Informationen: (()V)

    • Vorwärtsanalyse mit  := 

    • gen(bi) := {((i,j),v) | irj(i) ist letzte Definition von v in bi}

    • kill(bi) := {((m,n),v) | (m,n) ist Programmposition und bi enthält eine Definition von v}

y := 4 * i

x := 6 * j

t := x

((2,0),y),((2,1),x),((2,2),t),

((4,0),m),((4,1),n),((4,2),x),((4,3),i)

2:

((2,0),y),((2,1),x),((2,2),t)

3:

j := j +1

4:

m := 5 * y

n := t

x := x * 5

i := i + 1

((2,0),y),((2,1),x),((2,2),t),((3,0),j),

((4,0),m),((4,1),n),((4,2),x),((4,3),i)

1:

n := 6 * j

m := i + 1


Entfernen schleifeninvarianter Berechnungen in L

  • Finde in L Anweisungen der Form x := e, wobei e nur Konstanten und Variablen v enthält, die außerhalb der Blöcke von L definiert wurden.

  • Ersetze x := e durch x := inv (inv ist neue Variable) und füge am Ende von d die Anweisung inv := e ein.

  • Es entstehen neue Kopieranweisungen.

  • Konsequenz: Wiederholung von Konstanten- und Kopierpropagierung.

y := 4 * i

x := 6 * j

t := x

inv := 5 * y

y := 4 * i

x := 6 * j

t := x

((2,0),y),((2,1),x),((2,2),t),

((4,0),m),((4,1),n),((4,2),x),((4,3),i)

2:

3:

j := j +1

4:

m := 5 * y

n := t

x := x * 5

i := i + 1

j := j +1

m := inv

n := t

x := x * 5

i := i + 1

1:

n := 6 * j

m := i + 1

n := 6 * j

m := i + 1


Weitere Anwendung der Information Erreichende Definitionen

  • Erkennung der Benutzung einer Variablen vor ihrer Definition.

  • Definiere out(b0) := {((0,0),v) | v hat Verwendung im Steuerflussgraph}.

  • Berechne Erreichende Definitionen.

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


Strength-Reduction in Schleifen

  • Es sei L die Menge der Blöcke einer Schleife und d der Schleifenkopf (Dominator von L)

  • Suchen einer Variablen i (Induktionsvariablen), die in jedem Schleifendurchlauf um eine Konstante c erhöht wird.

  • Suchen nach einer Berechnung y := f(i), wobei f(i + c) – f(i) = di

  • Statt f(i) in jeder Iteration zu berechnen, wird in jeder Iteration zu ydi addiert.

i := 0

y := 4 * i

x := 6 * j

x' := x

m := 5 * y

n := x'

i ist Induktionsvariable und x schleifeninvariant. Dann wird z in jeder Iteration um 2*x größer.

j := j +1

z := x * i

i := i + 2

n := 6 * j

m := i + 1


Strength-Reduction im Schleifenkörper

  • Finden von Anweisungen der Form z := invi oder z := iinv, wobei i eine Induktionsvariable ist, die in jedem Schleifendurchlauf um cexpr erhöht wird und inv schleifeninvariant ist.

  • Füge am Ende von d ein:

    • dz := invcexpr und nz := invi

  • Im Schleifenkörper :

    • Füge nach der Anweisung i := i + cexpr die Anweisung nz := nz + dz ein und

    • ersetze z := invi durch z := nz.

  • Dadurch kann nz selbst wieder zu einer Induktionsvariablen werden. Konsequenz: Wiederholung der Strength-Reduction.

i := 0

y := 4 * i

x := 6 * j

x' := x

m := 5 * y

n := x'

dz := x * 2

nz := x * i

i := 0

y := 4 * i

x := 6 * j

x' := x

m := 5 * y

n := x'

i ist Induktionsvariable und x schleifeninvariant. Dann wird z in jeder Iteration um 2*x größer.

j := j +1

z := x * i

i := i + 2

j := j +1

z := nz

nz := nz + dz

i := i + 2

nz und z sind Induktions-variable.

n := 6 * j

m := i + 1

n := 6 * j

m := i + 1


Komplexbeispiel: Matrixmultiplikation

innerLoop:

t0 := &c

t1 := j

t2 := n

t3 := t1*t2

t4 := i

t5 := t3+t4

t6 := t0+t5

t7 := @t6

t8 := &a

t9 := j

t10:= n

t11:= t9*t10

t12:= k

t13:= t11+t12

t14:= t8+t13

t15:= @t14

t16:= &b

t17:= k

t18:= n

t19:= t17*t18

t20:= i

t21:= t19+t20

t22:= t16+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t26 := &c

t27 := j

t28 := n

t29 := t27*t28

t30 := i

t31 := t29+t30

t32 := t26+t31

@t32:= t25

Quelltext für Matrixmultiplikation:

for(i = 0; i < n; i = i+1) {

for(j = 0; j < n; j = j+1) {

c[j][i] = 0.0;

for(k = 0; k < n; k = k+1) {

c[j][i] = c[j][i] + a[j][k] * b[k][i]

}

}

}

Erzeugter Zwischencode


Konstanten- und Kopierpropagierung und Eliminierung toten Codes

innerLoop:

t0 := &c

t1 := j

t2 := n

t3 := t1*t2

t4 := i

t5 := t3+t4

t6 := t0+t5

t7 := @t6

t8 := &a

t9 := j

t10:= n

t11:= t9*t10

t12:= k

t13:= t11+t12

t14:= t8+t13

t15:= @t14

t16:= &b

t17:= k

t18:= n

t19:= t17*t18

t20:= i

t21:= t19+t20

t22:= t16+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t26 := &c

t27 := j

t28 := n

t29 := t27*t28

t30 := i

t31 := t29+t30

t32 := t26+t31

@t32:= t25

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t11:= j*n

t13:= t11+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t29 := j*n

t31 := t29+i

t32 := &c+t31

@t32:= t25

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t11:= j*n

t13:= t11+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t29 := j*n

t31 := t29+i

t32 := &c+t31

@t32:= t25

Copy-/Constant-Propagation

und anschließende

Dead-Code-Elimination


Common Subexpression Elimination

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t11:= j*n

t13:= t11+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t29 := j*n

t31 := t29+i

t32 := &c+t31

@t32:= t25

innerLoop:

t3 := j*n

s1 := t3

s0 := t3

t5 := t3+i

t6 := &c+t5

t7 := @t6

t11:= s0

t13:= t11+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t29:= s1

t31 := t29+i

t32 := &c+t31

@t32:= t25

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t31 := t3+i

t32 := &c+t31

@t32:= t25

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

t32 := &c+t5

@t32:= t25

innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

Eliminierung des gemeinsamen Teilausdrucks j*n

Eliminierung des gemeinsamen Teilausdrucks t3+i und anschließende Kopierpropagierung

und anschließende

Eliminierung toten Codes

Eliminierung des gemeinsamen Teilausdrucks &c+t5 und anschließende Kopierpropagierung

und anschließende

Eliminierung toten Codes

Kopierpropagierung

und anschließende

Eliminierung toten Codes

c[j][i] = c[j][i] + a[j][k] * b[k][i]


Schleifeninvariante Ausdrücke entfernen

k := 0

inv0 := j*n

k := 0

inv0 := j*n

k := 0

k := 0

innerLoopTest:

t53:= k<n

if t53 then innerLoop

goto innerLoopEnd innerLoop:

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

goto innerLoopTest

innerLoopEnd:

...

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t3 := j*n

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

t3 := inv0

t5 := t3+i

t6 := &c+t5

t7 := @t6

t13:= t3+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

t5 := inv0+i

t6 := &c+t5

t7 := @t6

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

...

...

...

for(k = 0; k < n; k = k+1) {

c[j][i] = c[j][i] + a[j][k] * b[k][i]

}


Schleifeninvariante Ausdrücke entfernen

k := 0

inv0:= j*n

inv1:= inv0+i

inv2:= &c+inv1

k := 0

inv0 := j*n

k := 0

inv0:= j*n

inv1:= inv0+i

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t5 := inv0+i

t6 := &c+t5

t7 := @t6

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

t6 := &c+inv1

t7 := @t6

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@t6:= t25

t35:= k+1

k := t35

t7 := @inv2

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@inv2:= t25

t35:= k+1

k := t35

...

...

...


Bestimmung der Induktionsvariablen

k := 0

inv0:= j*n

inv1:= inv0+i

inv2:= &c+inv1

k := 0

inv0:= j*n

inv1:= inv0+i

inv2:= &c+inv1

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t7 := @inv2

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@inv2:= t25

t35:= k+1

k := t35

t7 := @inv2

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@inv2:= t25

t35:= k+1

k := t35

...

...


Strength-Reduction

k := 0

inv0:= j*n

inv1:= inv0+i

inv2:= &c+inv1

d := 1*n

nn := k*n

k := 0

inv0:= j*n

inv1:= inv0+i

inv2:= &c+inv1

t53:= k<n

if t53 then 3

t53:= k<n

if t53 then 3

t7 := @inv2

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= k*n

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@inv2:= t25

t35:= k+1

k := t35

t7 := @inv2

t13:= inv0+k

t14:= &a+t13

t15:= @t14

t19:= nn

nn := nn + d

t21:= t19+i

t22:= &b+t21

t23:= @t22

t24:= t15*t23

t25:= t7+t24

@inv2:= t25

t35:= k+1

k := t35

cexpr für k ist 1

...

...


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.


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


(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 = {k1, k2, k3,…,kn} k1 k2  k3  …  kn die kleinste obere Schranke von K.


Fixpunktiteration

  • Es ist der Fixpunkt einer Funktion F(out(b0),…,out(bm)) = F((out(b0),…,out(bm))) bzw. (in(b0),…,in(bm)) = F((in(b0),…,in(bm))) gesucht.

  • Durch den Steuerflussgraphen wird für jede Komponente out(bi) bzw. in(bi) eine Mengengleichung erzeugt:

    • Vorwärtsanalyse:out(bi) = fi(out(bk1)…out(bkn)), wobei bk1,…,bkn die Steuerflussvorgänger von bi sind und 0  kj m.

    • Rückwärtsanalyse:in(bi) = fi(in(bk1)…in(bkn)), wobei bk1,…,bkn die Steuerflussvorgänger von bi sind und 0  kj m.

  • Wir schreiben kurz: (b0,…,bm) = F((b0,…,bm)) und abstrahieren von der Richtung.

  • Die induzierte Ordnung auf I wird zu einer Ordnung auf Im+1 erweitert:(a0,…,am)  (b0,…,bm) gdw. j: 0  j  m  aj  bj. Analog wird der Operator  für einen Vektor erweitert.

  • Unter der Voraussetzung, dass die Transferfunktionen fi monoton und stetig sind, ist es F auch (Beweis folgt).


Monotonie von F

  • F monoton gdw. aus (a0,…,am)  (b0,…,bm) folgt F(a0,…,am)  F(b0,…,bm).

  • a = (a0,…,am)  (b0,…,bm) = b gdw. i: ai  bi.

  • Für jedes ai und bi gilt nun:

    • Es seien ak1,…,akn bzw. bk1,…,bkndie Komponenten in a bzw. b, die den in/out-Resultaten der Steuerflussvorgänger/-nachfolger von ai bzw. bi entsprechen.

    • Wegen akj  bkj ist ak1…akn bk1…bkn. (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 fi gilt dann fi(ak1…akn) fi(bk1…bkn)

  • Und damit F(a0,…,am)  F(b0,…,bm)


Stetigkeit von F

  • F stetig gdw. F(a0,…,am) F(b0,…,bm) = F(a0b0,…,ambm).

  • Es seien ai' und bi' die i-ten Komponenten des Resultats von F(a) bzw. F(b), d.h.: b'i = fi(bk1,…,bkn ) und a'i = fi(ak1,…,akn)

  • Wegen der Stetigkeit von fi gilt: a'i  b'i= fi(ak1,…,akn)fi(bk1,…,bkn) = fi(ak1)… fi(akn)fi(bk1)…fi(bkn) = fi(ak1) fi(bk1)…fi(akn)fi(bkn) = fi(ak1bk1)…fi(aknbkn) = fi(ak1bk1,…,aknbkn).

  • fi(ak1bk1,…,aknbkn) ist auch die i-te Komponente des Resultats von F(a0b0,…,ambm)


Ende der Optimierung

Ende der Vorlesung


Beispiel Steuerflussgraph/Interferenzgraph

d := 0

a := 1

c := 3

(d)

(a,d)

(a,d,c)

u

v

t

w

e

f := c

(a,c,f,d)

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)

(c,d,r)

(d,s,r)

(d,t)

(d,e)

(c,d)

(d,u)

(d,v)

(d,w)

(d,e)

a

d

s

f

c

r

z

c:= d+3

a := e*c

(d,c)

(d,c,a)

z:= a+d

(z)


Färbung des Interferenzgraphen

u

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

v

t

w

e

s

a

d

f

c

r

z

I = (V, E), R = {0,1,2}

w

w

v

v

u

u

t

t

e

e

a

a

d

d

s

s

d4

d4

c

f

f

c

r

r

z

z

w

v

u

t

e

d4

z

d1

d2

d3

s

r

c

f

a

d1

d1

d2

d2

d3

d3


Spillen

Spillen von d

d := 0

@&d := d

a := 1

c := 3

(d)

()

(a,d)

(a,c)

d := 0

a := 1

c := 3

(d)

(a,d)

(a,d,c)

f := c

(a,c,f)

f := c

(a,c,f,d)

d1 := @&d

d1:= d1+1

@&d := d1

r := 2*d

s := 3*c

t := r+s

e := t+5

d2 := a+f

@&d := d2

u := c

v := u+1

w := v+1

e := v

(c,d1)

(c,d1)

(c)

(c,r)

(s,r)

(t)

(e)

(c,d2)

(c)

(u)

(v)

(w)

(e)

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)

(c,d,r)

(d,s,r)

(d,t)

(d,e)

(c,d)

(d,u)

(d,v)

(d,w)

(d,e)

d3 := @&d

c:= d3+3

a := e*c

(d3,c)

(c)

(c,a)

c:= d+3

a := e*c

(d,c)

(d,c,a)

d4 := @&d

z:= a+d

(d4)

(z)

z:= a+d

(z)


Auswahl der Spillvariablen

  • Falls ein Interferenzgraph nicht weiter reduziert werden kann, dann wird aus den verbleibenden Knoten der ausgewählt, für denminimal 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.


  • Login