286 lines
13 KiB
TeX
286 lines
13 KiB
TeX
% !TeX spellcheck = de_DE
|
|
\documentclass[11pt,a4paper,toc]{scrartcl}
|
|
\usepackage[a4paper,left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm]{geometry}
|
|
\usepackage[ngerman]{babel}
|
|
\usepackage{amssymb}
|
|
\usepackage{scrextend}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage{amsmath}
|
|
\usepackage{enumitem}
|
|
\usepackage{mathtools}
|
|
\usepackage[load=named]{siunitx}
|
|
\usepackage{csquotes}
|
|
\usepackage[hidelinks]{hyperref}
|
|
%\usepackage{listings}
|
|
\usepackage{algorithmicx}
|
|
\usepackage{algpseudocode}
|
|
%\usepackage{pgfplots}
|
|
\usepackage{tikz}
|
|
%\usetikzlibrary{positioning}
|
|
%\usetikzlibrary{arrows.meta}
|
|
%\usetikzlibrary{quotes}
|
|
%\usetikzlibrary{angles}
|
|
%\usetikzlibrary{babel}
|
|
%\usetikzlibrary{fit}
|
|
%\usepackage{datetime}
|
|
%\usepackage{xcolor}
|
|
|
|
%\pdfminorversion=7 % Import-Unterstützung für PDFs bis Version 1.7
|
|
%\pgfplotsset{compat=1.16} % verhindern, dass pgfplots im Rückwärtskompatibilitätsmodus arbeitet
|
|
|
|
|
|
\setlist[enumerate,1]{label={\arabic*.}}
|
|
\setlist[enumerate,2]{label={\alph*)}}
|
|
|
|
\title{Optimierungen in Übersetzern: Verfahren}
|
|
\author{Marco Ammon (my04mivo)}
|
|
\date{\today}
|
|
|
|
\makeatletter
|
|
\g@addto@macro\bfseries{\boldmath}
|
|
\makeatother
|
|
|
|
\begin{document}
|
|
\maketitle
|
|
|
|
\tableofcontents
|
|
\clearpage
|
|
\section{Kontrollflussanalyse}
|
|
\subsection{Kontrollflussgraph}
|
|
\begin{itemize}
|
|
\item Gerichteter Graph
|
|
\item Knoten: Grundblöcke (meist maximal)
|
|
\item Kante zwischen zwei Blöcken $A$ und $B$ wenn $B$ direkt nach $A$ ausgeführt werden kann (etwa [un-]bedingter Sprung oder Fallthrough)
|
|
\item Synthetische Ergänzung um Entry- und Exit-Knoten, die mit Kante verbunden sind
|
|
\item Kontrollflussabhängigkeit: Bei Verzweigungsknoten $v$ mit direkten Nachfolgern $a$ und $b$: $y$ kontrollflussabhängig von $v$ $\Leftrightarrow$ mindestens ein Pad von $a$ zum Exit-Knoten ohne $y$ und jeder Pfad von $b$ zum Exit-Knoten über $y$
|
|
\end{itemize}
|
|
\subsection{Dominanz}
|
|
\begin{itemize}
|
|
\item Knoten $x$ dominiert $y$ ($x \geq \geq y$), wenn jeder Pfad von Wurzel zu $y$ durch $x$ laufen muss
|
|
\item Strikte Dominanz $x >> y$, falls zusätzlich $x \neq y$ gilt
|
|
\item $\mathrm{ImmDom[}y\mathrm{]}$ ist strikter Dominator von $y$, der $y$ am Nächsten ist
|
|
\item Dominatorbaum enthält jeden Knoten als Kind seines ImmDomms $\rightarrow$ Pfad zwischen $x$ und $z$ in Dominatorbaum $\Leftrightarrow$ $x >> z$
|
|
\end{itemize}
|
|
|
|
\subsubsection{Berechnung der Dominatoren $D(n)$ eines Knoten $n$}
|
|
|
|
\paragraph{Iterativer Fixpunkt-Algorithmus (Lengauer)}
|
|
\begin{itemize}
|
|
\item mit $\mathcal{O}(\vert E\vert \vert N\vert ^2)$
|
|
\item Zunächst Überapproximation der Dominatorenmenge
|
|
\item Initialisierung aller $D(n) \in N$ mit $N$ außer Startknoten $S$ mit $D(S) = S$
|
|
\item Bis Fixpunkt erreicht ist: alle $D(n)$ zu $D'(n) = \lbrace n\rbrace \cup \bigcap_{(p, n) \in E} D(p)$
|
|
\item $n$ am besten in Tiefensuchereihenfolge durchlaufen
|
|
\end{itemize}
|
|
|
|
\paragraph{Verfahren mit Spannendem Tiefenbaum $T$}
|
|
\begin{itemize}
|
|
\item Besuch des KFG in Tiefensuchereihenfolge mit zugehöriger Nummerierung: \begin{itemize}
|
|
\item \enquote{Spannende} Kanten gehen zu frisch nummerierten Knoten
|
|
\item Rückschreitende Kanten gehen zu Vorgänger (kleinere DFS-Nummer) in $T$
|
|
\item Fortschreitende Kanten gehen zu Nachfolger (größere DFS-Nummer) in $T$
|
|
\item Kreuzkanten führen in früher besuchten Ast in $T$
|
|
\end{itemize}
|
|
\item Dominatoren $D(n)$ liegen auf jeden Fall \enquote{über} $n$ in $T$
|
|
\item Berechnung der Semidominatoren $\mathrm{SemDom}\lbrack w\rbrack$ in Reihenfolge fallender DFS-Nummern: \begin{itemize}
|
|
\item Direkte Vorgänger auf $T$ sind Kandidaten
|
|
\item $\min_{u\in \mathrm{Pred}(w)} \mathrm{SemDom}\lbrack u\rbrack$ ist Kandidat
|
|
\item Minimum der Kandidaten ist $\mathrm{SemDom}\lbrack w\rbrack$
|
|
\end{itemize}
|
|
\item Berechnung von $\mathrm{ImmDom}\lbrack w\rbrack$ durch Durchlaufen in Tiefenordnung von $\mathrm{SemDom}\lbrack w\rbrack$ nach $w$:\begin{itemize}
|
|
\item Jeweils alle Vorgänger $u$ untersuchen und $u$ mit kleinstem $\mathrm{SemDom}\lbrack u\rbrack$ finden
|
|
\item \begin{equation*}
|
|
\mathrm{ImmDom}\lbrack w\rbrack = \begin{cases}
|
|
\mathrm{SemDom}\lbrack u\rbrack & \mathrm{falls}\, \mathrm{SemDom}\lbrack w\rbrack = \mathrm{SemDom}\lbrack u \rbrack\\
|
|
\mathrm{ImmDom}\lbrack u\rbrack & \mathrm{sonst}
|
|
\end{cases}
|
|
\end{equation*}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\subsubsection{Dominanzgrenze}
|
|
\begin{itemize}
|
|
\item Dominanzgrenze $DG[x]$ enthält Knoten $y$, die einen von $x$ dominierten Vorgänger besitzen, aber nicht von $x$ streng dominiert werden
|
|
\item Berechnung der $DG[x]$: \begin{align*}
|
|
DG[x] &= DG_\text{local}[x] \cup \bigcup_{z \in N, \mathrm{ImmDom}[z] = x} DG_\text{up}[x, z] \\
|
|
DG_\text{local}[x] &= \lbrace y \in \mathrm{Succ}(x) \mid \mathrm{ImmDom}[y] \neq x\rbrace\\
|
|
DG_\text{up}[x, z] &= \lbrace y \in DG[z] \mid \mathrm{ImmDom}[y] \neq x\rbrace
|
|
\end{align*}
|
|
\item Invertierung der Dominanzgrenzen liefert Kontrollflussabhängigkeiten
|
|
\end{itemize}
|
|
|
|
\subsection{Schleifenerkennung}
|
|
\begin{itemize}
|
|
\item Region: \begin{itemize}
|
|
\item Untergraph mit einem \enquote{Header} $d$, der (potentiell mehrere) Eingangskante von außerhalb besitzt
|
|
\item Wichtige Region: maximale Region mit $d$ dominiert alle Knoten der Region
|
|
\item Hierarchischer Flussbaum: Baum der Regionen
|
|
\end{itemize}
|
|
\item Rückwärtskante: Kante $(n,d)$ mit $d \geq \geq n$
|
|
\item Natürliche Schleife: \begin{itemize}
|
|
\item Rückwärtskante $(n, d)$ sowie alle Knoten $k$ mit $d \ge \ge k$ und es gibt einen Pfad von $k$ nach $n$ ohne $d$
|
|
\item Bestimmung mit Worklist-Algorithmus, der bei $n$ beginnt und rekursiv die Vorgänger bis $d$ durchläuft und in Menge aufnimmt
|
|
\end{itemize}
|
|
\item Suche nach Rückwärtskanten und natürlichen Schleifen in wichtigen Regionen ausreichend
|
|
\item \enquote{Unsaubere} Regionen: \begin{itemize}
|
|
\item ein Knoten dominiert nachgeordneten Zyklus
|
|
\item Erkennung durch Prüfung der Reduzierbarkeit des Graphs: \begin{itemize}
|
|
\item Entfernung der Rückwärtskanten aus KFG $\rightarrow$ azyklischer Graph, in dem jeder Knoten von der Wurzel erreicht werden kann $\Leftrightarrow$ KFG frei von unnatürlichen Schleifen
|
|
\item Alternative mit Transformationen: Am Ende Graph aus einem einzigen Knoten $\Leftrightarrow$ KFG reduzierbar (ohne Zyklen) \begin{description}
|
|
\item[T1-Transformation] Selbstschleifen aus Graph löschen
|
|
\item[T2-Transformation] Knoten mit eindeutigem Vorgänger mit diesem zusammenfassen
|
|
\end{description}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\section{Datenflussanalyse}
|
|
\begin{itemize}
|
|
\item Datenabhängigkeiten: \begin{itemize}
|
|
\item Schreiben vor Lesen:
|
|
\item Schreiben vor Schreiben: Ausgabeabhängigkeit
|
|
\item Lesen vor Schreiben: Anti-Abhängigkeit
|
|
\end{itemize}
|
|
\item Starke Variablendefinition: sichere Zuweisung zu einer Variablen
|
|
\item Schwache Variablendefinition: mögliche Zuweisung zu einer Variablen (etwa über Zeiger oder Referenz, die möglicherweise auf Variable zeigen)
|
|
\end{itemize}
|
|
|
|
\subsection{Berechnung von Datenflusswissen}
|
|
\begin{itemize}
|
|
\item Funktion pro Grundblock: \begin{itemize}
|
|
\item Eingabe: bei Vorwärtsproblem (Rückwärtsproblem) Datenflusswissen der Vorgängerknoten (Nachfolgerknoten)
|
|
\item Vorverarbeitung: logische Operationen oder Mengenoperationen \begin{itemize}
|
|
\item sicher (must): Eigenschaft muss auf allen Eingangskanten erfüllt sein
|
|
\item möglich (may): Eigenschaft muss auf mindestens einer Eingangskante erfüllt sein
|
|
\end{itemize}
|
|
\item Ausgabe: auf Eingabe und in Grundblock enthaltenen Befehlen basierendes, aktualisiertes Datenflusswissen
|
|
\end{itemize}
|
|
\item Iterativer Fixpunkt-Algorithmus für Vorwärtsproblem: optimal Besuch in Reihenfolge des spannenden Tiefenbaums \begin{algorithmic}[]
|
|
\State $\mathrm{in}(\mathrm{Entry}) \gets \mathrm{Init}$
|
|
\ForAll{$n \in N \setminus \lbrace \mathrm{Entry}\rbrace$}
|
|
\State $\mathrm{in}(n) \gets \bot$
|
|
\EndFor
|
|
\State $\mathrm{WL} \gets N\setminus \lbrace \mathrm{Entry}\rbrace$
|
|
\While{$\mathrm{WL} \neq \emptyset$}
|
|
\State $B \gets \mathrm{pop}(\mathrm{WL})$
|
|
\State $\mathrm{out} \gets f_B(\mathrm{in}(B))$
|
|
\ForAll{$B' \in \mathrm{Succ}(B)$}
|
|
\State $\mathrm{in}(B') \gets \mathrm{in}(B') \sqcup \mathrm{out}$
|
|
\If{$\mathrm{out} \neq \mathrm{out}(B)$}
|
|
\State $\mathrm{WL} \gets \mathrm{WL} \cup \lbrace B'\rbrace$
|
|
\State $\mathrm{out}(B) \gets \mathrm{out}$
|
|
\EndIf
|
|
\EndFor
|
|
\EndWhile
|
|
\end{algorithmic}
|
|
\item Probleme bei Verwendung von Bitvektoren:\begin{itemize}
|
|
\item Transformation erfordert komplettes Neuberechnen
|
|
\item Bitvektoren oft zu groß für jeweilige Nutzungsstelle
|
|
\end{itemize}
|
|
\item Alternative Datenstrukturen: \begin{itemize}
|
|
\item Definitions-Nutzungs-Graph für erreichbare Nutzungen
|
|
\item Nutzungs-Definitions-Graph für erreichenden Definitionen
|
|
\item Variablen-Netz als Vereinigung aller sich schneidenden DU-Graphen
|
|
\item Single Static-Assignment (SSA)
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\subsection{Typische Datenflussprobleme}
|
|
\begin{itemize}
|
|
\item Erreichende Definitionen: \begin{itemize}
|
|
\item mindestens ein Pfad, auf dem Variable nicht erneut schwach definiert wird
|
|
\item Optimierungen: \begin{itemize}
|
|
\item Keine erreichende Definition $\rightarrow$ Variable nicht initialisiert
|
|
\item Genau eine oder gleiche Definition $\rightarrow$ Konstantenweitergabe oder Kopienfortschreibung möglich
|
|
\item Alle Variablen nur außerhalb einer Schleife definiert $\rightarrow$ Ausdruck schleifeninvariant
|
|
\end{itemize}
|
|
\item Umsetzung: \begin{itemize}
|
|
\item Eine Bitposition pro Variablendefinition
|
|
\item Setzen bei Definition der Variable
|
|
\item Zurücksetzen bei mindestens schwacher Definition
|
|
\item Anfangsbelegung: false
|
|
\item Vorverarbeitung: oder
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item Konstantenweitergabe: \begin{itemize}
|
|
\item Eine Bitposition plus Wert pro Variable
|
|
\item Setzen von Bit und Wert bei konstanter Definition
|
|
\item Zurücksetzen von Bit bei mindestens schwacher oder nicht konstanter Definition
|
|
\item Anfangsbelegung: false, ?
|
|
\item Vorverarbeitung: und sowie Wertgleichheit
|
|
\end{itemize}
|
|
\item Kopienfortschreibung: \begin{itemize}
|
|
\item Eine Bitposition pro aus Kopieren entstandener Wergleichtheitsbeziehung
|
|
\item Setzen bei Kopieroperation
|
|
\item Zurücksetzen wenn Original oder Kopie mindestens schwach definiert wird
|
|
\item Anfangsbelegung: false
|
|
\item Vorverarbeitung: und
|
|
\end{itemize}
|
|
\item Verfügbare Ausdrücke: \begin{itemize}
|
|
\item auf allen Pfaden von Entry-Knoten aus wird Ausdruck bestimmt und verwendete Variablen anschließend nicht mehr schwach definiert
|
|
\item Optimierungen: \begin{itemize}
|
|
\item Elimination gleicher Teilausdrücke
|
|
\item Wiederverwendung statt Neuberechnung
|
|
\end{itemize}
|
|
\item Umsetzung: \begin{itemize}
|
|
\item Eine Bitposition pro wertnummeriertem (Teil-)Ausdruck
|
|
\item Setzen wenn Ausdruck ausgewertet wird
|
|
\item Zurücksetzen wenn vorkommende Variable mindestens schwach definiert wird
|
|
\item Anfangsbelegung: false
|
|
\item Vorverarbeitung: und sowie Ausdruck muss auf allen Pfaden verfügbar sein
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item Lebendige Variablen: \begin{itemize}
|
|
\item lebendig in Knoten $D$, wenn es einen Pfad von $D$ zum Exit-Knoten gibt, auf der die Variable ohne vorherige Redefinition schwach benutzt wird; sonst tot
|
|
\item Optimierungen: \begin{itemize}
|
|
\item Tote Variablen müssen nicht ausgerechnet werden
|
|
\item Weniger Registerdruck
|
|
\item Elimination redudanter Schleifenlaufvariablen nach der Schleife
|
|
\end{itemize}
|
|
\item Umsetzung: \begin{itemize}
|
|
\item Eine Bitposition pro Variable
|
|
\item Setzen bei Verwendung der Variable
|
|
\item Zurücksetzen bei starker Redefinition
|
|
\item Anfangsbelegung: false
|
|
\item Vorverarbeitung: oder
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item Erreichbare Nutzungen: \begin{itemize}
|
|
\item Alle Nutzungen einer Variable durch Bestimmen der Pfade, auf denen Variable ohne vorherige Redefinition verwendet wird
|
|
\item Zweck: Hilfreich für Lebendigkeitsspannen und Registerallokation
|
|
\end{itemize}
|
|
\item Vorhersehbare Ausdrücke: \begin{itemize}
|
|
\item auf allen Pfaden zum Exit-Knoten wird Ausdruck bestimmt und verwendete Variablen werden nicht vorher schwach redefiniert
|
|
\item Optimierungen: \begin{itemize}
|
|
\item Vorziehen der Ausdrucksberechnung zur Verkleinerung der Code-Größe
|
|
\item Geringerer Registerdruck in folgenden Zweigen
|
|
\end{itemize}
|
|
\item Umsetzung: \begin{itemize}
|
|
\item Eine Bitposition pro (Teil-)Ausdruck
|
|
\item Setzen bei Auswertung des Audrucks
|
|
\item Zurücksetzen bei mindestens schwacher Redefinition einer der verwendeten Variablen
|
|
\item Anfangsbelegung: false
|
|
\item Vorverarbeitung: und
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\section{Wertnummerierung in Grundblock}
|
|
\begin{itemize}
|
|
\item Post-Order-Traversierung des Ausdrucksbaums
|
|
\item Jede referenzierte Variable bekommt eindeutige Id
|
|
\item Kombination aus Operator und beiden Argumenten bekommt entweder frische Id oder bei Duplikat (auch kommutativ) bereits verwendete
|
|
\item Gleiche Ids $\Leftrightarrow$ gleicher Ausdruck
|
|
\end{itemize}
|
|
|
|
\section{Aliasanalyse}
|
|
|
|
\section{Induktionsvarianten und schleifeninvarianter Code}
|
|
|
|
\section{Schleifen und Arrays}
|
|
|
|
\section{Schleifentransformationen}
|
|
|
|
\section{Schleifenrestrukturierungen}
|
|
\end{document}
|