Jeremy Siek 3 سال پیش
والد
کامیت
cb600e5634
1فایلهای تغییر یافته به همراه211 افزوده شده و 97 حذف شده
  1. 211 97
      book.tex

+ 211 - 97
book.tex

@@ -7520,21 +7520,114 @@ following paragraphs we discuss specific cases in the
 {\if\edition\pythonEd\color{purple}
 {\if\edition\pythonEd\color{purple}
 %
 %
 We recommend implementing \code{explicate\_control} using four
 We recommend implementing \code{explicate\_control} using four
-auxiliary functions:
+auxiliary functions which we discuss in the following paragraphs.
 \begin{description}
 \begin{description}
-\item[\code{explicate\_pred}] generates code for expressions
-  that appear in the condition of an \code{if}.
-\item[\code{explicate\_assign}] generates code for exprssions
-  that appear on the right-hand side of an assignment.
 \item[\code{explicate\_exp}] generates code for expressions in all
 \item[\code{explicate\_exp}] generates code for expressions in all
   other contexts.
   other contexts.
+\item[\code{explicate\_assign}] generates code for exprssions
+  that appear on the right-hand side of an assignment.
+\item[\code{explicate\_pred}] generates code for expressions
+  that appear in the condition of an \code{if}.
 \item[\code{explicate\_stmt}] generates code for statements.
 \item[\code{explicate\_stmt}] generates code for statements.
 \end{description}
 \end{description}
-  
+These four functions should incrementally build up the dictionary of
+basic blocks. The following auxiliary function can be used to create a
+new basic block from a list of statements. It returns a \code{goto}
+statement that jumps to the new basic block.
+\begin{lstlisting}
+def create_block(stmts, basic_blocks):
+    label = label_name(generate_name('block'))
+    basic_blocks[label] = stmts
+    return Goto(label)
+\end{lstlisting}
+Figure~\ref{fig:explicate-control-Rif} provides a skeleton for the
+\code{explicate\_control} pass.
+
+The \code{explicate\_exp} function has three parameters: 1) the
+expression to be compiled, 2) the already-compiled code for this
+expression's \emph{continuation}, that is, the code that should
+execute after this expression, and 3) the dictionary of generated
+basic blocks. The output of \code{explicate\_exp} is a list of
+\LangCIf{} statements.
+%
+The only kind of expression in \LangIf{} that is not in \LangCIf{} is
+the \code{if} expression, so that must be translated into something
+else.  The two branches should be translated using
+\code{explicate\_exp} and the condition expression should be
+translated using \code{explicate\_pred}.  All other expressions can be
+translated into a statment using \code{Expr}.
+
+The \code{explicate\_assign} function has four parameters: 1) the
+right-hand-side of the assignment, 2) the left-hand-side of the
+assignment (the variable), 3) the continuation, and 4) the dictionary
+of basic blocks. When the right-hand-side is an \code{if} expression,
+there is some work to there. The two branches should be translated
+using \code{explicate\_assign} and the condition expression should be
+translated using \code{explicate\_pred}.  Otherwise we can simply
+generate an assignment statement with the given left and right-hand
+sides.
+
+\begin{figure}[tbp]
+\begin{lstlisting}
+def explicate_exp(e, cont, basic_blocks):
+    match e:
+        case IfExp(test, body, orelse):
+            ...
+        case _:
+            return [Expr(e)] + cont
+
+def explicate_assign(rhs, lhs, cont, basic_blocks):
+    match rhs:
+        case IfExp(test, body, orelse):
+            ...
+        case _:
+            return [Assign([lhs], rhs)] + cont
+
+def explicate_pred(cnd, thn, els, basic_blocks):
+    match cnd:
+        case Compare(left, [op], [right]):
+            goto_thn = create_block(thn, basic_blocks)
+            goto_els = create_block(els, basic_blocks)
+            return [If(cnd, [goto_thn], [goto_els])]
+        case Constant(True):
+            return thn;
+        case Constant(False):
+            return els;
+        case UnaryOp(Not(), operand):
+            ...
+        case IfExp(test, body, orelse):
+            ...
+        case _:
+            return [If(Compare(cnd, [Eq()], [Constant(False)]),
+                       [create_block(els, basic_blocks)],
+                       [create_block(thn, basic_blocks)])]
+
+def explicate_stmt(s, cont, basic_blocks):
+    match s:
+        case Assign([lhs], rhs):
+            return explicate_assign(rhs, lhs, cont, basic_blocks)
+        case Expr(value):
+            return explicate_exp(value, cont, basic_blocks)
+        case If(test, body, orelse):
+            ...
+
+def explicate_control(p):
+    match p:
+        case Module(body):
+            new_body = [Return(Constant(0))]
+            basic_blocks = {}
+            for s in reversed(body):
+                new_body = explicate_stmt(s, new_body, basic_blocks)
+            basic_blocks[label_name('start')] = new_body
+            return CProgram(basic_blocks)
+\end{lstlisting}
+\caption{Skeleton for the \code{explicate\_control} pass.}
+\label{fig:explicate-control-Rif}
+\end{figure}
 \fi}
 \fi}
 
 
