|
@@ -1649,11 +1649,12 @@ place restrictions on the frame size. For example, Mac OS X requires
|
|
the frame size to be a multiple of 16 bytes.
|
|
the frame size to be a multiple of 16 bytes.
|
|
|
|
|
|
\begin{exercise}
|
|
\begin{exercise}
|
|
-\normalfont
|
|
|
|
-Implement the \key{assign-homes} pass and test it on all of the
|
|
|
|
-example programs that you created for the previous passes pass. Use
|
|
|
|
-the \key{interp-tests} function (Appendix~\ref{appendix:utilities})
|
|
|
|
-from \key{utilities.rkt} to test your passes on the example programs.
|
|
|
|
|
|
+\normalfont Implement the \key{assign-homes} pass and test it on all
|
|
|
|
+of the example programs that you created for the previous passes pass.
|
|
|
|
+I recommend that \key{assign-homes} take an extra parameter that is a
|
|
|
|
+mapping of variable names to homes (stack locations for now). Use the
|
|
|
|
+\key{interp-tests} function (Appendix~\ref{appendix:utilities}) from
|
|
|
|
+\key{utilities.rkt} to test your passes on the example programs.
|
|
\end{exercise}
|
|
\end{exercise}
|
|
|
|
|
|
\section{Patch Instructions}
|
|
\section{Patch Instructions}
|
|
@@ -1759,12 +1760,13 @@ variables instead of stack locations or registers.
|
|
\begin{minipage}{0.45\textwidth}
|
|
\begin{minipage}{0.45\textwidth}
|
|
Source program:
|
|
Source program:
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
|
|
+(program
|
|
(let ([v 1])
|
|
(let ([v 1])
|
|
(let ([w 46])
|
|
(let ([w 46])
|
|
(let ([x (+ v 7)])
|
|
(let ([x (+ v 7)])
|
|
(let ([y (+ 4 x)])
|
|
(let ([y (+ 4 x)])
|
|
(let ([z (+ x w)])
|
|
(let ([z (+ x w)])
|
|
- (- z y))))))
|
|
|
|
|
|
+ (- z y)))))))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\end{minipage}
|
|
\begin{minipage}{0.45\textwidth}
|
|
\begin{minipage}{0.45\textwidth}
|
|
@@ -1789,15 +1791,15 @@ After instruction selection:
|
|
|
|
|
|
The goal of register allocation is to fit as many variables into
|
|
The goal of register allocation is to fit as many variables into
|
|
registers as possible. It is often the case that we have more
|
|
registers as possible. It is often the case that we have more
|
|
-variables than registers, so we can't naively map each variable to a
|
|
|
|
|
|
+variables than registers, so we cannot naively map each variable to a
|
|
register. Fortunately, it is also common for different variables to be
|
|
register. Fortunately, it is also common for different variables to be
|
|
needed during different periods of time, and in such cases the
|
|
needed during different periods of time, and in such cases the
|
|
-variables can be mapped to the same register. Consider variables $x$
|
|
|
|
-and $y$ in Figure~\ref{fig:reg-eg}. After the variable $x$ is moved
|
|
|
|
-to $z$ it is no longer needed. Variable $y$, on the other hand, is
|
|
|
|
-used only after this point, so $x$ and $y$ could share the same
|
|
|
|
-register. The topic of the next section is how we compute where a
|
|
|
|
-variable is needed.
|
|
|
|
|
|
+variables can be mapped to the same register. Consider variables
|
|
|
|
+\code{x} and \code{y} in Figure~\ref{fig:reg-eg}. After the variable
|
|
|
|
+\code{x} is moved to \code{z} it is no longer needed. Variable
|
|
|
|
+\code{y}, on the other hand, is used only after this point, so
|
|
|
|
+\code{x} and \code{y} could share the same register. The topic of the
|
|
|
|
+next section is how we compute where a variable is needed.
|
|
|
|
|
|
|
|
|
|
\section{Liveness Analysis}
|
|
\section{Liveness Analysis}
|
|
@@ -1807,19 +1809,19 @@ in the program and there is not an intervening assignment to the
|
|
variable.
|
|
variable.
|
|
%
|
|
%
|
|
To understand the latter condition, consider the following code
|
|
To understand the latter condition, consider the following code
|
|
-fragment in which there are two writes to $b$. Are $a$ and
|
|
|
|
-$b$ both live at the same time?
|
|
|
|
|
|
+fragment in which there are two writes to \code{b}. Are \code{a} and
|
|
|
|
+\code{b} both live at the same time?
|
|
\begin{lstlisting}[numbers=left,numberstyle=\tiny]
|
|
\begin{lstlisting}[numbers=left,numberstyle=\tiny]
|
|
-(movq (int 5) (var a)) ; |$a \gets 5$|
|
|
|
|
-(movq (int 30) (var b)) ; |$b \gets 30$|
|
|
|
|
-(movq (var a) (var c)) ; |$c \gets x$|
|
|
|
|
-(movq (int 10) (var b)) ; |$b \gets 10$|
|
|
|
|
-(addq (var b) (var c)) ; |$c \gets c + b$|
|
|
|
|
|
|
+ (movq (int 5) (var a))
|
|
|
|
+ (movq (int 30) (var b))
|
|
|
|
+ (movq (var a) (var c))
|
|
|
|
+ (movq (int 10) (var b))
|
|
|
|
+ (addq (var b) (var c))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
-The answer is no because the value $30$ written to $b$ on line 2 is
|
|
|
|
-never used. The variable $b$ is read on line 5 and there is an
|
|
|
|
-intervening write to $b$ on line 4, so the read on line 5 receives the
|
|
|
|
-value written on line 4, not line 2.
|
|
|
|
|
|
+The answer is no because the value \code{30} written to \code{b} on
|
|
|
|
+line 2 is never used. The variable \code{b} is read on line 5 and
|
|
|
|
+there is an intervening write to \code{b} on line 4, so the read on
|
|
|
|
+line 5 receives the value written on line 4, not line 2.
|
|
|
|
|
|
The live variables can be computed by traversing the instruction
|
|
The live variables can be computed by traversing the instruction
|
|
sequence back to front (i.e., backwards in execution order). Let
|
|
sequence back to front (i.e., backwards in execution order). Let
|
|
@@ -1845,7 +1847,7 @@ instruction sequence back to front.
|
|
where $W(k)$ are the variables written to by instruction $I_k$ and
|
|
where $W(k)$ are the variables written to by instruction $I_k$ and
|
|
$R(k)$ are the variables read by instruction $I_k$.
|
|
$R(k)$ are the variables read by instruction $I_k$.
|
|
Figure~\ref{fig:live-eg} shows the results of live variables analysis
|
|
Figure~\ref{fig:live-eg} shows the results of live variables analysis
|
|
-for the running example. Next to each instruction we write its
|
|
|
|
|
|
+for the running example. Next to each instruction we have written its
|
|
$L_{\mathtt{after}}$ set.
|
|
$L_{\mathtt{after}}$ set.
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
\begin{figure}[tbp]
|
|
@@ -1867,17 +1869,39 @@ $L_{\mathtt{after}}$ set.
|
|
\end{figure}
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
|
|
+\begin{exercise}\normalfont
|
|
|
|
+Implement the compiler pass named \code{uncover-live} that computes
|
|
|
|
+the live-after sets. We recommend storing this information (a list of
|
|
|
|
+lists of variables) in the $\itm{info}$ field of the \key{program}
|
|
|
|
+node alongside the list of variables as follows.
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+ (program (|$\Var^{*}$| |$\itm{live{-}afters}$|) |$\Instr^{+}$|)
|
|
|
|
+\end{lstlisting}
|
|
|
|
+I recommend organizing your code to use a helper function that takes a
|
|
|
|
+list of statements and an initial live-after set (typically empty) and
|
|
|
|
+returns the list of statements and the list of live-after sets. For
|
|
|
|
+this chapter, returning the list of statements is unecessary, as they
|
|
|
|
+will be unchanged, but in Chatper~\ref{ch:bool-types} we will
|
|
|
|
+introduce \key{if} statements and will need to annotate them with the
|
|
|
|
+live-after sets of the two branches.
|
|
|
|
+
|
|
|
|
+I recommend creating helper functions to 1) compute the set of
|
|
|
|
+variables that appear in an argument (of an instruction), 2) compute
|
|
|
|
+the variables read by an instruction which corresponds to the $R$
|
|
|
|
+function discussed above, and 3) the variables written by an
|
|
|
|
+instruction which corresponds to $W$.
|
|
|
|
+\end{exercise}
|
|
|
|
+
|
|
\section{Building the Interference Graph}
|
|
\section{Building the Interference Graph}
|
|
|
|
|
|
-Based on the liveness analysis, we know the program regions where each
|
|
|
|
-variable is needed. However, during register allocation, we need to
|
|
|
|
-answer questions of the specific form: are variables $u$ and $v$ ever
|
|
|
|
-live at the same time? (And therefore cannot be assigned to the same
|
|
|
|
-register.) To make this question easier to answer, we create an
|
|
|
|
-explicit data structure, an \emph{interference graph}. An
|
|
|
|
-interference graph is an undirected graph that has an edge between two
|
|
|
|
-variables if they are live at the same time, that is, if they
|
|
|
|
-interfere with each other.
|
|
|
|
|
|
+Based on the liveness analysis, we know where each variable is needed.
|
|
|
|
+However, during register allocation, we need to answer questions of
|
|
|
|
+the specific form: are variables $u$ and $v$ live at the same time?
|
|
|
|
+(And therefore cannot be assigned to the same register.) To make this
|
|
|
|
+question easier to answer, we create an explicit data structure, an
|
|
|
|
+\emph{interference graph}. An interference graph is an undirected
|
|
|
|
+graph that has an edge between two variables if they are live at the
|
|
|
|
+same time, that is, if they interfere with each other.
|
|
|
|
|
|
The most obvious way to compute the interference graph is to look at
|
|
The most obvious way to compute the interference graph is to look at
|
|
the set of live variables between each statement in the program, and
|
|
the set of live variables between each statement in the program, and
|
|
@@ -1889,8 +1913,8 @@ which two variables that are live at the same time do not actually
|
|
interfere with each other: when they both contain the same value
|
|
interfere with each other: when they both contain the same value
|
|
because we have assigned one to the other.
|
|
because we have assigned one to the other.
|
|
|
|
|
|
-A better way to compute the edges of the intereference graph is given
|
|
|
|
-by the following rules.
|
|
|
|
|
|
+A better way to compute the intereference graph is given by the
|
|
|
|
+following.
|
|
|
|
|
|
\begin{itemize}
|
|
\begin{itemize}
|
|
\item If instruction $I_k$ is a move: (\key{movq} $s$\, $d$), then add
|
|
\item If instruction $I_k$ is a move: (\key{movq} $s$\, $d$), then add
|
|
@@ -1938,6 +1962,20 @@ Figure~\ref{fig:interfere}.
|
|
\end{figure}
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
|
|
|
+\begin{exercise}\normalfont
|
|
|
|
+Implement the compiler pass named \code{build-interference} according
|
|
|
|
+to the algorithm suggested above. There are several helper functions
|
|
|
|
+in \code{utilities.rkt} for representing graphs: \code{make-graph},
|
|
|
|
+\code{add-edge}, and \code{adjacent}
|
|
|
|
+(Appendix~\ref{appendix:utilities}). The output of this pass should
|
|
|
|
+replace the live-after sets with the interference $\itm{graph}$ as
|
|
|
|
+follows.
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+ (program (|$\Var^{*}$| |$\itm{graph}$|) |$\Instr^{+}$|)
|
|
|
|
+\end{lstlisting}
|
|
|
|
+
|
|
|
|
+\end{exercise}
|
|
|
|
+
|
|
\section{Graph Coloring via Sudoku}
|
|
\section{Graph Coloring via Sudoku}
|
|
|
|
|
|
We now come to the main event, mapping variables to registers (or to
|
|
We now come to the main event, mapping variables to registers (or to
|
|
@@ -1952,45 +1990,41 @@ problem~\citep{Balakrishnan:1996ve,Rosen:2002bh}.
|
|
The reader may be more familar with the graph coloring problem then he
|
|
The reader may be more familar with the graph coloring problem then he
|
|
or she realizes; the popular game of Sudoku is an instance of the
|
|
or she realizes; the popular game of Sudoku is an instance of the
|
|
graph coloring problem. The following describes how to build a graph
|
|
graph coloring problem. The following describes how to build a graph
|
|
-out of a Sudoku board.
|
|
|
|
|
|
+out of an initial Sudoku board.
|
|
\begin{itemize}
|
|
\begin{itemize}
|
|
\item There is one node in the graph for each Sudoku square.
|
|
\item There is one node in the graph for each Sudoku square.
|
|
\item There is an edge between two nodes if the corresponding squares
|
|
\item There is an edge between two nodes if the corresponding squares
|
|
- are in the same row or column, or if the squares are in the same
|
|
|
|
- $3\times 3$ region.
|
|
|
|
|
|
+ are in the same row, in the same column, or if the squares are in
|
|
|
|
+ the same $3\times 3$ region.
|
|
\item Choose nine colors to correspond to the numbers $1$ to $9$.
|
|
\item Choose nine colors to correspond to the numbers $1$ to $9$.
|
|
\item Based on the initial assignment of numbers to squares in the
|
|
\item Based on the initial assignment of numbers to squares in the
|
|
Sudoku board, assign the corresponding colors to the corresponding
|
|
Sudoku board, assign the corresponding colors to the corresponding
|
|
nodes in the graph.
|
|
nodes in the graph.
|
|
\end{itemize}
|
|
\end{itemize}
|
|
If you can color the remaining nodes in the graph with the nine
|
|
If you can color the remaining nodes in the graph with the nine
|
|
-colors, then you've also solved the corresponding game of Sudoku.
|
|
|
|
|
|
+colors, then you have also solved the corresponding game of Sudoku.
|
|
|
|
|
|
Given that Sudoku is graph coloring, one can use Sudoku strategies to
|
|
Given that Sudoku is graph coloring, one can use Sudoku strategies to
|
|
come up with an algorithm for allocating registers. For example, one
|
|
come up with an algorithm for allocating registers. For example, one
|
|
-of the basic techniques for Sudoku is Pencil Marks. The idea is that
|
|
|
|
-you use a process of elimination to determine what numbers still make
|
|
|
|
-sense for a square, and write down those numbers in the square
|
|
|
|
-(writing very small). At first, each number might be a
|
|
|
|
-possibility, but as the board fills up, more and more of the
|
|
|
|
-possibilities are crossed off (or erased). For example, if the number
|
|
|
|
-$1$ is assigned to a square, then by process of elimination, you can
|
|
|
|
-cross off the $1$ pencil mark from all the squares in the same row,
|
|
|
|
-column, and region. Many Sudoku computer games provide automatic
|
|
|
|
-support for Pencil Marks. This heuristic also reduces the degree of
|
|
|
|
-branching in the search tree.
|
|
|
|
|
|
+of the basic techniques for Sudoku is called Pencil Marks. The idea is
|
|
|
|
+that you use a process of elimination to determine what numbers no
|
|
|
|
+longer make sense for a square, and write down those numbers in the
|
|
|
|
+square (writing very small). For example, if the number $1$ is
|
|
|
|
+assigned to a square, then by process of elimination, you can write
|
|
|
|
+the pencil mark $1$ in all the squares in the same row, column, and
|
|
|
|
+region. Many Sudoku computer games provide automatic support for
|
|
|
|
+Pencil Marks. This heuristic also reduces the degree of branching in
|
|
|
|
+the search tree.
|
|
|
|
|
|
The Pencil Marks technique corresponds to the notion of color
|
|
The Pencil Marks technique corresponds to the notion of color
|
|
-\emph{saturation} due to \cite{Brelaz:1979eu}. The
|
|
|
|
-saturation of a node, in Sudoku terms, is the number of possibilities
|
|
|
|
-that have been crossed off using the process of elimination mentioned
|
|
|
|
-above. In graph terminology, we have the following definition:
|
|
|
|
|
|
+\emph{saturation} due to \cite{Brelaz:1979eu}. The saturation of a
|
|
|
|
+node, in Sudoku terms, is the set of colors that are no longer
|
|
|
|
+available. In graph terminology, we have the following definition:
|
|
\begin{equation*}
|
|
\begin{equation*}
|
|
- \mathrm{saturation}(u) = |\{ c \;|\; \exists v. v \in \mathrm{Adj}(u)
|
|
|
|
- \text{ and } \mathrm{color}(v) = c \}|
|
|
|
|
|
|
+ \mathrm{saturation}(u) = \{ c \;|\; \exists v. v \in \mathrm{adjacent}(u)
|
|
|
|
+ \text{ and } \mathrm{color}(v) = c \}
|
|
\end{equation*}
|
|
\end{equation*}
|
|
-where $\mathrm{Adj}(u)$ is the set of nodes adjacent to $u$ and
|
|
|
|
-the notation $|S|$ stands for the size of the set $S$.
|
|
|
|
|
|
+where $\mathrm{adjacent}(u)$ is the set of nodes adjacent to $u$.
|
|
|
|
|
|
Using the Pencil Marks technique leads to a simple strategy for
|
|
Using the Pencil Marks technique leads to a simple strategy for
|
|
filling in numbers: if there is a square with only one possible number
|
|
filling in numbers: if there is a square with only one possible number
|
|
@@ -1998,28 +2032,28 @@ left, then write down that number! But what if there are no squares
|
|
with only one possibility left? One brute-force approach is to just
|
|
with only one possibility left? One brute-force approach is to just
|
|
make a guess. If that guess ultimately leads to a solution, great. If
|
|
make a guess. If that guess ultimately leads to a solution, great. If
|
|
not, backtrack to the guess and make a different guess. Of course,
|
|
not, backtrack to the guess and make a different guess. Of course,
|
|
-this is horribly time consuming. One standard way to reduce the amount
|
|
|
|
-of backtracking is to use the most-constrained-first heuristic. That
|
|
|
|
-is, when making a guess, always choose a square with the fewest
|
|
|
|
-possibilities left (the node with the highest saturation). The idea
|
|
|
|
-is that choosing highly constrained squares earlier rather than later
|
|
|
|
-is better because later there may not be any possibilities left.
|
|
|
|
|
|
+backtracking can be horribly time consuming. One standard way to
|
|
|
|
+reduce the amount of backtracking is to use the most-constrained-first
|
|
|
|
+heuristic. That is, when making a guess, always choose a square with
|
|
|
|
+the fewest possibilities left (the node with the highest saturation).
|
|
|
|
+The idea is that choosing highly constrained squares earlier rather
|
|
|
|
+than later is better because later there may not be any possibilities.
|
|
|
|
|
|
In some sense, register allocation is easier than Sudoku because we
|
|
In some sense, register allocation is easier than Sudoku because we
|
|
-can always cheat and add more numbers by spilling variables to the
|
|
|
|
-stack. Also, we'd like to minimize the time needed to color the graph,
|
|
|
|
-and backtracking is expensive. Thus, it makes sense to keep the
|
|
|
|
-most-constrained-first heuristic but drop the backtracking in favor of
|
|
|
|
-greedy search (guess and just keep going).
|
|
|
|
|
|
+can always cheat and add more numbers by mapping variables to the
|
|
|
|
+stack. We say that a variable is \emph{spilled} when we decide to map
|
|
|
|
+it to a stack location. We would like to minimize the time needed to
|
|
|
|
+color the graph, and backtracking is expensive. Thus, it makes sense
|
|
|
|
+to keep the most-constrained-first heuristic but drop the backtracking
|
|
|
|
+in favor of greedy search (guess and just keep going).
|
|
Figure~\ref{fig:satur-algo} gives the pseudo-code for this simple
|
|
Figure~\ref{fig:satur-algo} gives the pseudo-code for this simple
|
|
greedy algorithm for register allocation based on saturation and the
|
|
greedy algorithm for register allocation based on saturation and the
|
|
most-constrained-first heuristic, which is roughly equivalent to the
|
|
most-constrained-first heuristic, which is roughly equivalent to the
|
|
-DSATUR algorithm of \cite{Brelaz:1979eu} (also known as
|
|
|
|
-saturation degree ordering
|
|
|
|
-(SDO)~\citep{Gebremedhin:1999fk,Omari:2006uq}). Just as in Sudoku,
|
|
|
|
-the algorithm represents colors with integers, with the first $k$
|
|
|
|
-colors corresponding to the $k$ registers in a given machine and the
|
|
|
|
-rest of the integers corresponding to stack locations.
|
|
|
|
|
|
+DSATUR algorithm of \cite{Brelaz:1979eu} (also known as saturation
|
|
|
|
+degree ordering (SDO)~\citep{Gebremedhin:1999fk,Omari:2006uq}). Just
|
|
|
|
+as in Sudoku, the algorithm represents colors with integers, with the
|
|
|
|
+first $k$ colors corresponding to the $k$ registers in a given machine
|
|
|
|
+and the rest of the integers corresponding to stack locations.
|
|
|
|
|
|
\begin{figure}[btp]
|
|
\begin{figure}[btp]
|
|
\centering
|
|
\centering
|
|
@@ -2032,7 +2066,7 @@ Output: an assignment |$\mathrm{color}[v]$| for each node |$v \in G$|
|
|
while |$W \neq \emptyset$| do
|
|
while |$W \neq \emptyset$| do
|
|
pick a node |$u$| from |$W$| with the highest saturation,
|
|
pick a node |$u$| from |$W$| with the highest saturation,
|
|
breaking ties randomly
|
|
breaking ties randomly
|
|
- find the lowest color |$c$| that is not in |$\{ \mathrm{color}[v] \;:\; v \in \mathrm{Adj}(v)\}$|
|
|
|
|
|
|
+ find the lowest color |$c$| that is not in |$\{ \mathrm{color}[v] \;:\; v \in \mathrm{adjacent}(v)\}$|
|
|
|$\mathrm{color}[u] \gets c$|
|
|
|$\mathrm{color}[u] \gets c$|
|
|
|$W \gets W - \{u\}$|
|
|
|$W \gets W - \{u\}$|
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
@@ -2065,9 +2099,9 @@ dash for their color and an empty set for the saturation.
|
|
\end{tikzpicture}
|
|
\end{tikzpicture}
|
|
\]
|
|
\]
|
|
We select a maximally saturated node and color it $0$. In this case we
|
|
We select a maximally saturated node and color it $0$. In this case we
|
|
-have a 5-way tie, so we arbitrarily pick $y$. The color $0$ is no
|
|
|
|
-longer available for $w$, $x$, and $z$ because they interfere with
|
|
|
|
-$y$.
|
|
|
|
|
|
+have a 5-way tie, so we arbitrarily pick $y$. The then mark color $0$
|
|
|
|
+as no longer available for $w$, $x$, and $z$ because they interfere
|
|
|
|
+with $y$.
|
|
\[
|
|
\[
|
|
\begin{tikzpicture}[baseline=(current bounding box.center)]
|
|
\begin{tikzpicture}[baseline=(current bounding box.center)]
|
|
\node (v) at (0,0) {$v:-,\{\}$};
|
|
\node (v) at (0,0) {$v:-,\{\}$};
|
|
@@ -2171,13 +2205,12 @@ The last iteration of the coloring algorithm assigns color $0$ to $v$.
|
|
\draw (z) to (y);
|
|
\draw (z) to (y);
|
|
\end{tikzpicture}
|
|
\end{tikzpicture}
|
|
\]
|
|
\]
|
|
-With the coloring complete, we can finalize assignment of variables to
|
|
|
|
-registers and stack locations. Recall that if we have $k$ registers,
|
|
|
|
-we map the first $k$ colors to registers and the rest to stack
|
|
|
|
-locations.
|
|
|
|
-Suppose for the moment that we just have one extra register
|
|
|
|
-to use for register allocation, just \key{rbx}. Then the following is
|
|
|
|
-the mapping of colors to registers and stack allocations.
|
|
|
|
|
|
+With the coloring complete, we can finalize the assignment of
|
|
|
|
+variables to registers and stack locations. Recall that if we have $k$
|
|
|
|
+registers, we map the first $k$ colors to registers and the rest to
|
|
|
|
+stack locations. Suppose for the moment that we just have one extra
|
|
|
|
+register to use for register allocation, just \key{rbx}. Then the
|
|
|
|
+following is the mapping of colors to registers and stack allocations.
|
|
\[
|
|
\[
|
|
\{ 0 \mapsto \key{\%rbx}, \; 1 \mapsto \key{-8(\%rbp)}, \; 2 \mapsto \key{-16(\%rbp)}, \ldots \}
|
|
\{ 0 \mapsto \key{\%rbx}, \; 1 \mapsto \key{-8(\%rbp)}, \; 2 \mapsto \key{-16(\%rbp)}, \ldots \}
|
|
\]
|
|
\]
|
|
@@ -2196,26 +2229,26 @@ Applying this assignment to our running example
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(program 32
|
|
(program 32
|
|
(movq (int 1) (reg rbx))
|
|
(movq (int 1) (reg rbx))
|
|
- (movq (int 46) (stack-loc -8))
|
|
|
|
- (movq (reg rbx) (stack-loc -16))
|
|
|
|
- (addq (int 7) (stack-loc -16))
|
|
|
|
- (movq (stack-loc 16) (reg rbx))
|
|
|
|
|
|
+ (movq (int 46) (stack -8))
|
|
|
|
+ (movq (reg rbx) (stack -16))
|
|
|
|
+ (addq (int 7) (stack -16))
|
|
|
|
+ (movq (stack 16) (reg rbx))
|
|
(addq (int 4) (reg rbx))
|
|
(addq (int 4) (reg rbx))
|
|
- (movq (stack-loc -16) (stack-loc -16))
|
|
|
|
- (addq (stack-loc -8) (stack-loc -16))
|
|
|
|
- (movq (stack-loc -16) (reg rax))
|
|
|
|
|
|
+ (movq (stack -16) (stack -16))
|
|
|
|
+ (addq (stack -8) (stack -16))
|
|
|
|
+ (movq (stack -16) (reg rax))
|
|
(subq (reg rbx) (reg rax)))
|
|
(subq (reg rbx) (reg rax)))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
This program is almost an x86-64 program. The remaining step is to apply
|
|
This program is almost an x86-64 program. The remaining step is to apply
|
|
the patch instructions pass. In this example, the trivial move of
|
|
the patch instructions pass. In this example, the trivial move of
|
|
-\key{-16(\%rbp)} to itself is deleted and the addition of
|
|
|
|
-\key{-8(\%rbp)} to \key{-16(\%rbp)} is fixed by going through
|
|
|
|
-\key{\%rax}. The following shows the portion of the program that
|
|
|
|
|
|
+\code{-16(\%rbp)} to itself is deleted and the addition of
|
|
|
|
+\code{-8(\%rbp)} to \key{-16(\%rbp)} is fixed by going through
|
|
|
|
+\code{rax}. The following shows the portion of the program that
|
|
changed.
|
|
changed.
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(addq (int 4) (reg rbx))
|
|
(addq (int 4) (reg rbx))
|
|
- (movq (stack-loc -8) (reg rax)
|
|
|
|
- (addq (reg rax) (stack-loc -16))
|
|
|
|
|
|
+ (movq (stack -8) (reg rax)
|
|
|
|
+ (addq (reg rax) (stack -16))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
An overview of all of the passes involved in register allocation is
|
|
An overview of all of the passes involved in register allocation is
|
|
shown in Figure~\ref{fig:reg-alloc-passes}.
|
|
shown in Figure~\ref{fig:reg-alloc-passes}.
|
|
@@ -2230,17 +2263,35 @@ shown in Figure~\ref{fig:reg-alloc-passes}.
|
|
\node (5) at (0,-4.5) {$\text{x86-64}^{*}$};
|
|
\node (5) at (0,-4.5) {$\text{x86-64}^{*}$};
|
|
\node (6) at (3.5,-4.5) {$\text{x86-64}$};
|
|
\node (6) at (3.5,-4.5) {$\text{x86-64}$};
|
|
|
|
|
|
-\path[->] (1) edge [above] node {\ttfamily\scriptsize select-instr.} (2);
|
|
|
|
|
|
+\path[->] (1) edge [above] node {\ttfamily\scriptsize select-instructions} (2);
|
|
\path[->] (2) edge [right] node {\ttfamily\scriptsize uncover-live} (3);
|
|
\path[->] (2) edge [right] node {\ttfamily\scriptsize uncover-live} (3);
|
|
\path[->] (3) edge [right] node {\ttfamily\scriptsize build-interference} (4);
|
|
\path[->] (3) edge [right] node {\ttfamily\scriptsize build-interference} (4);
|
|
\path[->] (4) edge [left] node {\ttfamily\scriptsize allocate-registers} (5);
|
|
\path[->] (4) edge [left] node {\ttfamily\scriptsize allocate-registers} (5);
|
|
-\path[->] (5) edge [above] node {\ttfamily\scriptsize patch-instr.} (6);
|
|
|
|
|
|
+\path[->] (5) edge [above] node {\ttfamily\scriptsize patch-instructions} (6);
|
|
\end{tikzpicture}
|
|
\end{tikzpicture}
|
|
\]
|
|
\]
|
|
\caption{Diagram of the passes for register allocation.}
|
|
\caption{Diagram of the passes for register allocation.}
|
|
\label{fig:reg-alloc-passes}
|
|
\label{fig:reg-alloc-passes}
|
|
\end{figure}
|
|
\end{figure}
|
|
|
|
|
|
|
|
+\begin{exercise}\normalfont
|
|
|
|
+Implement the pass \code{allocate-registers} and test it by creating
|
|
|
|
+new example programs that exercise all of the register allocation
|
|
|
|
+algorithm, such as forcing variables to be spilled to the stack.
|
|
|
|
+
|
|
|
|
+I recommend organizing our code by creating a helper function named
|
|
|
|
+\code{allocate-homes} that takes an interference graph, a list of all
|
|
|
|
+the variables in the program, and the list of statements. This
|
|
|
|
+function should return a mapping of variables to their homes
|
|
|
|
+(registers or stack locations) and the total size needed for the
|
|
|
|
+stack. By creating this helper function, we will be able to reuse it
|
|
|
|
+in Chapter~\ref{ch:functions} when we add support for functions.
|
|
|
|
+
|
|
|
|
+Once you have obtained the mapping from \code{allocate-homes}, you can
|
|
|
|
+use the \code{assign-homes} function from Section~\ref{sec:assign-s0}
|
|
|
|
+to replace the variables with their homes.
|
|
|
|
+\end{exercise}
|
|
|
|
+
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Booleans, Type Checking, and Control Flow}
|
|
\chapter{Booleans, Type Checking, and Control Flow}
|
|
@@ -2470,6 +2521,9 @@ The \key{lookup} function ...
|
|
|
|
|
|
The \key{map2} function ...
|
|
The \key{map2} function ...
|
|
|
|
|
|
|
|
+The \code{make-graph}, \code{add-edge}, and \code{adjacent}
|
|
|
|
+functions...
|
|
|
|
+
|
|
The \key{interp-tests} function takes a compiler name (a string) a
|
|
The \key{interp-tests} function takes a compiler name (a string) a
|
|
description of the passes a test family name (a string), and a list of
|
|
description of the passes a test family name (a string), and a list of
|
|
test numbers, and runs the compiler passes and the interpreters to
|
|
test numbers, and runs the compiler passes and the interpreters to
|