|
@@ -1331,7 +1331,7 @@ extensible way.
|
|
|
Having justified the use of classes and methods to implement
|
|
|
interpreters, we turn to the definitional interpreter for \LangVar{}
|
|
|
in Figure~\ref{fig:interp-Rvar}. It is similar to the interpreter for
|
|
|
-\LangInt{} but adds two new \key{match} clauses for variables and
|
|
|
+\LangInt{} but adds two new \key{match} cases for variables and
|
|
|
\key{let}. For \key{let} we need a way to communicate the value bound
|
|
|
to a variable to all the uses of the variable. To accomplish this, we
|
|
|
maintain a mapping from variables to values. Throughout the compiler
|
|
@@ -1973,8 +1973,8 @@ for the alist.
|
|
|
The skeleton of the \code{uniquify-exp} function is shown in
|
|
|
Figure~\ref{fig:uniquify-Rvar}. The function is curried so that it is
|
|
|
convenient to partially apply it to an alist and then apply it to
|
|
|
-different expressions, as in the last clause for primitive operations
|
|
|
-in Figure~\ref{fig:uniquify-Rvar}. The
|
|
|
+different expressions, as in the last case for primitive operations in
|
|
|
+Figure~\ref{fig:uniquify-Rvar}. The
|
|
|
%
|
|
|
\href{https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29}{\key{for/list}}
|
|
|
%
|
|
@@ -1985,7 +1985,7 @@ produce a new list.\index{for/list}
|
|
|
\normalfont % I don't like the italics for exercises. -Jeremy
|
|
|
|
|
|
Complete the \code{uniquify} pass by filling in the blanks in
|
|
|
-Figure~\ref{fig:uniquify-Rvar}, that is, implement the clauses for
|
|
|
+Figure~\ref{fig:uniquify-Rvar}, that is, implement the cases for
|
|
|
variables and for the \key{let} form in the file \code{compiler.rkt}
|
|
|
in the support code.
|
|
|
\end{exercise}
|
|
@@ -2012,17 +2012,29 @@ in the support code.
|
|
|
\begin{exercise}
|
|
|
\normalfont % I don't like the italics for exercises. -Jeremy
|
|
|
|
|
|
-Creating five \LangVar{} programs to test the most interesting parts
|
|
|
-of the \key{uniquify} pass, that is, the programs should include
|
|
|
+Create five \LangVar{} programs that exercise the most interesting
|
|
|
+parts of the \key{uniquify} pass, that is, the programs should include
|
|
|
\key{let} forms, variables, and variables that overshadow each other.
|
|
|
The five programs should be placed in the subdirectory named
|
|
|
\key{tests} and the file names should start with \code{var\_test\_}
|
|
|
followed by a unique integer and end with the file extension
|
|
|
-\key{.rkt}. Run the \key{run-tests.rkt} script in the support code to
|
|
|
-check whether the output programs produce the same result as the input
|
|
|
-programs. The script uses the \key{interp-tests} function
|
|
|
+\key{.rkt}.
|
|
|
+%
|
|
|
+The \key{run-tests.rkt} script in the support code checks whether the
|
|
|
+output programs produce the same result as the input programs. The
|
|
|
+script uses 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. The \code{passes}
|
|
|
+parameter of \key{interp-tests} is a list that should have one entry
|
|
|
+for each pass in your compiler. For now, define \code{passes} to
|
|
|
+contain just one entry for \code{uniquify} as follows.
|
|
|
+\begin{lstlisting}
|
|
|
+(define passes
|
|
|
+ (list (list "uniquify" uniquify interp-Rvar type-check-Rvar)))
|
|
|
+\end{lstlisting}
|
|
|
+Run the \key{run-tests.rkt} script in the support code to check
|
|
|
+whether the output programs produce the same result as the input
|
|
|
+programs.
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2040,7 +2052,7 @@ operand, as shown in the output of \code{remove-complex-opera*} on the
|
|
|
right.\\
|
|
|
\begin{tabular}{lll}
|
|
|
\begin{minipage}{0.4\textwidth}
|
|
|
-% s0_19.rkt
|
|
|
+% var_test_19.rkt
|
|
|
\begin{lstlisting}
|
|
|
(+ 52 (- 10))
|
|
|
\end{lstlisting}
|
|
@@ -2126,7 +2138,7 @@ variable to an atomic expression. You should leave such variable
|
|
|
bindings unchanged, as shown in to the program on the right \\
|
|
|
\begin{tabular}{lll}
|
|
|
\begin{minipage}{0.4\textwidth}
|
|
|
-% s0_20.rkt
|
|
|
+% var_test_20.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([a 42])
|
|
|
(let ([b a])
|
|
@@ -2156,14 +2168,20 @@ produce the following output with unnecessary temporary variables.\\
|
|
|
\end{lstlisting}
|
|
|
\end{minipage}
|
|
|
|
|
|
-\begin{exercise}
|
|
|
- \normalfont Implement the \code{remove-complex-opera*} in
|
|
|
- \code{compiler.rkt}. Create three new \LangInt{} programs that are
|
|
|
- designed to exercise the interesting code in the
|
|
|
- \code{remove-complex-opera*} pass (Following the same file name
|
|
|
- guidelines as before.). In the \code{run-tests.rkt} script,
|
|
|
- uncomment the line for this pass in the list of \code{passes} and
|
|
|
- then run the script to test your compiler.
|
|
|
+\begin{exercise}\normalfont
|
|
|
+%
|
|
|
+Implement the \code{remove-complex-opera*} function in
|
|
|
+\code{compiler.rkt}.
|
|
|
+%
|
|
|
+Create three new \LangInt{} programs that exercise the interesting
|
|
|
+code in the \code{remove-complex-opera*} pass (Following the same file
|
|
|
+name guidelines as before.).
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "remove complex" remove-complex-opera* interp-Rvar type-check-Rvar)
|
|
|
+\end{lstlisting}
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2175,7 +2193,7 @@ 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
|
|
|
\LangVar{} program.\\
|
|
|
-% s0_11.rkt
|
|
|
+% var_test_11.rkt
|
|
|
\begin{minipage}{0.96\textwidth}
|
|
|
\begin{lstlisting}
|
|
|
(let ([y (let ([x 20])
|
|
@@ -2274,6 +2292,18 @@ statements. We warn against that alternative because the
|
|
|
accumulator-passing style is key to how we generate high-quality code
|
|
|
for conditional expressions in Chapter~\ref{ch:bool-types}.
|
|
|
|
|
|
+\begin{exercise}\normalfont
|
|
|
+%
|
|
|
+Implement the \code{explicate-control} function in
|
|
|
+\code{compiler.rkt}. Create three new \LangInt{} programs that
|
|
|
+exercise the code in \code{explicate-control}.
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "explicate control" explicate-control interp-Cvar type-check-Cvar)
|
|
|
+\end{lstlisting}
|
|
|
+\end{exercise}
|
|
|
|
|
|
\section{Select Instructions}
|
|
|
\label{sec:select-r1}
|
|
@@ -2376,10 +2406,13 @@ recursively and then append the resulting instructions.
|
|
|
\begin{exercise}
|
|
|
\normalfont Implement the \key{select-instructions} pass in
|
|
|
\code{compiler.rkt}. Create three new example programs that are
|
|
|
-designed to exercise all of the interesting cases in this pass. In
|
|
|
-the \code{run-tests.rkt} script, uncomment the line for this pass in
|
|
|
-the list of \code{passes} and then run the script to test your
|
|
|
-compiler.
|
|
|
+designed to exercise all of the interesting cases in this pass.
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "instruction selection" select-instructions interp-pseudo-x86-0)
|
|
|
+\end{lstlisting}
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2399,7 +2432,7 @@ Chapter~\ref{ch:register-allocation-r1}.
|
|
|
|
|
|
Consider again the following \LangVar{} program from
|
|
|
Section~\ref{sec:remove-complex-opera-Rvar}.
|
|
|
-% s0_20.rkt
|
|
|
+% var_test_20.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([a 42])
|
|
|
(let ([b a])
|
|
@@ -2455,9 +2488,13 @@ Implement the \key{assign-homes} pass in \code{compiler.rkt}, defining
|
|
|
auxiliary functions for the non-terminals \Arg{}, \Instr{}, and
|
|
|
\Block{}. We recommend that the auxiliary functions take an extra
|
|
|
parameter that is an alist mapping variable names to homes (stack
|
|
|
-locations for now). In the \code{run-tests.rkt} script, uncomment the
|
|
|
-line for this pass in the list of \code{passes} and then run the
|
|
|
-script to test your compiler.
|
|
|
+locations for now).
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "assign homes" assign-homes interp-x86-0)
|
|
|
+\end{lstlisting}
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2470,7 +2507,7 @@ restriction that at most one argument of an instruction may be a
|
|
|
memory reference.
|
|
|
|
|
|
We return to the following example.
|
|
|
-% s0_20.rkt
|
|
|
+% var_test_20.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([a 42])
|
|
|
(let ([b a])
|
|
@@ -2500,10 +2537,13 @@ from \key{rax} to the destination location, as follows.
|
|
|
\begin{exercise}
|
|
|
\normalfont Implement the \key{patch-instructions} pass in
|
|
|
\code{compiler.rkt}. Create three new example programs that are
|
|
|
-designed to exercise all of the interesting cases in this pass. In
|
|
|
-the \code{run-tests.rkt} script, uncomment the line for this pass in
|
|
|
-the list of \code{passes} and then run the script to test your
|
|
|
-compiler.
|
|
|
+designed to exercise all of the interesting cases in this pass.
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "patch instructions" patch-instructions interp-x86-0)
|
|
|
+\end{lstlisting}
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2527,15 +2567,21 @@ labels like \key{main}. The Racket call \code{(system-type 'os)} is
|
|
|
useful for determining which operating system the compiler is running
|
|
|
on. It returns \code{'macosx}, \code{'unix}, or \code{'windows}.
|
|
|
|
|
|
-\begin{exercise}
|
|
|
- \normalfont Implement the \key{print-x86} pass in
|
|
|
- \code{compiler.rkt}. Uncomment the line for this pass in the list of
|
|
|
- \code{passes} in the \code{run-tests.rkt} script. Also uncomment the
|
|
|
- call to the \key{compiler-tests} function
|
|
|
- (Appendix~\ref{appendix:utilities}), which tests your complete
|
|
|
- compiler by executing the generated x86 code. Compile the provided
|
|
|
- \key{runtime.c} file to \key{runtime.o} using \key{gcc}. Run the
|
|
|
- script to test your compiler.
|
|
|
+\begin{exercise}\normalfont
|
|
|
+%
|
|
|
+Implement the \key{print-x86} pass in \code{compiler.rkt}.
|
|
|
+%
|
|
|
+In the \code{run-tests.rkt} script, add the following entry to the
|
|
|
+list of \code{passes} and then run the script to test your compiler.
|
|
|
+\begin{lstlisting}
|
|
|
+(list "print x86" print-x86 #f)
|
|
|
+\end{lstlisting}
|
|
|
+%
|
|
|
+Uncomment the call to the \key{compiler-tests} function
|
|
|
+(Appendix~\ref{appendix:utilities}), which tests your complete
|
|
|
+compiler by executing the generated x86 code. Compile the provided
|
|
|
+\key{runtime.c} file to \key{runtime.o} using \key{gcc}. Run the
|
|
|
+script to test your compiler.
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -2614,7 +2660,7 @@ in the x86 assembly language but it still uses variables.
|
|
|
\begin{figure}
|
|
|
\begin{minipage}{0.45\textwidth}
|
|
|
Example \LangVar{} program:
|
|
|
-% s0_28.rkt
|
|
|
+% var_test_28.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([v 1])
|
|
|
(let ([w 42])
|
|
@@ -2818,7 +2864,7 @@ instruction. \index{prelude}\index{conclusion}
|
|
|
\begin{figure}[tp]
|
|
|
\begin{minipage}{0.45\textwidth}
|
|
|
Example \LangVar{} program:
|
|
|
-%s0_14.rkt
|
|
|
+%var_test_14.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([x (read)])
|
|
|
(let ([y (read)])
|
|
@@ -4173,7 +4219,7 @@ done in the prelude. We move the stack pointer up by \code{8} bytes
|
|
|
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
|
- % s0_28.rkt
|
|
|
+ % var_test_28.rkt
|
|
|
% (use-minimal-set-of-registers! #t)
|
|
|
% and only rbx rcx
|
|
|
% tmp 0 rbx
|
|
@@ -4359,7 +4405,7 @@ evaluated if $e_1$ evaluates to \code{\#f}.
|
|
|
|
|
|
With the increase in the number of primitive operations, the
|
|
|
interpreter would become repetitive without some care. We refactor
|
|
|
-the clause for \code{Prim}, moving the code that differs with each
|
|
|
+the case for \code{Prim}, moving the code that differs with each
|
|
|
operation into the \code{interp-op} method shown in in
|
|
|
Figure~\ref{fig:interp-op-Rif}. We handle the \code{and} operation
|
|
|
separately because of its short-circuiting behavior.
|
|
@@ -4479,10 +4525,10 @@ error or returns an expression and its type (\key{Integer} or
|
|
|
\key{Boolean}). It returns an expression because there are situations
|
|
|
in which we want to change or update the expression.
|
|
|
|
|
|
-Next we discuss the \code{match} clauses in \code{type-check-exp} of
|
|
|
+Next we discuss the \code{match} cases in \code{type-check-exp} of
|
|
|
Figure~\ref{fig:type-check-Rvar}. The type of an integer constant is
|
|
|
\code{Integer}. To handle variables, the type checker uses the
|
|
|
-environment \code{env} to map variables to types. Consider the clause
|
|
|
+environment \code{env} to map variables to types. Consider the case
|
|
|
for \key{let}. We type check the initializing expression to obtain
|
|
|
its type \key{T} and then associate type \code{T} with the variable
|
|
|
\code{x} in the environment used to type check the body of the
|
|
@@ -4892,9 +4938,9 @@ interfere with the generation of high-quality output in the
|
|
|
\Exp &::=& \gray{ \Atm \mid \READ{} } \\
|
|
|
&\mid& \gray{ \NEG{\Atm} \mid \ADD{\Atm}{\Atm} } \\
|
|
|
&\mid& \gray{ \LET{\Var}{\Exp}{\Exp} } \\
|
|
|
- &\mid& \UNIOP{\key{'not}}{\Atm} \\
|
|
|
+ &\mid& \UNIOP{\key{not}}{\Atm} \\
|
|
|
&\mid& \BINOP{\itm{cmp}}{\Atm}{\Atm} \mid \IF{\Exp}{\Exp}{\Exp} \\
|
|
|
-R^{\dagger}_2 &::=& \PROGRAM{\code{'()}}{\Exp}
|
|
|
+R^{\dagger}_2 &::=& \PROGRAM{\code{()}}{\Exp}
|
|
|
\end{array}
|
|
|
\]
|
|
|
\end{minipage}
|
|
@@ -4913,7 +4959,7 @@ addition of \key{if} this get more interesting.
|
|
|
|
|
|
As a motivating example, consider the following program that has an
|
|
|
\key{if} expression nested in the predicate of another \key{if}.
|
|
|
-% s1_41.rkt
|
|
|
+% cond_test_41.rkt
|
|
|
\begin{center}
|
|
|
\begin{minipage}{0.96\textwidth}
|
|
|
\begin{lstlisting}
|
|
@@ -5025,7 +5071,7 @@ comparison \lstinline{(eq? x 0)} and then branch to \code{block38} or
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{tabular}{lll}
|
|
|
\begin{minipage}{0.4\textwidth}
|
|
|
-% s1_41.rkt
|
|
|
+% cond_test_41.rkt
|
|
|
\begin{lstlisting}
|
|
|
(let ([x (read)])
|
|
|
(let ([y (read)])
|
|
@@ -5095,50 +5141,61 @@ the \key{if}. We need another function, \code{explicate-pred}, that
|
|
|
takes an \LangIf{} expression and two blocks for the then-branch and
|
|
|
else-branch. The output of \code{explicate-pred} is a block.
|
|
|
%
|
|
|
-%% Note that the three explicate functions need to construct a
|
|
|
-%% control-flow graph, which we recommend they do via updates to a global
|
|
|
-%% variable.
|
|
|
-%
|
|
|
In the following paragraphs we discuss specific cases in the
|
|
|
\code{explicate-pred} function as well as additions to the
|
|
|
\code{explicate-tail} and \code{explicate-assign} functions.
|
|
|
|
|
|
-The function \code{explicate-pred} will need 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, $B_1$ and $B_2$, for the two branches of
|
|
|
-the enclosing \key{if}. Suppose the expression is the Boolean
|
|
|
-\code{\#t}. Then we can perform a kind of partial evaluation
|
|
|
-\index{partial evaluation} and translate it to the ``then'' branch
|
|
|
-$B_1$. Likewise, we translate \code{\#f} to the ``else`` branch $B_2$.
|
|
|
-\[
|
|
|
-\key{\#t} \quad\Rightarrow\quad B_1,
|
|
|
-\qquad\qquad\qquad
|
|
|
-\key{\#f} \quad\Rightarrow\quad B_2
|
|
|
-\]
|
|
|
-These two cases demonstrate that we sometimes discard one of the
|
|
|
-blocks that are input to \code{explicate-pred}. We want the blocks
|
|
|
-that we actually use to appear in the resulting control-flow graph,
|
|
|
-but not the discarded blocks. We return to this issue later.
|
|
|
+\begin{figure}[tbp]
|
|
|
+\begin{lstlisting}
|
|
|
+(define (explicate-pred cnd thn els)
|
|
|
+ (match cnd
|
|
|
+ [(Var x) ___]
|
|
|
+ [(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)))]
|
|
|
+ [(Bool b) (if b thn els)]
|
|
|
+ [(If cnd^ thn^ els^) ___]
|
|
|
+ [else (error "explicate-pred unhandled case" cnd)]))
|
|
|
+\end{lstlisting}
|
|
|
+\caption{Skeleton for the \key{explicate-pred} auxiliary function.}
|
|
|
+\label{fig:explicate-pred}
|
|
|
+\end{figure}
|
|
|
+
|
|
|
+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{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 the example of the nested \key{if} expressions. The
|
|
|
-``then'' and ``else'' branches of the current \key{if} inherit their
|
|
|
-context from the current one, that is, predicate context. So we
|
|
|
-recursively apply \code{explicate-pred} to the ``then'' and ``else''
|
|
|
-branches. For both of those recursive calls, we pass the blocks $B_1$
|
|
|
-and $B_2$. Thus, $B_1$ may get used twice, once inside each recursive
|
|
|
-call, and likewise for $B_2$. As discussed above, to avoid duplicating
|
|
|
-code, we need to add these blocks 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 \key{\#t} and
|
|
|
-\key{\#f}, the blocks $B_1$ or $B_2$ 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.
|
|
|
+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{lazy evaluation} \citep{Friedman:1976aa} to delay
|
|
|
+ evaluation}\index{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
|
|
@@ -5150,21 +5207,24 @@ $p$\key{)}\index{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 promised blocks. 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} above, 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
|
|
|
-accomplishes this task. It begins with \code{delay} to create a
|
|
|
-promise. When forced, this promise will force the input block. If that
|
|
|
-block is already a \code{goto} (because it was already added to the
|
|
|
-control-flow graph), then we return that \code{goto}. Otherwise we add
|
|
|
-the block to the control-flow graph with another auxiliary function
|
|
|
-named \code{add-node} that returns the new label, and then return the
|
|
|
+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)
|
|
@@ -5172,63 +5232,60 @@ named \code{add-node} that returns the new label, and then return the
|
|
|
(define b (force block))
|
|
|
(match b
|
|
|
[(Goto label) (Goto label)]
|
|
|
- [else (Goto (add-node b))]
|
|
|
- )))
|
|
|
-\end{lstlisting}
|
|
|
-
|
|
|
-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
|
|
|
-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
|
|
|
-the result $B_5$.
|
|
|
-\[
|
|
|
-(\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els})
|
|
|
-\quad\Rightarrow\quad
|
|
|
-B_5
|
|
|
-\]
|
|
|
-
|
|
|
-Next, consider the case for a less-than comparison in
|
|
|
-\code{explicate-pred}. We translate it to an \code{if} statement,
|
|
|
-whose two branches are required to be \code{goto}'s. So we apply
|
|
|
-\code{block->goto} to $B_1$ and $B_2$ to obtain two promised goto's,
|
|
|
-which we can \code{force} to obtain the two actual goto's $G_1$ and
|
|
|
-$G_2$. The translation of the less-than comparison is as follows.
|
|
|
-\[
|
|
|
-(\key{<}~e_1~e_2) \quad\Rightarrow\quad
|
|
|
-\begin{array}{l}
|
|
|
-\key{if}~(\key{<}~e_1~e_2) \; G_1\\
|
|
|
-\key{else} \; G_2
|
|
|
-\end{array}
|
|
|
-\]
|
|
|
+ [else (Goto (add-node b))])))
|
|
|
+\end{lstlisting}
|
|
|
+
|
|
|
+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
|
|
|
+%% ``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
|
|
|
+%% 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
|
|
|
+%% the result $B_5$.
|
|
|
+%% \[
|
|
|
+%% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els})
|
|
|
+%% \quad\Rightarrow\quad
|
|
|
+%% B_5
|
|
|
+%% \]
|
|
|
+
|
|
|
+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
|
|
|
+%% \code{explicate-tail}.
|
|
|
+%% %
|
|
|
+%% 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
|
|
|
+%% 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''
|
|
|
+%% branch and $G_0$ and let $B_2$ be the result of \code{explicate-tail}
|
|
|
+%% on the ``else'' branch and $G_0$. Let $B_3$ be the result of applying
|
|
|
+%% \code{explicate-pred} to the condition of the \key{if}, $B_1$, and
|
|
|
+%% $B_2$. Then the \key{if} as a whole translates to promise $B_3$.
|
|
|
+%% \[
|
|
|
+%% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_3
|
|
|
+%% \]
|
|
|
|
|
|
-The \code{explicate-tail} function needs to be updated to use lazy
|
|
|
-evaluation and it needs an additional case for \key{if}. Each of the
|
|
|
-cases that return an AST node need use \code{delay} to instead return
|
|
|
-a promise of an AST node. Recall that \code{explicate-tail} has an
|
|
|
-accumulator parameter that is a block, which now becomes a promise of
|
|
|
-a block, which we refer to as $B_0$.
|
|
|
-
|
|
|
-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
|
|
|
-\code{explicate-tail}.
|
|
|
-%
|
|
|
-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
|
|
|
-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''
|
|
|
-branch and $G_0$ and let $B_2$ be the result of \code{explicate-tail}
|
|
|
-on the ``else'' branch and $G_0$. Let $B_3$ be the result of applying
|
|
|
-\code{explicate-pred} to the condition of the \key{if}, $B_1$, and
|
|
|
-$B_2$. Then the \key{if} as a whole translates to promise $B_3$.
|
|
|
-\[
|
|
|
- (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_3
|
|
|
-\]
|
|
|
%% In the above discussion, we use the metavariables $B_1$, $B_2$, and
|
|
|
%% $B_3$ to refer to blocks for the purposes of our discussion, but they
|
|
|
%% should not be confused with the labels for the blocks that appear in
|
|
@@ -5236,30 +5293,31 @@ $B_2$. Then the \key{if} as a whole translates to promise $B_3$.
|
|
|
%% attach labels to blocks when we add them to the control-flow graph, as
|
|
|
%% we see in the next case.
|
|
|
|
|
|
-Next consider the case for \key{if} in the \code{explicate-assign}
|
|
|
-function. The context of the \key{if} is an assignment to some
|
|
|
-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
|
|
|
-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
|
|
|
-$G_1$. Let $B_3$ be the result of applying \code{explicate-assign} to
|
|
|
-the ``else'' branch, variable $x$, and $G_1$. Finally, let $B_4$ be
|
|
|
-the result of applying \code{explicate-pred} to the predicate
|
|
|
-$\itm{cnd}$ and the promises $B_2$ and $B_3$. The \key{if} as a whole
|
|
|
-translates to the promise $B_4$.
|
|
|
-\[
|
|
|
-(\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_4
|
|
|
-\]
|
|
|
-This completes the description of \code{explicate-control} for \LangIf{}.
|
|
|
+%% Next consider the case for \key{if} in the \code{explicate-assign}
|
|
|
+%% function. The context of the \key{if} is an assignment to some
|
|
|
+%% 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
|
|
|
+%% 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
|
|
|
+%% $G_1$. Let $B_3$ be the result of applying \code{explicate-assign} to
|
|
|
+%% the ``else'' branch, variable $x$, and $G_1$. Finally, let $B_4$ be
|
|
|
+%% the result of applying \code{explicate-pred} to the predicate
|
|
|
+%% $\itm{cnd}$ and the promises $B_2$ and $B_3$. The \key{if} as a whole
|
|
|
+%% translates to the promise $B_4$.
|
|
|
+%% \[
|
|
|
+%% (\key{if}\; \itm{cnd}\; \itm{thn}\; \itm{els}) \quad\Rightarrow\quad B_4
|
|
|
+%% \]
|
|
|
+%% This completes the description of \code{explicate-control} for \LangIf{}.
|
|
|
+
|
|
|
|
|
|
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
|
|
|
following program.
|
|
|
-% s1_21.rkt
|
|
|
+% cond_test_21.rkt
|
|
|
\begin{lstlisting}
|
|
|
(if (and (eq? (read) 0) (eq? (read) 1))
|
|
|
0
|
|
@@ -5274,16 +5332,12 @@ following for the above program.
|
|
|
\begin{lstlisting}
|
|
|
start:
|
|
|
tmp1 = (read);
|
|
|
- if (eq? tmp1 0)
|
|
|
- goto block40;
|
|
|
- else
|
|
|
- goto block39;
|
|
|
+ if (eq? tmp1 0) goto block40;
|
|
|
+ else goto block39;
|
|
|
block40:
|
|
|
tmp2 = (read);
|
|
|
- if (eq? tmp2 1)
|
|
|
- goto block38;
|
|
|
- else
|
|
|
- goto block39;
|
|
|
+ if (eq? tmp2 1) goto block38;
|
|
|
+ else goto block39;
|
|
|
block38:
|
|
|
return 0;
|
|
|
block39:
|
|
@@ -5292,10 +5346,20 @@ block39:
|
|
|
\end{center}
|
|
|
|
|
|
\begin{exercise}\normalfont
|
|
|
- Implement the pass \code{explicate-control} by adding the cases for
|
|
|
- \key{if} to the functions for tail and assignment contexts, and
|
|
|
- implement \code{explicate-pred} for predicate contexts. Create test
|
|
|
- cases that exercise all of the new cases in the code for this pass.
|
|
|
+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.
|
|
|
+%
|
|
|
+Create test cases that exercise all of the new cases in the code for
|
|
|
+this pass.
|
|
|
+%
|
|
|
+Add the following entry to the list of \code{passes} in
|
|
|
+\code{run-tests.rkt}
|
|
|
+\begin{lstlisting}
|
|
|
+(list "explicate-control" explicate-control interp-Cif type-check-Cif)
|
|
|
+\end{lstlisting}
|
|
|
+
|
|
|
\end{exercise}
|
|
|
|
|
|
|
|
@@ -5566,7 +5630,7 @@ x86 assembly code.
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{tabular}{lll}
|
|
|
\begin{minipage}{0.5\textwidth}
|
|
|
-% s1_20.rkt
|
|
|
+% cond_test_20.rkt
|
|
|
\begin{lstlisting}
|
|
|
(if (eq? (read) 1) 42 0)
|
|
|
\end{lstlisting}
|
|
@@ -5775,7 +5839,7 @@ optimization on the right.
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{tabular}{lll}
|
|
|
\begin{minipage}{0.5\textwidth}
|
|
|
-% s1_20.rkt
|
|
|
+% cond_test_20.rkt
|
|
|
\begin{lstlisting}
|
|
|
start:
|
|
|
callq read_int
|
|
@@ -8576,8 +8640,8 @@ syntax for function application.
|
|
|
\label{sec:interp-Rlambda}
|
|
|
|
|
|
Figure~\ref{fig:interp-Rlambda} shows the definitional interpreter for
|
|
|
-\LangLam{}. The clause for \key{lambda} saves the current environment
|
|
|
-inside the returned \key{lambda}. Then the clause for \key{Apply} uses
|
|
|
+\LangLam{}. The case for \key{lambda} saves the current environment
|
|
|
+inside the returned \key{lambda}. Then the case for \key{Apply} uses
|
|
|
the environment from the \key{lambda}, the \code{lam-env}, when
|
|
|
interpreting the body of the \key{lambda}. The \code{lam-env}
|
|
|
environment is extended with the mapping of parameters to argument
|
|
@@ -8685,7 +8749,7 @@ that comes after \code{reveal-functions} and before
|
|
|
\code{limit-functions}.
|
|
|
|
|
|
As usual, we implement the pass as a recursive function over the
|
|
|
-AST. All of the action is in the clauses for \key{Lambda} and
|
|
|
+AST. All of the action is in the cases for \key{Lambda} and
|
|
|
\key{Apply}. We transform a \key{Lambda} expression into an expression
|
|
|
that creates a closure, that is, a vector whose first element is a
|
|
|
function pointer and the rest of the elements are the free variables
|
|
@@ -9195,7 +9259,7 @@ typed language (it's dynamically typed!).
|
|
|
|
|
|
The definitional interpreter for \LangDyn{} is presented in
|
|
|
Figure~\ref{fig:interp-Rdyn} and its auxiliary functions are defined in
|
|
|
-Figure~\ref{fig:interp-Rdyn-aux}. Consider the match clause for
|
|
|
+Figure~\ref{fig:interp-Rdyn-aux}. Consider the match case for
|
|
|
\code{(Int n)}. Instead of simply returning the integer \code{n} (as
|
|
|
in the interpreter for \LangVar{} in Figure~\ref{fig:interp-Rvar}), the
|
|
|
interpreter for \LangDyn{} creates a \emph{tagged value}\index{tagged
|
|
@@ -9212,7 +9276,7 @@ example, a vector of type \code{(Vector Any Any)} is tagged with
|
|
|
\code{Vector} and a procedure of type \code{(Any Any -> Any)}
|
|
|
is tagged with \code{Procedure}.
|
|
|
|
|
|
-Next consider the match clause for \code{vector-ref}. The
|
|
|
+Next consider the match case for \code{vector-ref}. The
|
|
|
\code{check-tag} auxiliary function (Figure~\ref{fig:interp-Rdyn-aux})
|
|
|
is used to ensure that the first argument is a vector and the second
|
|
|
is an integer. If they are not, a \code{trapped-error} is raised.
|