-UNDER CONSTRUCTION
 
 
+{\if\edition\racketEd\color{olive}        
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{lstlisting}
 \begin{lstlisting}
 (define (explicate-pred cnd thn els)
 (define (explicate-pred cnd thn els)
@@ -7552,87 +7645,49 @@ UNDER CONSTRUCTION
 \caption{Skeleton for the \key{explicate-pred} auxiliary function.}
 \caption{Skeleton for the \key{explicate-pred} auxiliary function.}
 \label{fig:explicate-pred}
 \label{fig:explicate-pred}
 \end{figure}
 \end{figure}
+\fi}
 
 
-The skeleton for the \code{explicate-pred} function is given in
-Figure~\ref{fig:explicate-pred}. It has a case for every expression
-that can have type \code{Boolean}.  We detail a few cases here and
-leave the rest for the reader. The input to this function is an
-expression and two blocks, \code{thn} and \code{els}, for the two
-branches of the enclosing \key{if}.
-%
-Consider the case for Boolean constants in
-Figure~\ref{fig:explicate-pred}.  We perform a kind of partial
-evaluation\index{subject}{partial evaluation} and output either the \code{thn}
-or \code{els} branch depending on whether the constant is true or
-false. This case demonstrates that we sometimes discard the \code{thn}
-or \code{els} blocks that are input to \code{explicate-pred}.
-
-The case for \key{if} in \code{explicate-pred} is particularly
-illuminating because it deals with the challenges we discussed above
-regarding nested \key{if} expressions
-(Figure~\ref{fig:explicate-control-s1-38}).  The \lstinline{thn^} and
-\lstinline{els^} branches of the \key{if} inherit their context from
-the current one, that is, predicate context. So you should recursively
-apply \code{explicate-pred} to the \lstinline{thn^} and
-\lstinline{els^} branches. For both of those recursive calls, pass
-\code{thn} and \code{els} as the extra parameters. Thus, \code{thn}
-and \code{els} may get used twice, once inside each recursive call. As
-discussed above, to avoid duplicating code, we need to add them to the
-control-flow graph so that we can instead refer to them by name and
-execute them with a \key{goto}. However, as we saw in the cases above
-for Boolean constants, the blocks \code{thn} and \code{els} may not
-get used at all and we don't want to prematurely add them to the
-control-flow graph if they end up being discarded.
-
-The solution to this conundrum is to use \emph{lazy
-  evaluation}\index{subject}{lazy evaluation}\citep{Friedman:1976aa} to delay
-adding the blocks to the control-flow graph until the points where we
-know they will be used. Racket provides support for lazy evaluation
-with the
-\href{https://docs.racket-lang.org/reference/Delayed_Evaluation.html}{\code{racket/promise}}
-package. The expression \key{(delay} $e_1 \ldots e_n$\key{)}
-\index{subject}{delay} creates a \emph{promise}\index{subject}{promise} in which the
-evaluation of the expressions is postponed. When \key{(force}
-$p$\key{)}\index{subject}{force} is applied to a promise $p$ for the first
-time, the expressions $e_1 \ldots e_n$ are evaluated and the result of
-$e_n$ is cached in the promise and returned. If \code{force} is
-applied again to the same promise, then the cached result is returned.
-If \code{force} is applied to an argument that is not a promise,
-\code{force} simply returns the argument.
-
-We use lazy evaluation for the input and output blocks of the
-functions \code{explicate-pred} and \code{explicate-assign} and for
-the output block of \code{explicate-tail}. So instead of taking and
-returning blocks, they take and return promises. Furthermore, when we
-come to a situation in which we a block might be used more than once,
-as in the case for \code{if} in \code{explicate-pred}, we transform
-the promise into a new promise that will add the block to the
-control-flow graph and return a \code{goto}.  The following auxiliary
-function named \code{block->goto} accomplishes this task. It begins
-with \code{delay} to create a promise. When forced, this promise will
-force the original promise. If that returns a \code{goto} (because the
-block was already added to the control-flow graph), then we return the
-\code{goto}. Otherwise we add the block to the control-flow graph with
-another auxiliary function named \code{add-node}. That function
-returns the label for the new block, which we use to create a
-\code{goto}.
-\begin{lstlisting}
-(define (block->goto block)
-  (delay
-    (define b (force block))
-    (match b
-      [(Goto label) (Goto label)]
-      [else (Goto (add-node b))])))
-\end{lstlisting}
+\racket{The skeleton for the \code{explicate\_pred} function is given
+  in Figure~\ref{fig:explicate-pred}. It has a case for every
+  expression that can have type \code{Boolean}.  We detail a few cases
+  here and leave the rest for the reader. The input to this function
+  is an expression and two blocks, \code{thn} and \code{els}, for the
+  two branches of the enclosing \key{if}.}
+%
+\python{The \code{explicate\_pred} function has four parameters: 1)
+  the condition expession, 2) the generated code for the ``then''
+  branch, 3) the generated code for the ``else'' branch, and 4) the
+  dictionary of basic blocks.}
+%
+Consider the case for comparison operators. We translate the
+comparison to an \code{if} statement whose branches are \code{goto}
+statements created by applying \code{create\_block} to the \code{thn}
+and \code{els} branches.
+%
+Next consider the case for Boolean constants. We perform a kind of
+partial evaluation\index{subject}{partial evaluation} and output
+either the \code{thn} or \code{els} branch depending on whether the
+constant is \TRUE{} or \FALSE{}. This case demonstrates that we
+sometimes discard the \code{thn} or \code{els} blocks that are input
+to \code{explicate\_pred}.
+%
+The case for \key{if} expressions in \code{explicate\_pred} is
+particularly illuminating because it deals with the challenges we
+discussed above regarding nested \key{if} expressions
+(Figure~\ref{fig:explicate-control-s1-38}).  The
+\racket{\lstinline{thn^}}\python{\code{body}} and
+\racket{\lstinline{els^}}\python{\code{orlese}} branches of the
+\key{if} inherit their context from the current one, that is,
+predicate context. So you should recursively apply
+\code{explicate\_pred} to the
+\racket{\lstinline{thn^}}\python{\code{body}} and
+\racket{\lstinline{els^}}\python{\code{orelse}} branches. For both of
+those recursive calls, pass \code{thn} and \code{els} as the extra
+parameters. Thus, \code{thn} and \code{els} may get used twice, once
+inside each recursive call. As discussed above, to avoid duplicating
+code, we need to add them to the dictionary of basic blocks so that we
+can instead refer to them by name and execute them with a \key{goto}.
 
 
-Returning to the discussion of \code{explicate-pred}
-(Figure~\ref{fig:explicate-pred}), consider the case for comparison
-operators. This is one of the base cases of the recursive function so
-we translate the comparison to an \code{if} statement. We apply
-\code{block->goto} to \code{thn} and \code{els} to obtain two promises
-that will add then to the control-flow graph, which we can immediately
-\code{force} to obtain the two goto's that form the branches of the
-\code{if} statement.
 
 
 %% Getting back to the case for \code{if} in \code{explicate-pred}, we
 %% Getting back to the case for \code{if} in \code{explicate-pred}, we
 %% make the recursive calls to \code{explicate-pred} on the ``then'' and
 %% make the recursive calls to \code{explicate-pred} on the ``then'' and
