ソースを参照

edits to Ch 2

Jeremy Siek 4 年 前
コミット
da2143eb8c
1 ファイル変更257 行追加213 行削除
  1. 257 213
      book.tex

+ 257 - 213
book.tex

@@ -76,6 +76,7 @@
 \lstset{%
 language=Lisp,
 basicstyle=\ttfamily\small,
+morekeywords={seq,assign,program,block,define,lambda,match},
 escapechar=|,
 columns=flexible,
 moredelim=[is][\color{red}]{~}{~}
@@ -962,7 +963,7 @@ of x86 in later chapters. Once we have introduced $R_1$ and x86, we
 reflect on their differences and come up with a plan to break down the
 translation from $R_1$ to x86 into a handful of steps
 (Section~\ref{sec:plan-s0-x86}).  The rest of the sections in this
-Chapter give detailed hints regarding each step
+chapter give detailed hints regarding each step
 (Sections~\ref{sec:uniquify-s0} through \ref{sec:patch-s0}).  We hope
 to give enough hints that the well-prepared reader, together with some
 friends, can implement a compiler from $R_1$ to x86 in a couple weeks
@@ -1239,18 +1240,18 @@ for each procedure call. The memory layout for an individual frame is
 shown in Figure~\ref{fig:frame}.  The register \key{rsp} is called the
 \emph{stack pointer} and points to the item at the top of the
 stack. The stack grows downward in memory, so we increase the size of
-the stack by subtracting from the stack pointer. The frame size is
-required to be a multiple of 16 bytes. In the context of a procedure
-call, the \emph{return address} is the next instruction after the call
-instruction on the caller side. During a function call, the return
-address is pushed onto the stack.  The register \key{rbp} is the
-\emph{base pointer} which serves two purposes: 1) it saves the
-location of the stack pointer for the calling procedure and 2) it is
-used to access variables associated with the current procedure.  The
-base pointer of the calling procedure is pushed onto the stack after
-the return address. We number the variables from $1$ to $n$. Variable
-$1$ is stored at address $-8\key{(\%rbp)}$, variable $2$ at
-$-16\key{(\%rbp)}$, etc.
+the stack by subtracting from the stack pointer. Some operating
+systems require the frame size to be a multiple of 16 bytes. In the
+context of a procedure call, the \emph{return address} is the next
+instruction after the call instruction on the caller side. During a
+function call, the return address is pushed onto the stack.  The
+register \key{rbp} is the \emph{base pointer} which serves two
+purposes: 1) it saves the location of the stack pointer for the
+calling procedure and 2) it is used to access variables associated
+with the current procedure.  The base pointer of the calling procedure
+is pushed onto the stack after the return address. We number the
+variables from $1$ to $n$. Variable $1$ is stored at address
+$-8\key{(\%rbp)}$, variable $2$ at $-16\key{(\%rbp)}$, etc.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
@@ -1423,9 +1424,9 @@ non-terminal in the grammar of the input language of the pass.
   
 \item[Pass \key{explicate-control}] To make the execution order of the
   program explicit, we shall convert from the abstract syntax tree
-  representation into a graph representation in which each node
-  contains a sequence of statements and the edges say where to go
-  after the sequence is complete.
+  representation into a \emph{control-flow graph} in which each node
+  contains a sequence of statements and the edges between nodes say
+  where to go next.
 
 \item[Pass \key{assign-homes}] To handle the difference between the
   variables in $R_1$ versus the registers and stack location in x86,
@@ -1452,53 +1453,42 @@ inadvertently change the behavior of the program.  But if we apply
 that in \key{remove-complex-opera*}, we need to ensure that the
 temporary variables that it creates are unique.
 
-Next we shall consider the ordering of the \key{explicate-control}
-pass and \key{select-instructions}. It is clear that
-\key{explicate-control} must come first because the control-flow graph
-that it generates is needed when determining where to place the x86
-label and jump instructions.
+What should be the ordering of \key{explicate-control} with respect to
+\key{uniquify}? The \key{uniquify} pass should come first because
+\key{explicate-control} changes all the \key{let}-bound variables to
+become local variables whose scope is the entire program, which would
+confuse variables with the same name.
 %
