Browse Source

improving explicate

Jeremy Siek 3 năm trước cách đây
mục cha
commit
9e2255ec19
1 tập tin đã thay đổi với 156 bổ sung39 xóa
  1. 156 39
      book.tex

+ 156 - 39
book.tex

@@ -7737,6 +7737,62 @@ def explicate_control(p):
 \fi}
 
 
+{\if\edition\racketEd
+%
+The \code{explicate\_tail} and \code{explicate\_assign} functions need
+additional cases for Boolean constants and \key{if}.  The cases for
+\code{if} should recursively compile the two branches using either
+\code{explicate\_tail} or \code{explicate\_assign}, respectively. The
+cases should then invoke \code{explicate\_pred} on the condition
+expression, passing in the generated code for the two branches.  For
+example, consider the following program with an \code{if} in tail
+position.
+\begin{lstlisting}
+(let ([x (read)])
+  (if (eq? x 0) 42 777))
+\end{lstlisting}
+The two branches are recursively compiled to \code{(Return 42)} and
+\code{(Return 777)}. We then invoke \code{explicate\_pred} on the
+condition \code{(eq? x 0)} and the two return statements, which is
+used as the result for \code{explicate\_tail}.
+\begin{lstlisting}
+  (if (eq? x 0) 42 777)
+  |$\Rightarrow$| (explicate_pred `(Prim eq? ((Var x) (Int 0)))
+                       `(Return 42) `(Return 777))
+\end{lstlisting}
+Next let us consider a program with an \code{if} on the right-hand
+side of a \code{let}.
+\begin{lstlisting}
+(let ([y (read)])
+  (let ([x (if (eq? y 0) 40 777)])
+    (+ x 2)))
+\end{lstlisting}
+Note that the body of the inner \code{let} will have already been
+compiled to \code{(Return (+ x 2))} and passed as the \code{cont}
+parameter of \code{explicate\_assign}. We'll need to use \code{cont}
+to recursively process both branches of the \code{if}, so we generate
+the following block using an auxiliary function named \code{create\_block}.
+\begin{lstlisting}
+block_6:
+  return (+ x 2)
+\end{lstlisting}
+and use \code{(Goto 'block\_6)} as the \code{cont} argument for
+compiling the branches. So the two branches compile to
+\begin{lstlisting}
+x = 40;
+goto block_6;
+\end{lstlisting}
+and
+\begin{lstlisting}
+x = 777;
+goto block_6;
+\end{lstlisting}
+We then invoke \code{explicate\_pred} on the condition \code{(eq? y
+  0)} and the above code for the branches, which is used as the result
+for \code{explicate\_tail}.
+
+\fi}
+
 {\if\edition\racketEd        
 \begin{figure}[tbp]
 \begin{lstlisting}
@@ -7746,8 +7802,8 @@ def explicate_control(p):
     [(Let x rhs body) ___]
     [(Prim 'not (list e)) ___]
     [(Prim op es) #:when (or (eq? op 'eq?) (eq? op '<))
-     (IfStmt (Prim op arg*) (force (block->goto thn))
-              (force (block->goto els)))]
+     (IfStmt (Prim op arg*) (create_block thn)
+              (create_block els))]
     [(Bool b) (if b thn els)]
     [(If cnd^ thn^ els^) ___]
     [else (error "explicate_pred unhandled case" cnd)]))
@@ -7758,11 +7814,13 @@ def explicate_control(p):
 \fi}
 
 \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}.}
+  in Figure~\ref{fig:explicate-pred}.  It takes three parameters:
+  1) \code{cnd}, the condition expression of the \code{if},
+  2) \code{thn}, the code generated by explicate for the ``then'' branch,
+  and 3) \code{els}, the code generated by
+  explicate for the ``else'' branch.  The \code{explicate\_pred}
+  function should match on \code{cnd} with a case for
+  every kind of expression that can have type \code{Boolean}.}
 %
 \python{The \code{explicate\_pred} function has four parameters: 1)
   the condition expession, 2) the generated statements for the
@@ -7770,18 +7828,72 @@ def explicate_control(p):
   branch, and 4) the dictionary of basic blocks. The
   \code{explicate\_pred} function returns a list of \LangCIf{}
   statements and it may add to 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.
+statements created by applying \code{create\_block} to the code
+generated for the \code{thn} and \code{els} branches. Let us
+illustrate this translation with an example.  Returning
+to the program with an \code{if} expression in tail position,
+we invoke \code{explicate\_pred} on its condition \code{(eq? x 0)}
+which happens to be a comparison operator.
+\begin{lstlisting}
+(let ([x (read)])
+  (if (eq? x 0) 42 777))
+\end{lstlisting}
+The two branches \code{42} and \code{777} were already compiled to \code{return}
+statements, from which we now create the following blocks.
+\begin{center}
+\begin{minipage}{\textwidth}
+\begin{lstlisting}
+block_1:
+    return 42;
+block_2:
+    return 777;
+\end{lstlisting}
+  \end{minipage}
+\end{center}
 %
+So \code{explicate\_pred} compiles the comparison \code{(eq? x 0)}
+to the following \code{if} statement.
+%
+\begin{center}
+\begin{minipage}{\textwidth}
+\begin{lstlisting}
+if (eq? x 0)
+   goto block_1;
+else
+   goto block_2;
+\end{lstlisting}
+\end{minipage}
+\end{center}
+
 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}.
+constant is \TRUE{} or \FALSE{}. Let us illustrate this with the
+following program.
+\begin{center}
+\begin{minipage}{\textwidth}
+\begin{lstlisting}
+(if #t 42 777)
+\end{lstlisting}
+\end{minipage}
+\end{center}
+%
+Again, the two branches \code{42} and \code{777} were compiled to
+\code{return} statements, so \code{explicate\_pred} compiles the
+constant \code{\#t} to the code for the ``then'' branch.
+\begin{center}
+\begin{minipage}{\textwidth}
+\begin{lstlisting}
+return 42;
+\end{lstlisting}
+\end{minipage}
+\end{center}
+%
+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
@@ -7826,8 +7938,8 @@ the dictionary of basic blocks, labeling it as the ``start'' block.
 
 %% 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
-%% ``else'' branches with the arguments \code{(block->goto} $B_1$\code{)}
-%% and \code{(block->goto} $B_2$\code{)}. Let $B_3$ and $B_4$ be the
+%% ``else'' branches with the arguments \code{(create_block} $B_1$\code{)}
+%% and \code{(create_block} $B_2$\code{)}. Let $B_3$ and $B_4$ be the
 %% results from the two recursive calls.  We complete the case for
 %% \code{if} by recursively apply \code{explicate\_pred} to the condition
 %% of the \code{if} with the promised blocks $B_3$ and $B_4$ to obtain
@@ -7838,14 +7950,6 @@ the dictionary of basic blocks, labeling it as the ``start'' block.
 %% B_5
 %% \]
 
-\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.}
-
 %% 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
 %% recursive calls on the ``then'' and ``else'' branch should be calls to
@@ -7853,7 +7957,7 @@ the dictionary of basic blocks, labeling it as the ``start'' block.
 %% %
 %% We need to pass $B_0$ as the accumulator argument for both of these
 %% recursive calls, but we need to be careful not to duplicate $B_0$.
-%% Thus, we first apply \code{block->goto} to $B_0$ so that it gets added
+%% Thus, we first apply \code{create_block} to $B_0$ so that it gets added
 %% to the control-flow graph and obtain a promised goto $G_0$.
 %% %
 %% Let $B_1$ be the result of \code{explicate\_tail} on the ``then''
@@ -7877,7 +7981,7 @@ the dictionary of basic blocks, labeling it as the ``start'' block.
 %% variable $x$ and then the control continues to some promised block
 %% $B_1$.  The code that we generate for both the ``then'' and ``else''
 %% branches needs to continue to $B_1$, so to avoid duplicating $B_1$ we
-%% apply \code{block->goto} to it and obtain a promised goto $G_1$.  The
+%% apply \code{create_block} to it and obtain a promised goto $G_1$.  The
 %% branches of the \key{if} inherit the current context, so they are in
 %% assignment positions.  Let $B_2$ be the result of applying
 %% \code{explicate\_assign} to the ``then'' branch, variable $x$, and
@@ -7917,7 +8021,7 @@ Here was see that our algorithm sometimes inserts unnecessary blocks:
 and \code{block\_5} is just a \code{goto} to \code{block\_3}.
 It would be better to skip blocks \code{block\_4} and \code{block\_5}
 and go directly to \code{block\_2} and \code{block\_3},
-which we investigate doing in Section~\ref{sec:opt-jumps}.
+which we investigate in Section~\ref{sec:opt-jumps}.
 Getting back to the example, \code{block\_2} and \code{block\_3},
 corresponds to the two branches of the outer \key{if}, i.e.,
 \racket{\code{(+ y 2)}}\python{\code{y + 2}} and
@@ -7947,22 +8051,35 @@ The story for \code{block\_9} is similar to that of \code{block\_8}.
 $\Rightarrow$
 &
 \begin{minipage}{0.55\textwidth}
-  TODO: replace with non-optimized version. -Jeremy
 \begin{lstlisting}
 start:
     x = (read);
     y = (read);
-    if (< x 1) goto block40;
-    else goto block41;
-block40:
-    if (eq? x 0) goto block38;
-    else goto block39;
-block41:
-    if (eq? x 2) goto block38;
-    else goto block39;
-block38:
+    if (< x 1)
+       goto block_8;
+    else
+       goto block_9;
+block_8:
+    if (eq? x 0)
+       goto block_4;
+    else
+       goto block_5;
+block_9:
+    if (eq? x 2)
+       goto block_6;
+    else
+       goto block_7;
+block_4:
+    goto block_2;
+block_5:
+    goto block_3;
+block_6:
+    goto block_2;
+block_7:
+    goto block_3;
+block_2:
     return (+ y 2);
-block39:
+block_3:
     return (+ y 10);
 \end{lstlisting}
 \end{minipage}
@@ -8728,7 +8845,7 @@ block.
 %
 {\if\edition\racketEd
 %
-The following auxiliary function named \code{block->goto} accomplishes
+The following auxiliary function named \code{create\_block} 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
@@ -8737,7 +8854,7 @@ 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)
+(define (create_block block)
   (delay
     (define b (force block))
     (match b