@@ -7648,14 +7703,14 @@ that will add then to the control-flow graph, which we can immediately
 %% B_5
 %% B_5
 %% \]
 %% \]
 
 
-The \code{explicate-tail} and \code{explicate-assign} functions need
+\racket{The \code{explicate-tail} and \code{explicate-assign} functions need
 additional cases for Boolean constants and \key{if}.
 additional cases for Boolean constants and \key{if}.
 %
 %
 In the cases for \code{if}, the two branches inherit the current
 In the cases for \code{if}, the two branches inherit the current
 context, so in \code{explicate-tail} they are in tail position and in
 context, so in \code{explicate-tail} they are in tail position and in
 \code{explicate-assign} they are in assignment position. The
 \code{explicate-assign} they are in assignment position. The
 \code{cont} parameter of \code{explicate-assign} is used in both
 \code{cont} parameter of \code{explicate-assign} is used in both
-recursive calls, so make sure to use \code{block->goto} on it.
+recursive calls, so make sure to use \code{block->goto} on it.}
 
 
 %% In the case for \code{if} in \code{explicate-tail}, the two branches
 %% In the case for \code{if} in \code{explicate-tail}, the two branches
 %% inherit the current context, so they are in tail position. Thus, the
 %% inherit the current context, so they are in tail position. Thus, the
