Переглянути джерело

register allocation finished

Jeremy Siek 9 роки тому
батько
коміт
7d8dc93663
1 змінених файлів з 151 додано та 78 видалено
  1. 151 78
      book.tex

+ 151 - 78
book.tex

@@ -768,28 +768,31 @@ variables instead of stack locations or registers.
 \begin{minipage}{0.45\textwidth}
 Source program:
 \begin{lstlisting}
-(let ([x 25])
-  (let ([z (+ 9 x)])
-    (let ([y 2])
-      (let ([w (+ 10 z)])
-        (- w y)))))
+  (let ([v 1])
+  (let ([w 46])
+  (let ([x (+ v 7)])
+  (let ([y (+ 4 x)])
+  (let ([z (+ x w)])
+       (- z y))))))
 \end{lstlisting}
 \end{minipage}
 \begin{minipage}{0.45\textwidth}
 After instruction selection:
 \begin{lstlisting}
-(program (x z y w)
-  (mov (int 25) (var x))
-  (mov (int 9) (var z))
-  (add (var x) (var z))
-  (mov (int 2) (var y))
-  (mov (int 10) (var w))
-  (add (var z) (var w))
-  (mov (var w) (reg rax))
-  (sub (var y) (reg rax)))
+  (program (v w x y z)
+    (mov (int 1) (var v))
+    (mov (int 46) (var w))
+    (mov (var v) (var x))
+    (add (int 7) (var x))
+    (mov (var x) (var y))
+    (add (int 4) (var y))
+    (mov (var x) (var z))
+    (add (var w) (var z))
+    (mov (var z) (reg rax))
+    (sub (var y) (reg rax)))
 \end{lstlisting}
 \end{minipage}
-\caption{Program to serve as running example for this chapter.}
+\caption{Running example for this chapter.}
 \label{fig:reg-eg}
 \end{figure}
 
@@ -813,18 +816,18 @@ in the program and there is not an intervening assignment to the
 variable.
 %
 To understand the latter condition, consider the following code
-fragment in which there are two writes to $y$. Are $x$ and
-$y$ both live at the same time? 
+fragment in which there are two writes to $b$. Are $a$ and
+$b$ both live at the same time? 
 \begin{lstlisting}[numbers=left,numberstyle=\tiny]
-(mov (int 5) (var x))    ; @$x \gets 5$@
-(mov (int 30) (var y))   ; @$y \gets 30$@
-(mov (var x) (var z))    ; @$z \gets x$@
-(mov (int 10) (var y))   ; @$y \gets 10$@
-(add (var y) (var z))    ; @$z \gets z + y$@
+(mov (int 5) (var a))    ; @$a \gets 5$@
+(mov (int 30) (var b))   ; @$b \gets 30$@
+(mov (var a) (var c))    ; @$c \gets x$@
+(mov (int 10) (var b))   ; @$b \gets 10$@
+(add (var b) (var c))    ; @$c \gets c + b$@
 \end{lstlisting}
-The answer is no because the value $30$ written to $y$ on line 2 is
-never used. The variable $y$ is read on line 5 and there is an
-intervening write to $y$ on line 4, so the read on line 5 receives the
+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 live variables can be computed by traversing the instruction
@@ -856,22 +859,24 @@ $L_{\mathtt{after}}$ set.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
-(program (x z y w)
-  (mov (int 25) (var x))      @$\{x\}$@
-  (mov (int 9) (var z))       @$\{x,z\}$@
-  (add (var x) (var z))       @$\{z\}$@
-  (mov (int 2) (var y))       @$\{y,z\}$@
-  (mov (int 10) (var w))      @$\{w,y,z\}$@
-  (add (var z) (var w))       @$\{w,y\}$@
-  (mov (var w) (reg rax))     @$\{y\}$@
-  (sub (var y) (reg rax)))    @$\{\}$@
+  (program (v w x y z)
+    (mov (int 1) (var v))      @$\{ v \}$@
+    (mov (int 46) (var w))     @$\{ v, w \}$@
+    (mov (var v) (var x))      @$\{ w, x \}$@
+    (add (int 7) (var x))      @$\{ w, x \}$@
+    (mov (var x) (var y))      @$\{ w, x, y\}$@
+    (add (int 4) (var y))      @$\{ w, x, y \}$@
+    (mov (var x) (var z))      @$\{ w, y, z \}$@
+    (add (var w) (var z))      @$\{ y, z \}$@
+    (mov (var z) (reg rax))    @$\{ y \}$@
+    (sub (var y) (reg rax)))   @$\{\}$@
 \end{lstlisting}
 \caption{Running example program annotated with live-after sets.}
 \label{fig:live-eg}
 \end{figure}
 
 