-Regarding the ordering of \key{explicate-control} with respect to
-\key{uniquify}, it is important to apply \key{uniquify} first because
-in \key{explicate-control} we change all the \key{let}-bound variables
-to become local variables whose scope is the entire program.
+Likewise, we place \key{explicate-control} after
+\key{remove-complex-opera*} because \key{explicate-control} removes
+the \key{let} form, but it is convenient to use \key{let} in the
+output of \key{remove-complex-opera*}.
 %
-With respect to \key{remove-complex-opera*}, it perhaps does not
-matter very much, but it works well to place \key{explicate-control}
-after removing complex subexpressions.
-
-Next consider the ordering of the \key{assign-homes} pass with respect
-to \key{remove-complex-opera*} and \key{explicate-control}.
-%
-Removing complex subexpression requires generating temporary variables
-which then need to be assigned homes, so \key{assign-homes} should
-come after \key{remove-complex-opera*}.
-%
-The \key{explicate-control} pass
-deletes branches that will never be executed, which can remove
-variables. Thus it is good to place \key{explicate-control} prior to
-\key{assign-homes} so that there are fewer variables that need to be
-assigned homes. This is important because the \key{assign-homes} pass
-has the highest time complexity.
+Regarding \key{assign-homes}, it is helpful to place
+\key{explicate-control} first because \key{explicate-control} changes
+\key{let}-bound variables into program-scope variables.  Instead of
+traversing the entire program for \key{let}-bound variables,
+\key{assign-homes} can read them off from the $\itm{info}$ of the
+\key{program} AST node.
 
 Last, we need to decide on the ordering of \key{select-instructions}
-and \key{assign-homes}.  These two issues are intertwined, creating a
-bit of a Gordian Knot. To do a good job of assigning homes, it is
-helpful to have already determined which instructions will be used,
-because x86 instructions have restrictions about which of their
-arguments can be registers versus stack locations. For example, one
-can give preferential treatment to variables that occur in
-register-argument positions. On the other hand, it may turn out to be
-impossible to make sure that all such variables are assigned to
-registers, and then one must redo the selection of instructions. Some
-compilers handle this problem by iteratively repeating these two
-passes until a good solution is found.  We shall use a simpler
-approach in which \key{select-instructions} comes first, followed by
-the \key{assign-homes}, followed by a third pass, named
-\key{patch-instructions}, that uses a reserved register (\key{rax}) to
-patch-up outstanding problems regarding instructions with too many
-memory accesses. The disadvantage of this approach a reduction in
-runtime efficiency.
+and \key{assign-homes}.  These two passes are intertwined, creating a
+Gordian Knot. To do a good job of assigning homes, it is helpful to
+have already determined which instructions will be used, because x86
+instructions have restrictions about which of their arguments can be
+registers versus stack locations. For example, one can give
+preferential treatment to variables that occur in register-argument
+positions. On the other hand, it may turn out to be impossible to make
+sure that all such variables are assigned to registers, and then one
+must redo the selection of instructions. Some compilers handle this
+problem by iteratively repeating these two passes until a good
+solution is found.  We shall use a simpler approach in which
+\key{select-instructions} comes first, followed by the
+\key{assign-homes}, followed by a third pass, named
+\key{patch-instructions}, that uses a reserved register to patch-up
+outstanding problems regarding instructions with too many memory
+accesses. The disadvantage of this approach a reduction in runtime
+efficiency.
 
 
 \begin{figure}[tbp]
@@ -1506,7 +1496,7 @@ runtime efficiency.
 \node (R1) at (0,2)  {\large $R_1$};
 \node (R1-2) at (3,2)  {\large $R_1$};
 \node (R1-3) at (6,2)  {\large $R_1$};
-\node (C0-1) at (6,0)  {\large $C_0$};
+%\node (C0-1) at (6,0)  {\large $C_0$};
 \node (C0-2) at (3,0)  {\large $C_0$};
 
 \node (x86-2) at (3,-2)  {\large $\text{x86}^{*}_0$};
@@ -1516,8 +1506,8 @@ runtime efficiency.
 
 \path[->,bend left=15] (R1) edge [above] node {\ttfamily\footnotesize uniquify} (R1-2);
 \path[->,bend left=15] (R1-2) edge [above] node {\ttfamily\footnotesize remove-complex.} (R1-3);