@@ -7702,7 +7757,7 @@ recursive calls, so make sure to use \code{block->goto} on it.
 %% \]
 %% \]
 %% This completes the description of \code{explicate\_control} for \LangIf{}.
 %% This completes the description of \code{explicate\_control} for \LangIf{}.
 
 
-
+{\if\edition\racketEd\color{olive}
 The way in which the \code{shrink} pass transforms logical operations
 The way in which the \code{shrink} pass transforms logical operations
 such as \code{and} and \code{or} can impact the quality of code
 such as \code{and} and \code{or} can impact the quality of code
 generated by \code{explicate\_control}. For example, consider the
 generated by \code{explicate\_control}. For example, consider the
@@ -7734,21 +7789,27 @@ block39:
     return 42;
     return 42;
 \end{lstlisting}
 \end{lstlisting}
 \end{center}
 \end{center}
+\fi}
 
 
 \begin{exercise}\normalfont
 \begin{exercise}\normalfont
+\racket{
 Implement the pass \code{explicate\_control} by adding the cases for
 Implement the pass \code{explicate\_control} by adding the cases for
 Boolean constants and \key{if} to the \code{explicate-tail} and
 Boolean constants and \key{if} to the \code{explicate-tail} and
 \code{explicate-assign}. Implement the auxiliary function
 \code{explicate-assign}. Implement the auxiliary function
-\code{explicate-pred} for predicate contexts.
+\code{explicate-pred} for predicate contexts.}
+\python{Implement \code{explicate\_control} pass with its
+four auxiliary functions.}
 %
 %
 Create test cases that exercise all of the new cases in the code for
 Create test cases that exercise all of the new cases in the code for
 this pass.
 this pass.
 %
 %
+{\if\edition\racketEd\color{olive}
 Add the following entry to the list of \code{passes} in
 Add the following entry to the list of \code{passes} in
 \code{run-tests.rkt} and then run this script to test your compiler.
 \code{run-tests.rkt} and then run this script to test your compiler.
 \begin{lstlisting}
 \begin{lstlisting}
 (list "explicate-control" explicate-control interp-Cif type-check-Cif)
 (list "explicate-control" explicate-control interp-Cif type-check-Cif)
 \end{lstlisting}
 \end{lstlisting}
+\fi}
 
 
 \end{exercise}
 \end{exercise}
 
 
@@ -7757,17 +7818,21 @@ Add the following entry to the list of \code{passes} in
 \label{sec:select-Rif}
 \label{sec:select-Rif}
 \index{subject}{instruction selection}
 \index{subject}{instruction selection}
 
 
