Jeremy Siek 3 yıl önce
ebeveyn
işleme
cb600e5634
1 değiştirilmiş dosya ile 211 ekleme ve 97 silme
  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}
 %
 We recommend implementing \code{explicate\_control} using four
-auxiliary functions:
+auxiliary functions which we discuss in the following paragraphs.
 \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
   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.
 \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}
 
-UNDER CONSTRUCTION
 
+{\if\edition\racketEd\color{olive}        
 \begin{figure}[tbp]
 \begin{lstlisting}
 (define (explicate-pred cnd thn els)
@@ -7552,87 +7645,49 @@ UNDER CONSTRUCTION
 \caption{Skeleton for the \key{explicate-pred} auxiliary function.}
 \label{fig:explicate-pred}
 \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
 %% 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
 %% \]
 
-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}.
 %
 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
 \code{explicate-assign} they are in assignment position. The
 \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
 %% 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{}.
 
-
+{\if\edition\racketEd\color{olive}
 The way in which the \code{shrink} pass transforms logical operations
 such as \code{and} and \code{or} can impact the quality of code
 generated by \code{explicate\_control}. For example, consider the
@@ -7734,21 +7789,27 @@ block39:
     return 42;
 \end{lstlisting}
 \end{center}
+\fi}
 
 \begin{exercise}\normalfont
+\racket{
 Implement the pass \code{explicate\_control} by adding the cases for
 Boolean constants and \key{if} to the \code{explicate-tail} and
 \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
 this pass.
 %
+{\if\edition\racketEd\color{olive}
 Add the following entry to the list of \code{passes} in
 \code{run-tests.rkt} and then run this script to test your compiler.
 \begin{lstlisting}
 (list "explicate-control" explicate-control interp-Cif type-check-Cif)
 \end{lstlisting}
+\fi}
 
 \end{exercise}
 
@@ -7757,17 +7818,21 @@ Add the following entry to the list of \code{passes} in
 \label{sec:select-Rif}
 \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
 approach of encoding them as integers, with true as 1 and false as 0.
 \[
-\key{\#t} \Rightarrow \key{1}
+\TRUE{} \Rightarrow \key{1}
 \qquad
-\key{\#f} \Rightarrow \key{0}
+\FALSE{} \Rightarrow \key{0}
 \]
 
 For $\Stmt$, we discuss a couple cases.  The \code{not} operation can
@@ -8116,9 +8181,58 @@ conclusion:
 \end{figure}
 
 
-\section{Challenge: Remove Jumps}
+\section{Challenge: Optimize and Remove 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
 %% Figure~\ref{fig:explicate-control-s1-38}, \code{block57} through
 %% \code{block60} are trivial blocks, they do nothing but jump to another