-\path[->,bend left=15] (R1-3) edge [right] node {\ttfamily\footnotesize explicate-control} (C0-1);
-\path[->,bend right=15] (C0-1) edge [above] node {\ttfamily\footnotesize uncover-locals} (C0-2);
+\path[->,bend left=15] (R1-3) edge [right] node {\ttfamily\footnotesize explicate-control} (C0-2);
+%\path[->,bend right=15] (C0-1) edge [above] node {\ttfamily\footnotesize uncover-locals} (C0-2);
 \path[->,bend right=15] (C0-2) edge [left] node {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend left=15] (x86-2) edge [above] node {\ttfamily\footnotesize assign-homes} (x86-3);
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
@@ -1535,16 +1525,23 @@ of \key{uniquify} and \key{remove-complex-opera*} are programs that
 are still in the $R_1$ language, but the output of the pass
 \key{explicate-control} is in a different language that is designed to
 make the order of evaluation explicit in its syntax, which we
-introduce in the next section. Also, there are two passes of lesser
-importance in Figure~\ref{fig:R1-passes} that we have not yet talked
-about, \key{uncover-locals} and \key{print-x86}. We shall discuss them
-later in this Chapter.
+introduce in the next section. The last pass in
+Figure~\ref{fig:R1-passes} is \key{print-x86}, which converts from the
+abstract syntax of $\text{x86}_0$ to the concrete (textual) syntax of
+x86.
+
+In the next sections we discuss the $C_0$ language and the
+$\text{x86}^{*}_0$ and $\text{x86}^{\dagger}_0$ dialects of x86.  The
+remainder of this chapter gives hints regarding the implementation of
+each of the compiler passes in Figure~\ref{fig:R1-passes}.
+
 
 \subsection{The $C_0$ Intermediate Language}
 
-It so happens that the output of \key{explicate-control} is vaguely
-similar to the $C$ language~\citep{Kernighan:1988nx}, so we name it
-$C_0$.  The syntax for $C_0$ is defined in Figure~\ref{fig:c0-syntax}.
+The output of \key{explicate-control} is similar to the $C$
+language~\citep{Kernighan:1988nx} in that it has separate syntactic
+categories for expressions and statements, so we name it $C_0$.  The
+syntax for $C_0$ is defined in Figure~\ref{fig:c0-syntax}.
 %
 The $C_0$ language supports the same operators as $R_1$ but the
 arguments of operators are now restricted to just variables and
@@ -1562,18 +1559,18 @@ expression in tail position may contain subexpressions, and those may
 or may not be in tail position depending on the kind of expression.)
 
 A $C_0$ program consists of an association list mapping labels to
-tails. This is overkill for the present Chapter, as we do not yet need
+tails. This is overkill for the present chapter, as we do not yet need
 to introduce \key{goto} for jumping to labels, but it saves us from
 having to change the syntax of the program construct in
 Chapter~\ref{ch:bool-types}.  For now there will be just one label,
-\key{start}, and the whole program will be it's tail.
+\key{start}, and the whole program is it's tail.
 %
 The $\itm{info}$ field of the program construct, after the
-\key{uncover-locals} pass, will contain a mapping from the symbol
+\key{explicate-control} pass, contains a mapping from the symbol
 \key{locals} to a list of variables, that is, a list of all the
 variables used in the program. At the start of the program, these