-The \code{select-instructions} pass translate \LangCIf{} to
-\LangXIfVar{}. Recall that we implement this pass using three
-auxiliary functions, one for each of the non-terminals $\Atm$,
-$\Stmt$, and $\Tail$.
+The \code{select\_instructions} pass translates \LangCIf{} to
+\LangXIfVar{}.
+%
+\racket{Recall that we implement this pass using three auxiliary
+  functions, one for each of the non-terminals $\Atm$, $\Stmt$, and
+  $\Tail$.}
+
+UNDER CONSTRUCTION
 
 
 For $\Atm$, we have new cases for the Booleans.  We take the usual
 For $\Atm$, we have new cases for the Booleans.  We take the usual
 approach of encoding them as integers, with true as 1 and false as 0.
 approach of encoding them as integers, with true as 1 and false as 0.
 \[
 \[
-\key{\#t} \Rightarrow \key{1}
+\TRUE{} \Rightarrow \key{1}
 \qquad
 \qquad
-\key{\#f} \Rightarrow \key{0}
+\FALSE{} \Rightarrow \key{0}
 \]
 \]
 
 
 For $\Stmt$, we discuss a couple cases.  The \code{not} operation can
 For $\Stmt$, we discuss a couple cases.  The \code{not} operation can
@@ -8116,9 +8181,58 @@ conclusion:
 \end{figure}
 \end{figure}
 
 
 
 
-\section{Challenge: Remove Jumps}
+\section{Challenge: Optimize and Remove Jumps}
 \label{sec:opt-jumps}
 \label{sec:opt-jumps}
 
 
+UNDER CONSTRUCTION
+
+However, as we saw in the cases above for Boolean constants, the
+blocks \code{thn} and \code{els} may not get used at all and we don't
+want to prematurely add them to the control-flow graph if they end up
+being discarded.
+
+The solution to this conundrum is to use \emph{lazy
+  evaluation}\index{subject}{lazy evaluation}\citep{Friedman:1976aa} to delay
+adding the blocks to the control-flow graph until the points where we
+know they will be used. Racket provides support for lazy evaluation
+with the
+\href{https://docs.racket-lang.org/reference/Delayed_Evaluation.html}{\code{racket/promise}}
+package. The expression \key{(delay} $e_1 \ldots e_n$\key{)}
+\index{subject}{delay} creates a \emph{promise}\index{subject}{promise} in which the
+evaluation of the expressions is postponed. When \key{(force}
+$p$\key{)}\index{subject}{force} is applied to a promise $p$ for the first
+time, the expressions $e_1 \ldots e_n$ are evaluated and the result of
+$e_n$ is cached in the promise and returned. If \code{force} is
+applied again to the same promise, then the cached result is returned.
+If \code{force} is applied to an argument that is not a promise,
+\code{force} simply returns the argument.
+
+We use lazy evaluation for the input and output blocks of the
+functions \code{explicate-pred} and \code{explicate-assign} and for
+the output block of \code{explicate-tail}. So instead of taking and
+returning blocks, they take and return promises. Furthermore, when we
+come to a situation in which we a block might be used more than once,
+as in the case for \code{if} in \code{explicate-pred}, we transform
+the promise into a new promise that will add the block to the
+control-flow graph and return a \code{goto}.  The following auxiliary
+function named \code{block->goto} accomplishes this task. It begins
+with \code{delay} to create a promise. When forced, this promise will
+force the original promise. If that returns a \code{goto} (because the
+block was already added to the control-flow graph), then we return the
+\code{goto}. Otherwise we add the block to the control-flow graph with
+another auxiliary function named \code{add-node}. That function
+returns the label for the new block, which we use to create a
+\code{goto}.
+\begin{lstlisting}
+(define (block->goto block)
+  (delay
+    (define b (force block))
+    (match b
+      [(Goto label) (Goto label)]
+      [else (Goto (add-node b))])))
+\end{lstlisting}
+
+
 %% Recall that in the example output of \code{explicate\_control} in
 %% Recall that in the example output of \code{explicate\_control} in
 %% Figure~\ref{fig:explicate-control-s1-38}, \code{block57} through
 %% Figure~\ref{fig:explicate-control-s1-38}, \code{block57} through
 %% \code{block60} are trivial blocks, they do nothing but jump to another
 %% \code{block60} are trivial blocks, they do nothing but jump to another