-\section{Build 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
@@ -919,11 +924,11 @@ Figure~\ref{fig:interfere}.
 \large
 \[
 \xymatrix@=40pt{
-  w \ar@{-}[d]\ar@{-}[dr] &  x \ar@{-}[d]\\
-  y \ar@{-}[r] & z
+  v \ar@{-}[r] & w \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x \ar@{-}[dl]\\
+               & y \ar@{-}[r] & z
 }
 \]
-\caption{Interference graph for the example program.}
+\caption{Interference graph for the running example.}
 \label{fig:interfere}
 \end{figure}
 
@@ -984,17 +989,16 @@ the notation $|S|$ stands for the size of the set $S$.
 
 Using the Pencil Marks technique leads to a simple strategy for
 filling in numbers: if there is a square with only one possible number
-left, then write down that number! But what if there aren't any
-squares 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 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.
+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
+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,
+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.
 
 In some sense, register allocation is easier than Sudoku because we
 can always cheat and add more numbers by spilling variables to the
@@ -1032,42 +1036,109 @@ while @$W \neq \emptyset$@ do
 \end{figure}
 
 
-UNDER CONSTRUCTION
-
-
-Suppose only \key{rbx} is available for use by the register allocator.
-
+With this algorithm in hand, let us return to the running example and
+consider how to color the interference graph in
+Figure~\ref{fig:interfere}. Initially, all of the nodes are not yet
+colored and they are unsaturated, so we annotate each of them with a
+dash for their color and an empty set for the saturation.
 \[
-\xymatrix@=40pt{
-  w:\key{-16(\%rbp)} \ar@{-}[d] \ar@{-}[dr] &  x:\key{\%rbx} \ar@{-}[d] \\
-  y:\key{\%rbx} \ar@{-}[r] & z:\key{-8(\%rbp)}
+\xymatrix{
+  v:-,\{\} \ar@{-}[r] & w:-,\{\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:-,\{\} \ar@{-}[dl]\\
+               & y:-,\{\} \ar@{-}[r] & z:-,\{\}
+}
+\]
+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$.
+\[
+\xymatrix{
+  v:-,\{\} \ar@{-}[r] & w:-,\{0\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:-,\{0\} \ar@{-}[dl]\\
+               & y:0,\{\} \ar@{-}[r] & z:-,\{0\}
+}
+\]
+Now we repeat the process, selecting another maximally saturated node.
+This time there is a three-way tie between $w$, $x$, and $z$. We color
+$w$ with $1$.
+\[
+\xymatrix{
+  v:-,\{1\} \ar@{-}[r] & w:1,\{0\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:-,\{0,1\} \ar@{-}[dl]\\
+               & y:0,\{1\} \ar@{-}[r] & z:-,\{0,1\}
+}
+\]
+The most saturated nodes are now $x$ and $z$. We color $x$ with the
+next avialable color which is $2$.
+\[
+\xymatrix{
+  v:-,\{1\} \ar@{-}[r] & w:1,\{0,2\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:2,\{0,1\} \ar@{-}[dl]\\
+               & y:0,\{1,2\} \ar@{-}[r] & z:-,\{0,1\}
+}
+\]
+We have only two nodes left to color, $v$ and $z$, but $z$ is
+more highly saturaded, so we color $z$ with $2$.
+\[
+\xymatrix{
+  v:-,\{1\} \ar@{-}[r] & w:1,\{0,2\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:2,\{0,1\} \ar@{-}[dl]\\
+               & y:0,\{1,2\} \ar@{-}[r] & z:2,\{0,1\}
+}
+\]
+The last iteration of the coloring algorithm assigns color $0$ to $v$.
+\[
+\xymatrix{
+  v:0,\{1\} \ar@{-}[r] & w:1,\{0,2\} \ar@{-}[r]\ar@{-}[d]\ar@{-}[dr] &  x:2,\{0,1\} \ar@{-}[dl]\\
+               & y:0,\{1,2\} \ar@{-}[r] & z:2,\{0,1\}
 }
 \]
 
+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
+lcoations. 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 \}
+\]
+Putting this together with the above coloring of the variables, we
+arrive at the following assignment.
+\[
+  \{ v \mapsto \key{\%rbx}, \;
+  w \mapsto \key{-8(\%rbp)},  \;
+  x \mapsto \key{-16(\%rbp)}, \;
+  y \mapsto \key{\%rbx},  \;
+  z\mapsto \key{-16(\%rbp)} \}
+\]
+Applying this assignment to our running example
+(Figure~\ref{fig:reg-eg}) yields the following program.
+% why frame size of 32? -JGS
 \begin{lstlisting}
-	movq	$25, %rbx
-	movq	$9, -8(%rbp)
-	addq	%rbx, -8(%rbp)
-	movq	$2, %rbx
-	movq	$10, -16(%rbp)
-	addq	-8(%rbp), -16(%rbp)
-	movq	-16(%rbp), %rax
-	subq	%rbx, %rax
+(program 32
+  (mov (int 1) (reg rbx))
+  (mov (int 46) (stack-loc -8))
+  (mov (reg rbx) (stack-loc -16))
+  (add (int 7) (stack-loc -16))
+  (mov (stack-loc 16) (reg rbx))
+  (add (int 4) (reg rbx))
+  (mov (stack-loc -16) (stack-loc -16))
+  (add (stack-loc -8) (stack-loc -16))
+  (mov (stack-loc -16) (reg rax))
+  (sub (reg rbx) (reg rax)))
 \end{lstlisting}
-
-patch instructions fixes the addition of
-\key{-8(\%rbp)} to  \key{-16(\%rbp)}.
-
+This program is almost an x86 program. The remaining step is to apply
+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
+changed.
 \begin{lstlisting}
-	movq	-8(%rbp), %rax
-	addq	%rax, -16(%rbp)
+  (add (int 4) (reg rbx))
+  (mov (stack-loc -8) (reg rax)
+  (add (reg rax) (stack-loc -16))
 \end{lstlisting}
+An overview of all of the passes involved in register allocation is
+shown in Figure~\ref{fig:reg-alloc-passes}.
 
-% three new passes between instruction selection and spill code
-% uncover-live
-% build-interference
-% allocate registers (uses assign-homes)
-
+\begin{figure}[tbp]
 \[
 \xymatrix{
   C_0 \ar@/^/[r]^-{\textsf{select\_instr.}}
@@ -1078,11 +1149,13 @@ patch instructions fixes the addition of
     & \text{x86} 
 }
 \]
-
+\caption{Diagram of the passes for register allocation.}
+\label{fig:reg-alloc-passes}
+\end{figure}
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\chapter{Booleans, Conditions, and Type Checking}
+\chapter{Booleans, Type Checking, and Control Flow}
 \label{ch:bool-types}