-variables are uninitialized (they contain garbage) and each variable
-becomes initialized on its first assignment.
+variables are uninitialized; they become initialized on their first
+assignment.
 
 \begin{figure}[tbp]
 \fbox{
@@ -1622,18 +1619,19 @@ C_0 & ::= & (\key{program}\;\itm{info}\;((\itm{label}\,\key{.}\,\Tail)^{+}))
 \subsection{The dialects of x86}
 
 The x86$^{*}_0$ language, pronounced ``pseudo-x86'', is the output of
-the pass \key{select-instructions}. It extends $x86_0$ with variables
-and looser rules regarding instruction arguments. The x86$^{\dagger}$
-language, the output of \key{print-x86}, is the concrete syntax for
-x86.
+the pass \key{select-instructions}. It extends $x86_0$ with an unbound
+number program-scope variables and has looser rules regarding
+instruction arguments. The x86$^{\dagger}$ language, the output of
+\key{print-x86}, is the concrete syntax for x86.
 
 
 \section{Uniquify Variables}
 \label{sec:uniquify-s0}
 
-The purpose of this pass is to make sure that each \key{let} uses a
-unique variable name. For example, the \code{uniquify} pass should
-translate the program on the left into the program on the right. \\
+The \code{uniquify} pass compiles arbitrary $R_1$ programs into $R_1$
+programs in which every \key{let} uses a unique variable name. For
+example, the \code{uniquify} pass should translate the program on the
+left into the program on the right. \\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
@@ -1688,15 +1686,15 @@ list. The \code{uniquify} function will need to access this
 association list when it gets to a variable reference, so we add
 another parameter to \code{uniquify} for the association list. It is
 quite common for a compiler pass to need a map to store extra
-information about variables. Such maps are often called \emph{symbol
-  tables}.
+information about variables. Such maps are traditionally called
+\emph{symbol tables}.
 
 The skeleton of the \code{uniquify} function is shown in
 Figure~\ref{fig:uniquify-s0}.  The function is curried so that it is
 convenient to partially apply it to an association list and then apply
 it to different expressions, as in the last clause for primitive
 operations in Figure~\ref{fig:uniquify-s0}. In the last \key{match}
-clause for the primitive operators, note the use of the comma-@
+clause for the primitive operators, note the use of the comma-\code{@}
 operator to splice a list of S-expressions into an enclosing
 S-expression.
 
@@ -1743,20 +1741,20 @@ subdirectory named \key{tests} and they should have the same file name
 except for a different integer at the end of the name, followed by the
 ending \key{.rkt}.  Use the \key{interp-tests} function
 (Appendix~\ref{appendix:utilities}) from \key{utilities.rkt} to test
-your \key{uniquify} pass on the example programs.
+your \key{uniquify} pass on the example programs. 
 
 \end{exercise}
 
-\section{Remove Complex Operators and Operands}
+\section{Remove Complex Operands}
 \label{sec:remove-complex-opera-r1}
 
-The \code{remove-complex-opera*} pass will transform $R_1$ programs so
-that the arguments of operations are simple expressions.  Put another
-way, this pass removes complex subexpressions, such as the expression
-\code{(- 10)} in the program below. This is accomplished by
-introducing a new \key{let}-bound variable, binding the complex
-subexpression to the new variable, and then using the new variable in
-place of the complex expression, as shown in the output of
+The \code{remove-complex-opera*} pass compiles $R_1$ programs into
+$R_1$ programs in which the arguments of operations are simple
+expressions.  Put another way, this pass removes complex operands,
+such as the expression \code{(- 10)} in the program below. This is
+accomplished by introducing a new \key{let}-bound variable, binding
+the complex operand to the new variable, and then using the new
+variable in place of the complex operand, as shown in the output of
 \code{remove-complex-opera*} on the right.\\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
@@ -1781,19 +1779,21 @@ $\Rightarrow$
 We recommend implementing this pass with two mutually recursive
 functions, \code{rco-arg} and \code{rco-exp}. The idea is to apply
 \code{rco-arg} to subexpressions that need to become simple and to
-apply \code{rco-exp} to subexpressions can stay complex.  
-Both functions take an expression in $R_1$ as input.
-The \code{rco-exp} function returns an expression.
-The \code{rco-arg} function returns two things:
-a simple expression and association list mapping temporary variables
-to complex subexpressions. You can return multiple things from a
-function using Racket's \key{values} form and you can receive multiple
-things from a function call using the \key{define-values} form. If you
-are not familiar with these constructs, the Racket documentation will
-be of help.  Also, the \key{for/lists} construct is useful for
+apply \code{rco-exp} to subexpressions can stay complex.  Both
+functions take an $R_1$ expression as input.  The \code{rco-exp}
+function returns an expression.  The \code{rco-arg} function returns
+two things: a simple expression and association list mapping temporary
+variables to complex subexpressions. You can return multiple things
+from a function using Racket's \key{values} form and you can receive
+multiple things from a function call using the \key{define-values}
+form. If you are not familiar with these constructs, review the Racket
+documentation.  Also, the \key{for/lists} construct is useful for
 applying a function to each element of a list, in the case where the
 function returns multiple values.
 
+The following shows the output of \code{rco-arg} on the expression
+\code{(- 10)}.
+
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
@@ -1811,11 +1811,12 @@ $\Rightarrow$
 \end{minipage}
 \end{tabular}
 
-Take special care of programs such as the following that
-\key{let}-bind variables with integers or other variables. It should
-leave them unchanged, as shown in to the program on the right \\
+Take special care of programs such as the next one that \key{let}-bind
+variables with integers or other variables. You should leave them
+unchanged, as shown in to the program on the right \\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
+% s0_20.rkt
 \begin{lstlisting}
 (program ()
   (let ([a 42])
@@ -1835,9 +1836,8 @@ $\Rightarrow$
 \end{lstlisting}
 \end{minipage}
 \end{tabular} \\
-and not translate them to the following, which might result from a
-careless implementation of \key{rco-exp} and \key{rco-arg}.
-
+A careless implementation of \key{rco-exp} and \key{rco-arg} might
+produce the following output.\\
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
    (program ()
@@ -1863,10 +1863,11 @@ your passes on the example programs.
 \section{Explicate Control}
 \label{sec:explicate-control-r1}
 
-The \code{explicate-control} pass makes the order of execution
-explicit in the syntax of the program. For $R_1$, this amounts to
-flattening \key{let} constructs into a sequence of assignment
-statements. For example, consider the following $R_1$ program.
+The \code{explicate-control} pass compiles $R_1$ programs into $C_0$
+programs that make the order of execution explicit in their
+syntax. For now this amounts to flattening \key{let} constructs into a
+sequence of assignment statements. For example, consider the following
+$R_1$ program.
 % s0_11.rkt
 \begin{lstlisting}
 (program ()
@@ -1875,13 +1876,12 @@ statements. For example, consider the following $R_1$ program.
     y))
 \end{lstlisting}
 %
-The output of \code{remove-complex-opera*} is shown below, on the
-left.  The right-hand-side of a \key{let} executes before its body, so
-the order of evaluation for this program is to assign \code{20} to
-\code{x.1}, assign \code{22} to \code{x.2}, assign \code{(+ x.1 x.2)}
-to \code{y}, then return \code{y}. Indeed, the result of
-\code{explicate-control} produces code in the $C_0$ language that
-makes this explicit.\\
+The output of the previous pass and of \code{explicate-control} is
+shown below. Recall that the right-hand-side of a \key{let} executes
+before its body, so the order of evaluation for this program is to
+assign \code{20} to \code{x.1}, assign \code{22} to \code{x.2}, assign
+\code{(+ x.1 x.2)} to \code{y}, then return \code{y}. Indeed, the
+output of \code{explicate-control} makes this ordering explicit.\\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
@@ -1897,7 +1897,7 @@ $\Rightarrow$
 &
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
-(program ()
+(program ((locals . (y x.1 x.2)))
   ((start . 
    (seq (assign x.1 20)
    (seq (assign x.2 22)
@@ -1910,55 +1910,62 @@ $\Rightarrow$
 We recommend implementing \code{explicate-control} using two mutually
 recursive functions: \code{explicate-control-tail} and
 \code{explicate-control-assign}.  The \code{explicate-control-tail}
-function should be applied to expressions in tail position, whereas
+function should be applied to expressions in tail position whereas
 \code{explicate-control-assign} should be applied to expressions that
-occur on the right-hand-side of a \code{let}.  The function
+occur on the right-hand-side of a \key{let}.  The function
 \code{explicate-control-tail} takes an $R_1$ expression as input and
 produces a $C_0$ $\Tail$ (see the grammar in
-Figure~\ref{fig:c0-syntax}).  The \code{explicate-control-assign}
-function takes an $R_1$ expression, the variable that it is to be
-assigned to, and $C_0$ code (a $\Tail$) that should come after the
-assignment (e.g., the code generated for the body of the \key{let}).
+Figure~\ref{fig:c0-syntax}) and a list of formerly \key{let}-bound
+variables. The \code{explicate-control-assign} function takes an $R_1$
+expression, the variable that it is to be assigned to, and $C_0$ code
+(a $\Tail$) that should come after the assignment (e.g., the code
+generated for the body of the \key{let}).  It returns a $\Tail$ and a
+list of variables. The top-level \code{explicate-control} function
+should invoke \code{explicate-control-tail} on the body of the
+\key{program} and then associate the \code{locals} symbol with the
+resulting list of variables in the $\itm{info}$ field, as in the above
+example.
 
-\section{Uncover Locals}
-\label{sec:uncover-locals-r1}
+%% \section{Uncover Locals}
+%% \label{sec:uncover-locals-r1}
 
-The pass \code{uncover-locals} simply collects all of the variables in
-the program and places then in the $\itm{info}$ of the program
-construct. Here is the output for the example program of the last
-section.
+%% The pass \code{uncover-locals} simply collects all of the variables in
+%% the program and places then in the $\itm{info}$ of the program
+%% construct. Here is the output for the example program of the last
+%% section.
 
-\begin{minipage}{0.4\textwidth}
-\begin{lstlisting}
-(program ((locals . (x.1 x.2 y)))
-  ((start . 
-   (seq (assign x.1 20)
-   (seq (assign x.2 22)
-   (seq (assign y (+ x.1 x.2))
-   (return y)))))))
-\end{lstlisting}
-\end{minipage}
+%% \begin{minipage}{0.4\textwidth}
+%% \begin{lstlisting}
+%% (program ((locals . (x.1 x.2 y)))
+%%   ((start . 
+%%    (seq (assign x.1 20)
+%%    (seq (assign x.2 22)
+%%    (seq (assign y (+ x.1 x.2))
+%%    (return y)))))))
+%% \end{lstlisting}
+%% \end{minipage}
 
 \section{Select Instructions}
 \label{sec:select-r1}
 
 In the \code{select-instructions} pass we begin the work of
-translating from $C_0$ to x86. The target language of this pass is a
-pseudo-x86 language that still uses variables, so we add an AST node
-of the form $\VAR{\itm{var}}$ to the x86 abstract syntax.  We
-recommend implementing the \code{select-instructions} in terms of
-three auxiliary functions, one for each of the non-terminals of
-$C_0$: $\Arg$, $\Stmt$, and $\Tail$.
-
-The cases for $\itm{arg}$ are straightforward, simply putting
-variables and integer literals into the s-expression format expected
-of pseudo-x86, \code{(var $x$)} and \code{(int $n$)}, respectively.
-
-Next we discuss some of the cases for $\itm{stmt}$, starting with
-arithmetic operations. For example, in $C_0$ an addition operation can
-take the form below.  To translate to x86, we need to use the
-\key{addq} instruction which does an in-place update. So we must first
-move \code{10} to \code{x}. \\
+translating from $C_0$ to $\text{x86}^{*}_0$. The target language of
+this pass is a pseudo-x86 language that still uses variables, so we
+add an AST node of the form $\VAR{\itm{var}}$ to the $\text{x86}_0$
+abstract syntax of Figure~\ref{fig:x86-ast-a}.  We recommend
+implementing the \code{select-instructions} in terms of three
+auxiliary functions, one for each of the non-terminals of $C_0$:
+$\Arg$, $\Stmt$, and $\Tail$.
+
+The cases for $\itm{arg}$ are straightforward, simply put variables
+and integer literals into the s-expression format expected of
+pseudo-x86, \code{(var $x$)} and \code{(int $n$)}, respectively.
+
+Next we consider the cases for $\itm{stmt}$, starting with arithmetic
+operations. For example, in $C_0$ an addition operation can take the
+form below, to the left of the $\Rightarrow$.  To translate to x86, we
+need to use the \key{addq} instruction which does an in-place
+update. So we must first move \code{10} to \code{x}. \\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
@@ -1976,11 +1983,12 @@ $\Rightarrow$
 \end{minipage}
 \end{tabular} \\
 %
-There are some cases that require special care to avoid generating
-needlessly complicated code. If one of the arguments is the same as
-the left-hand side of the assignment, then there is no need for the
-extra move instruction.  For example, the following assignment
-statement can be translated into a single \key{addq} instruction.\\
+There are cases that require special care to avoid generating
+needlessly complicated code. If one of the arguments of the addition
+is the same as the left-hand side of the assignment, then there is no
+need for the extra move instruction.  For example, the following
+assignment statement can be translated into a single \key{addq}
+instruction.\\
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
@@ -2002,11 +2010,11 @@ assembly, so we have instead implemented this functionality in the C
 language, with the function \code{read\_int} in the file
 \code{runtime.c}. In general, we refer to all of the functionality in
 this file as the \emph{runtime system}, or simply the \emph{runtime}
-for short. When compiling your generated x86 assembly code, you
-will need to compile \code{runtime.c} to \code{runtime.o} (an ``object
-file'', using \code{gcc} option \code{-c}) and link it into the final
+for short. When compiling your generated x86 assembly code, you need
+to compile \code{runtime.c} to \code{runtime.o} (an ``object file'',
+using \code{gcc} option \code{-c}) and link it into the
 executable. For our purposes of code generation, all you need to do is
-translate an assignment of \key{read} to some variable $\itm{lhs}$
+translate an assignment of \key{read} into some variable $\itm{lhs}$
 (for left-hand side) into a call to the \code{read\_int} function
 followed by a move from \code{rax} to the left-hand side.  The move
 from \code{rax} is needed because the return value from
@@ -2032,8 +2040,8 @@ There are two cases for the $\Tail$ non-terminal: \key{return} and
 \key{seq}. Regarding \RETURN{e}, we recommend treating it as an
 assignment to the \key{rax} register followed by a jump to the
 conclusion of the program (so the conclusion needs to be labeled).
-For $(\key{seq}\,s\,t)$, we simply process the statement $s$ and tail
-$t$ recursively and append the resulting instructions.
+For $(\key{seq}\,s\,t)$, we the statement $s$ and tail $t$ recursively
+and append the resulting instructions.
 
 \begin{exercise}
 \normalfont
@@ -2048,29 +2056,58 @@ your passes on the example programs.
 \section{Assign Homes}
 \label{sec:assign-r1}
 
-As discussed in Section~\ref{sec:plan-s0-x86}, the
-\key{assign-homes} pass places all of the variables on the stack.
-Consider again the example $R_1$ program \code{(+ 52 (- 10))},
-which after \key{select-instructions} looks like the following.
+The \key{assign-homes} pass compiles $\text{x86}^{*}_0$ programs to
+$\text{x86}^{*}_0$ programs that no longer use program variables.
+Thus, the \key{assign-homes} pass is responsible for placing all of
+the program variables in registers or on the stack. For runtime
+efficiency, it is better to place variables in registers, but as there
+are only 16 registers, some programs must necessarily place some
+variables on the stack. In this chapter we focus on the mechanics of
+placing variables on the stack. We study an algorithm for placing
+variables in registers in Chapter~\ref{ch:register-allocation-r1}.
+
+Consider again the following $R_1$ program.
+% s0_20.rkt
 \begin{lstlisting}
-   (movq (int 10) (var tmp.1))
-   (negq (var tmp.1))
-   (movq (var tmp.1) (var tmp.2))
-   (addq (int 52) (var tmp.2))
-   (movq (var tmp.2) (reg rax)))
+(program ()
+  (let ([a 42])
+    (let ([b a])
+      b)))
 \end{lstlisting}
-The variable \code{tmp.1} is assigned to stack location
-\code{-8(\%rbp)}, and \code{tmp.2} is assign to \code{-16(\%rbp)}, so
-the \code{assign-homes} pass translates the above to
-\begin{lstlisting}
-   (movq (int 10) (deref rbp -8))
-   (negq (deref rbp -8))
-   (movq (deref rbp -8) (deref rbp -16))
-   (addq (int 52) (deref rbp -16))
-   (movq (deref rbp -16) (reg rax)))
+For reference, we repeat the output of \code{select-instructions} on
+the left and show the output of \code{assign-homes} on the right.
+Recall that \key{explicate-control} associated the list of
+variables with the \code{locals} symbol in the program's $\itm{info}$
+field, so \code{assign-homes} has convenient access to the them.  In
+this example, we assign variable \code{a} to stack location
+\code{-8(\%rbp)} and variable \code{b} to location \code{-16(\%rbp)}.\\
+\begin{tabular}{l}
+  \begin{minipage}{0.4\textwidth}
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+(program ((locals . (a b)))
+ ((start . 
+   (block ()
+    (movq (int 42) (var a))
+    (movq (var a) (var b))
+    (movq (var b) (reg rax))
+    (jmp conclusion)))))
 \end{lstlisting}
+\end{minipage}
+{$\Rightarrow$}
+\begin{minipage}{0.4\textwidth}
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+(program ((stack-space . 16))
+ ((start .
+   (block ()
+    (movq (int 42) (deref rbp -8))
+    (movq (deref rbp -8) (deref rbp -16))
+    (movq (deref rbp -16) (reg rax))
+    (jmp conclusion)))))
+\end{lstlisting}
+\end{minipage}
+\end{tabular} \\
 
-In the process of assigning stack locations to variables, it is
+In the process of assigning variables to stack locations, it is
 convenient to compute and store the size of the frame (in bytes) in
 the $\itm{info}$ field of the \key{program} node, with the key
 \code{stack-space}, which will be needed later to generate the
@@ -2090,33 +2127,39 @@ mapping of variable names to homes (stack locations for now).  Use the
 \section{Patch Instructions}
 \label{sec:patch-s0}
 
-The purpose of this pass is to make sure that each instruction adheres
-to the restrictions regarding which arguments can be memory
-references. For most instructions, the rule is that at most one
-argument may be a memory reference.
+The \code{patch-instructions} pass compiles $\text{x86}^{*}_0$
+programs to $\text{x86}_0$ programs by making sure that each
+instruction adheres to the restrictions of the x86 assembly language.
+In particular, at most one argument of an instruction may be a memory
+reference.
 
-Consider again the following example.
+We return to the following running example.
+% s0_20.rkt
 \begin{lstlisting}
    (let ([a 42])
      (let ([b a])
        b))
 \end{lstlisting}
-After \key{assign-homes} pass, the above has been translated to
+After the \key{assign-homes} pass, the above program has been translated to
+the following. \\
+\begin{minipage}{0.5\textwidth}
 \begin{lstlisting}
-   (movq (int 42) (deref rbp -8))
-   (movq (deref rbp -8) (deref rbp -16))
-   (movq (deref rbp -16) (reg rax))
-   (jmp conclusion)
+(program ((stack-space . 16))
+ ((start .
+   (block ()
+     (movq (int 42) (deref rbp -8))
+     (movq (deref rbp -8) (deref rbp -16))
+     (movq (deref rbp -16) (reg rax))
+     (jmp conclusion)))))
 \end{lstlisting}
+\end{minipage}\\
 The second \key{movq} instruction is problematic because both
 arguments are stack locations. We suggest fixing this problem by
-moving from the source to the register \key{rax} and then from
-\key{rax} to the destination, as follows.
+moving from the source location to the register \key{rax} and then
+from \key{rax} to the destination location, as follows.
 \begin{lstlisting}
-   (movq (int 42) (deref rbp -8))
    (movq (deref rbp -8) (reg rax))
    (movq (reg rax) (deref rbp -16))
-   (movq (deref rbp -16) (reg rax))
 \end{lstlisting}
 
 \begin{exercise}
@@ -2133,9 +2176,9 @@ your passes on the example programs.
 \section{Print x86}
 \label{sec:print-x86}
 
-The last step of the compiler from $R_1$ to x86 is to convert the x86
-AST (defined in Figure~\ref{fig:x86-ast-a}) to the string
-representation (defined in Figure~\ref{fig:x86-a}). The Racket
+The last step of the compiler from $R_1$ to x86 is to convert the
+$\text{x86}_0$ AST (defined in Figure~\ref{fig:x86-ast-a}) to the
+string representation (defined in Figure~\ref{fig:x86-a}). The Racket
 \key{format} and \key{string-append} functions are useful in this
 regard. The main work that this step needs to perform is to create the
 \key{main} function and the standard instructions for its prelude and
@@ -7565,21 +7608,22 @@ AST to AST), and a function that implements the interpreter (a
 function from AST to result value) for the language of the output of
 the pass.  The interpreters from Appendix~\ref{appendix:interp} make a
 good choice.  The \key{interp-tests} function assumes that the
-subdirectory \key{tests} has a bunch of Scheme programs whose names
+subdirectory \key{tests} has a collection of Scheme programs whose names
 all start with the family name, followed by an underscore and then the
 test number, ending in \key{.scm}. Also, for each Scheme program there
 is a file with the same number except that it ends with \key{.in} that
 provides the input for the Scheme program.
 \begin{lstlisting}
-(define (interp-tests name passes test-family test-nums) ...
+(define (interp-tests name passes test-family test-nums) ...)
 \end{lstlisting}
 
 The compiler-tests function takes a compiler name (a string) a
-description of the passes (see the comment for \key{interp-tests}) a
-test family name (a string), and a list of test numbers (see the
-comment for interp-tests), and runs the compiler to generate x86 (a
-\key{.s} file) and then runs gcc to generate machine code.  It runs
-the machine code and checks that the output is 42.
+description of the passes (as described above for
+\code{interp-tests}), a test family name (a string), and a list of
+test numbers (see the comment for interp-tests), and runs the compiler
+to generate x86 (a \key{.s} file) and then runs gcc to generate
+machine code.  It runs the machine code and checks that the output is
+42.
 \begin{lstlisting}
 (define (compiler-tests name passes test-family test-nums) ...)
 \end{lstlisting}