Datenflußanalyse
Datenflußanalyse
Datenflußanalyse
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>Datenflußanalyse</strong><br />
Christoph Dreyer<br />
Projektgruppe Programmanalyse für Java<br />
1
<strong>Datenflußanalyse</strong><br />
<strong>Datenflußanalyse</strong> wird in Compilern benutzt.<br />
Sie liefert Informationen über das Programm.<br />
Diese werden zur Optimierung genutzt.<br />
Compiler<br />
<br />
Optimierung<br />
<br />
Analyse<br />
<br />
Kontrollflußanalyse<br />
<br />
<br />
Transformation<br />
<strong>Datenflußanalyse</strong><br />
<strong>Datenflußanalyse</strong> ist nicht nur zur Optimierung nützlich.<br />
Auch für andere Zwecke formuliert man Datenflußprobleme.<br />
Sie können dann mit Standardverfahren gelöst werden.<br />
2
Programmanalyse<br />
Was wird berechnet?<br />
f0 = 0;<br />
f1 = 1;<br />
if (m ≤ 1) {<br />
return m;<br />
}<br />
else {<br />
i = 2;<br />
while (i ≤ m) {<br />
f2 = f0 + f1;<br />
f0 = f1;<br />
f1 = f2;<br />
i++;<br />
}<br />
return f2;<br />
}<br />
Wie wird f2 berechnet?<br />
Welche Werte kann f0 haben?<br />
Wo wird f0 berechnet?<br />
3
Ziele<br />
• Datenflußprobleme kennen<br />
• Datenflußgleichungen aufstellen können<br />
• Lösungsverfahren verstehen<br />
4
Überblick<br />
1. ein Datenflußproblem<br />
2. Datenflußgleichungen<br />
3. ein Lösungsverfahren<br />
4. andere Probleme<br />
5. Verbesserungen des Algorithmus<br />
6. ein anderes Verfahren<br />
5
Erreichende Definitionen<br />
Welche Definitionen erreichen eine bestimmte Verwendung?<br />
Definition einer Variablen Der Variablen wird ein Wert<br />
zugewiesen<br />
Zerstören einer Definition Eine spätere Definition weist<br />
derselben Variable einen Wert zu<br />
Definition erreicht Verwendung Zwischen Definition<br />
und Verwendung wird die Definition nicht zerstört<br />
x = 0;<br />
x = 1;<br />
y = x + 1;<br />
6
Programmablauf<br />
Die Menge der erreichenden Definitionen ist unabhängig<br />
vom Programmablauf.<br />
x = 0;<br />
if (a = 0) {<br />
x = 1;<br />
}<br />
y = x + 1;<br />
Eine Definition erreicht alle möglichen Verwendungen.<br />
→ Ergebnismenge nicht exakt, sondern zu groß.<br />
→ Suche nach kleinster Menge<br />
7
Kontrollflußanalyse<br />
Die Kontrollflußanalyse liefert einen Ablaufgraph auf dem<br />
die <strong>Datenflußanalyse</strong> durchgeführt wird.<br />
Kontrollflußanalyse<br />
Ablaufgraph<br />
<br />
<strong>Datenflußanalyse</strong><br />
B2<br />
Y<br />
<br />
<br />
<br />
<br />
<br />
entry<br />
<br />
B1<br />
B5<br />
<br />
exit<br />
<br />
<br />
N<br />
N <br />
<br />
B3<br />
<br />
<br />
B4<br />
Y <br />
B6<br />
<br />
8
Definitionen<br />
Jeder Definition wird eine Nummer zugeordnet.<br />
Block Variable Nummer<br />
B1 m 1<br />
B1 f0 2<br />
B1 f1 3<br />
B3 i 4<br />
B6 f2 5<br />
B6 f0 6<br />
B6 f1 7<br />
B6 i 8<br />
GEN[b] Menge der erzeugten Definitionen<br />
KILL[b] Menge der zerstörten Definitionen<br />
Ein Block zerstört die durch ihn erzeugten Definitionen.<br />
9
Datenflußgleichungen<br />
Wenn der erste Befehl eines Grundblocks ausgeführt wird,<br />
dann auch alle anderen.<br />
in[b] Definitionen, die den Block erreichen<br />
out[b] Definitionen, die den Block verlassen<br />
By<br />
Y<br />
<br />
<br />
<br />
<br />
<br />
Bx<br />
<br />
N<br />
Bz<br />
Eine Definition erreicht einen Block, wenn sie einen der<br />
Vorgängerblöcke verlassen hat.<br />
in[b] = ∪ p∈P RED[b] out[p]<br />
Eine Definition verläßt einen Block, wenn sie entweder in<br />
ihm erzeugt wurde oder ihn erreicht hat und nicht zerstört<br />
wurde.<br />
out[b] = GEN[b] ∪ (in[b] \ KILL[b])<br />
10
iterativer Algorithmus<br />
for all (b ∈ BLOCK) {<br />
out[b] = GEN[b];<br />
}<br />
do {<br />
change = false;<br />
for all (b ∈ BLOCK) {<br />
in[b] = ∪ p∈P RED[b] out[p];<br />
oldout = out[b];<br />
out[b] = GEN[b] ∪ (in[b] \ KILL[b]);<br />
if (out[b] = oldout) {<br />
change = true;<br />
}<br />
}<br />
}<br />
while (change == true);<br />
11
Beispiel<br />
Die Blöcke B4 und B6 bilden zusammen eine Schleife.<br />
<br />
<br />
B4 <br />
<br />
B6<br />
Der Block B6 enthält die Befehle des Schleifenrumpfs.<br />
f2 = f0 + f1;<br />
f0 = f1;<br />
f1 = f2;<br />
i++;<br />
GEN[B6]= {5, 6, 7, 8}<br />
KILL[B6]= {2, 3, 4, 5, 6, 7, 8}<br />
in1[B6] = out1[B4] = ∅<br />
out1[B6] = {5, 6, 7, 8}<br />
in2[B6] = out2[B4] = {1, 2, 3, 4, 5, 6, 7, 8}<br />
out2[B6] = {1, 5, 6, 7, 8}<br />
12
Upwards Exposed Uses<br />
Welche Verwendungen erreichen eine bestimmte Definition?<br />
x = 0<br />
<br />
<br />
<br />
<br />
x = 1<br />
y = x + 1 z = x + 1<br />
<br />
Verwendungen bewegen sich von unten nach oben.<br />
Es handelt sich um ein Rückwärtsproblem.<br />
out[b] = ∪ s∈SUCC[b] in[s]<br />
in[b] = GEN ′ [b] ∪ (out[b] \ KILL ′ [b])<br />
13
Verfügbare Ausdrücke<br />
Welche Ausdrücke sind an einem Punkt verfügbar?<br />
<br />
x = a + b<br />
<br />
z = a + b<br />
<br />
<br />
<br />
<br />
<br />
y = a + b<br />
Der verfügbare Ausdruck muß auf jedem Pfad berechnet<br />
werden.<br />
Es handelt sich um ein Allproblem.<br />
in[b] = ∩ p∈P RED[b] out[p]<br />
Problem Konfluenzoperator gesuchte Lösung<br />
Existenzproblem ∪ minimale Lösung<br />
Allproblem ∩ maximale Lösung<br />
14
Mengen<br />
Mengen werden mit Bitvektoren implementiert.<br />
Block Variable Nummer<br />
B1 m 1<br />
B1 f0 2<br />
B1 f1 3<br />
B3 i 4<br />
B6 f2 5<br />
B6 f0 6<br />
B6 f1 7<br />
B6 i 8<br />
Nummer der Definition entspricht Position im Bitvektor.<br />
GEN[B6] = 〈0, 0, 0, 0, 1, 1, 1, 1〉<br />
KILL[B6] = 〈0, 1, 1, 1, 1, 1, 1, 1〉<br />
Datenflußgleichungen:<br />
in[b] = ∨ p∈P RED[b] out[p]<br />
out[b] = GEN[b] ∨ (in[b] ∧ ¬KILL[b])<br />
15
Transferfunktion<br />
Transferfunktion F b berechnet den Effekt eines Blocks.<br />
out[b] = F b(in[b])<br />
F b(x) = GEN ∨ (x ∧ ¬KILL)<br />
Die Menge P RSV [b] (preserve) enthält die Definitionen,<br />
die durch den Block nicht beeinflußt werden.<br />
P RSV = ¬KILL<br />
F b(x) = GEN ∨ (x ∧ P RSV )<br />
P RSV [B6] = 〈1, 0, 0, 0, 0, 0, 0, 0〉<br />
F B6(x) = 〈x1, 0, 0, 0, 1, 1, 1, 1〉<br />
Datenflußgleichungen →<br />
→ Transferfunktionen und Konfluenzoperator<br />
16
Beschleunigung<br />
Zur Lösung des Datenflußproblems reicht im Idealfall ein<br />
Durchlauf durch den Ablaufgraph.<br />
Bx<br />
Y<br />
<br />
<br />
<br />
<br />
<br />
<br />
Bw<br />
Bz<br />
<br />
<br />
<br />
N <br />
<br />
By<br />
Schleifenköpfe müssen mehrmals berechnet werden. Nach<br />
jeder Änderung müssen auch alle abhängigen Blöcke neu<br />
berechnet werden.<br />
<br />
<br />
B4 <br />
<br />
B6<br />
in[B4] = out[B3] ∪ out[B6]<br />
in[B6] = out[B4]<br />
Bei Schleifen, die hintereinander ausgeführt werden, addieren<br />
sich die zusätzlichen Berechnungen.<br />
17
Reihenfolge<br />
In und zwischen Schleifen profitiert man von der richtigen<br />
Reihenfolge.<br />
Vorwärtsrichtung: Knoten vor allen Nachfolgern besuchen<br />
Rückwärtsrichtung: Knoten vor allen Vorgängern besuchen<br />
Bx<br />
Y<br />
<br />
<br />
<br />
<br />
<br />
<br />
Bw<br />
Bz<br />
<br />
<br />
<br />
N <br />
<br />
By<br />
Richtung Reihenfolge Beispiel<br />
vorwärts topologisch Bw, By, Bx, Bz<br />
rückwärts postorder Bz, Bx, By, Bw<br />
18
Strukturbasierte Analyse<br />
Anderes Verfahren zum Lösen von Datenflußgleichungen.<br />
Verallgemeinerung der Intervallanalyse.<br />
Gemeinsamkeiten mit iterativem Verfahren:<br />
• Transferfunktionen<br />
• Konfluenzoperator<br />
• Initialisierungswerte<br />
Kontrollflußanalyse liefert jetzt control tree.<br />
Control tree enthält Grundblöcke und abstrakte Blöcke.<br />
Abstrakte Blöcke fassen Grundblöcke zusammen.<br />
19
Verfahren<br />
Zunächst Berechnung der Transferfunktionen für die<br />
Grundblöcke.<br />
Lösung wird mit zwei Durchläufen durch den control tree<br />
berechnet.<br />
<br />
entrya<br />
entry B1a<br />
<br />
<br />
B1 B2 B3a<br />
<br />
B3 B4a<br />
<br />
B4 B6<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
exit<br />
B5<br />
Im ersten Durchlauf werden bottom-up die Transferfunktionen<br />
der abstrakten Blöcke berechnet.<br />
Im zweiten Durchlauf werden top-down für jeden Block<br />
Datenflußgleichungen aufgestellt und gelöst.<br />
20
lock-Konstrukt<br />
Alle Blöcke werden der Reihe nach ausgeführt.<br />
<br />
<br />
B3a<br />
B3 B4a<br />
<br />
<br />
<br />
<br />
<br />
Transferfunktion:<br />
<br />
block<br />
B5<br />
F B3a = F B5 ◦ F B4a ◦ F B3<br />
Datenflußgleichungen:<br />
in[B3] = in[B3a]<br />
in[B4a] = F B3(in[B3])<br />
in[B5] = F B4a(in[B4a])<br />
21
if-then-else-Konstrukt<br />
Zuerst wird der Block ausgeführt, der die Bedingung auswertet,<br />
danach einer der beiden anderen Blöcke.<br />
<br />
<br />
<br />
B1a<br />
B1 B2 B3a<br />
<br />
Transferfunktion:<br />
<br />
if-then-else<br />
<br />
<br />
<br />
<br />
<br />
F B1a = (F B2 ◦ F B1) ∨ (F B3a ◦ F B1)<br />
Datenflußgleichungen:<br />
in[B1] = in[B1a]<br />
in[B2] = F B1(in[B1])<br />
in[B3a] = F B1(in[B1])<br />
22
while-Konstrukt<br />
Die Bedingung wird ausgewertet, danach die Schleife entweder<br />
verlassen oder der Schleifenrumpf ausgeführt und<br />
noch einmal die Bedingung ausgewertet.<br />
<br />
<br />
B4a<br />
<br />
B4 B6<br />
Transferfunktion:<br />
while<br />
F B4a’ = (F B6 ◦ F B4) ∨ id<br />
F B4a = F B4 ◦ F B4a’<br />
Datenflußgleichungen:<br />
in[B4] = F B4a’(in[B4a])<br />
in[B6] = F B4a(in[B4])<br />
23
improper region<br />
Einteilung in Gruppen:<br />
acyclic keine rückführenden Kante<br />
cyclic mit Rückwärtskante<br />
improper Schleife mit mehreren Eingängen<br />
Ablaufgraph einer improper region:<br />
By<br />
<br />
<br />
<br />
<br />
Bx<br />
<br />
<br />
<br />
<br />
<br />
Bz<br />
Datenflußgleichungen sind rekursiv:<br />
in[Bx] = in[Bxa]<br />
in[By] = F Bx(in[Bx]) ∨F Bz(in[Bz])<br />
in[Bz] = F Bx(in[Bx]) ∨F By(in[By])<br />
24
Knotenaufspaltung<br />
Gleichungen werden mit iterativem Verfahren gelöst.<br />
By<br />
<br />
<br />
<br />
<br />
Bx<br />
<br />
<br />
<br />
<br />
<br />
Bz<br />
Oder durch Knotenaufspaltung:<br />
By<br />
<br />
<br />
Bx<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Bz<br />
Bza<br />
Neue Schleife hat nur einen Eingang.<br />
25
Zusammenfassung<br />
<strong>Datenflußanalyse</strong> liefert Informationen über Programm.<br />
Ergebnisse gelten für alle Programmabläufe.<br />
Klassifizierung nach . . .<br />
• Flußrichtung (vorwärts oder rückwärts)<br />
• Allproblem oder Existenzproblem (Konfluenzoperator)<br />
Transferfunktion aufstellen, dann Lösung berechnen.<br />
viele Verfahren, hier: iterativ und strukturbasiert.<br />
Aspekt iterativ strukturbasiert<br />
Geschwindigkeit schnell schneller<br />
Implementierung einfach kompliziert<br />
Transformationen neue Berechnung Änderung<br />
26
Ausblick<br />
<strong>Datenflußanalyse</strong> wird auch benutzt, . . .<br />
• zur interprozeduralen <strong>Datenflußanalyse</strong><br />
• um Decknamen zu bestimmen<br />
• um Typinformationen zu berechnen<br />
• zur Verfifikation von Programmen<br />
27