|
@@ -5330,22 +5330,22 @@ Test your compiler using your previously created programs on the
|
|
|
\node (R2-2) at (3,2) {\large $R_2$};
|
|
|
\node (R2-3) at (6,2) {\large $R_2$};
|
|
|
\node (R2-4) at (9,2) {\large $R_2$};
|
|
|
-\node (R2-5) at (9,0) {\large $R_2$};
|
|
|
-\node (C1-1) at (3,-2) {\large $C_1$};
|
|
|
+\node (R2-5) at (12,2) {\large $R_2$};
|
|
|
+\node (C1-1) at (3,0) {\large $C_1$};
|
|
|
|
|
|
-\node (x86-2) at (3,-4) {\large $\text{x86}^{*}_1$};
|
|
|
-\node (x86-3) at (6,-4) {\large $\text{x86}^{*}_1$};
|
|
|
-\node (x86-4) at (9,-4) {\large $\text{x86}^{*}_1$};
|
|
|
-\node (x86-5) at (9,-6) {\large $\text{x86}^{\dagger}_1$};
|
|
|
+\node (x86-2) at (3,-2) {\large $\text{x86}^{*}_1$};
|
|
|
+\node (x86-3) at (6,-2) {\large $\text{x86}^{*}_1$};
|
|
|
+\node (x86-4) at (9,-2) {\large $\text{x86}^{*}_1$};
|
|
|
+\node (x86-5) at (9,-4) {\large $\text{x86}^{\dagger}_1$};
|
|
|
|
|
|
-\node (x86-2-1) at (3,-6) {\large $\text{x86}^{*}_1$};
|
|
|
-\node (x86-2-2) at (6,-6) {\large $\text{x86}^{*}_1$};
|
|
|
+\node (x86-2-1) at (3,-4) {\large $\text{x86}^{*}_1$};
|
|
|
+\node (x86-2-2) at (6,-4) {\large $\text{x86}^{*}_1$};
|
|
|
|
|
|
\path[->,bend left=15] (R2) edge [above] node {\ttfamily\footnotesize\color{red} type-check} (R2-2);
|
|
|
\path[->,bend left=15] (R2-2) edge [above] node {\ttfamily\footnotesize\color{red} shrink} (R2-3);
|
|
|
\path[->,bend left=15] (R2-3) edge [above] node {\ttfamily\footnotesize uniquify} (R2-4);
|
|
|
-\path[->,bend left=15] (R2-4) edge [right] node {\ttfamily\footnotesize remove-complex.} (R2-5);
|
|
|
-\path[->,bend right=15] (R2-5) edge [left] node {\ttfamily\footnotesize\color{red} explicate-control} (C1-1);
|
|
|
+\path[->,bend left=15] (R2-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R2-5);
|
|
|
+\path[->,bend left=15] (R2-5) edge [left] node {\ttfamily\footnotesize\color{red} explicate-control} (C1-1);
|
|
|
\path[->,bend right=15] (C1-1) edge [left] node {\ttfamily\footnotesize\color{red} select-instructions} (x86-2);
|
|
|
\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize\color{red} uncover-live} (x86-2-1);
|
|
|
\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build-inter.} (x86-2-2);
|
|
@@ -6805,24 +6805,23 @@ conclusion:
|
|
|
\node (R3-2) at (3,2) {\large $R_3$};
|
|
|
\node (R3-3) at (6,2) {\large $R_3$};
|
|
|
\node (R3-4) at (9,2) {\large $R_3$};
|
|
|
-\node (R3-5) at (9,0) {\large $R'_3$};
|
|
|
-\node (R3-6) at (6,0) {\large $R'_3$};
|
|
|
-\node (C2-4) at (3,-2) {\large $C_2$};
|
|
|
-
|
|
|
-\node (x86-2) at (3,-4) {\large $\text{x86}^{*}_2$};
|
|
|
-\node (x86-3) at (6,-4) {\large $\text{x86}^{*}_2$};
|
|
|
-\node (x86-4) at (9,-4) {\large $\text{x86}^{*}_2$};
|
|
|
-\node (x86-5) at (9,-6) {\large $\text{x86}^{\dagger}_2$};
|
|
|
-
|
|
|
-\node (x86-2-1) at (3,-6) {\large $\text{x86}^{*}_2$};
|
|
|
-\node (x86-2-2) at (6,-6) {\large $\text{x86}^{*}_2$};
|
|
|
-
|
|
|
-\path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize\color{red} type-check} (R3-2);
|
|
|
-\path[->,bend left=15] (R3-2) edge [above] node {\ttfamily\footnotesize shrink} (R3-3);
|
|
|
-\path[->,bend left=15] (R3-3) edge [above] node {\ttfamily\footnotesize uniquify} (R3-4);
|
|
|
-\path[->,bend left=15] (R3-4) edge [right] node {\ttfamily\footnotesize\color{red} expose-alloc.} (R3-5);
|
|
|
-\path[->,bend left=15] (R3-5) edge [below] node {\ttfamily\footnotesize remove-complex.} (R3-6);
|
|
|
-\path[->,bend right=20] (R3-6) edge [left] node {\ttfamily\footnotesize explicate-control} (C2-4);
|
|
|
+\node (R3-5) at (12,2) {\large $R'_3$};
|
|
|
+\node (C2-4) at (3,0) {\large $C_2$};
|
|
|
+
|
|
|
+\node (x86-2) at (3,-2) {\large $\text{x86}^{*}_2$};
|
|
|
+\node (x86-3) at (6,-2) {\large $\text{x86}^{*}_2$};
|
|
|
+\node (x86-4) at (9,-2) {\large $\text{x86}^{*}_2$};
|
|
|
+\node (x86-5) at (9,-4) {\large $\text{x86}^{\dagger}_2$};
|
|
|
+
|
|
|
+\node (x86-2-1) at (3,-4) {\large $\text{x86}^{*}_2$};
|
|
|
+\node (x86-2-2) at (6,-4) {\large $\text{x86}^{*}_2$};
|
|
|
+
|
|
|
+%\path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize\color{red} type-check} (R3-2);
|
|
|
+\path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize shrink} (R3-2);
|
|
|
+\path[->,bend left=15] (R3-2) edge [above] node {\ttfamily\footnotesize uniquify} (R3-3);
|
|
|
+\path[->,bend left=15] (R3-3) edge [above] node {\ttfamily\footnotesize\color{red} expose-alloc.} (R3-4);
|
|
|
+\path[->,bend left=15] (R3-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R3-5);
|
|
|
+\path[->,bend left=20] (R3-5) edge [left] node {\ttfamily\footnotesize explicate-control} (C2-4);
|
|
|
\path[->,bend left=15] (C2-4) edge [right] node {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
|
|
|
\path[->,bend right=15] (x86-2) edge [left] node {\ttfamily\footnotesize uncover-live} (x86-2-1);
|
|
|
\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize\color{red} build-inter.} (x86-2-2);
|
|
@@ -8005,7 +8004,7 @@ previously created test programs.
|
|
|
\begin{tikzpicture}[baseline=(current bounding box.center)]
|
|
|
\node (R4) at (0,2) {\large $R_4$};
|
|
|
\node (R4-2) at (3,2) {\large $R_4$};
|
|
|
-\node (R4-3) at (6,2) {\large $R_4$};
|
|
|
+%\node (R4-3) at (6,2) {\large $R_4$};
|
|
|
\node (F1-1) at (12,0) {\large $F_1$};
|
|
|
\node (F1-2) at (9,0) {\large $F_1$};
|
|
|
\node (F1-3) at (6,0) {\large $F_1$};
|
|
@@ -8020,11 +8019,11 @@ previously created test programs.
|
|
|
\node (x86-2-1) at (3,-6) {\large $\text{x86}^{*}_3$};
|
|
|
\node (x86-2-2) at (6,-6) {\large $\text{x86}^{*}_3$};
|
|
|
|
|
|
+%\path[->,bend left=15] (R4) edge [above] node
|
|
|
+% {\ttfamily\footnotesize\color{red} type-check} (R4-2);
|
|
|
\path[->,bend left=15] (R4) edge [above] node
|
|
|
- {\ttfamily\footnotesize\color{red} type-check} (R4-2);
|
|
|
-\path[->,bend left=15] (R4-2) edge [above] node
|
|
|
- {\ttfamily\footnotesize uniquify} (R4-3);
|
|
|
-\path[->,bend left=15] (R4-3) edge [right] node
|
|
|
+ {\ttfamily\footnotesize uniquify} (R4-2);
|
|
|
+\path[->,bend left=15] (R4-2) edge [right] node
|
|
|
{\ttfamily\footnotesize\color{red} reveal-functions} (F1-1);
|
|
|
\path[->,bend left=15] (F1-1) edge [below] node
|
|
|
{\ttfamily\footnotesize\color{red} limit-functions} (F1-2);
|
|
@@ -8156,6 +8155,7 @@ mainconclusion:
|
|
|
\end{figure}
|
|
|
|
|
|
|
|
|
+% Challenge idea: inlining! (simple version)
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
@@ -8660,23 +8660,24 @@ all functions, obtaining the following output for this program.
|
|
|
\end{center}
|
|
|
|
|
|
In the previous Chapter, there would be no allocation in the program
|
|
|
-and the calls to \code{tail\_sum} would be direct calls. In contrast,
|
|
|
+and the calls to \code{tail-sum} would be direct calls. In contrast,
|
|
|
the above program allocates memory for each \code{closure} and the
|
|
|
-calls to \code{tail\_sum} are indirect. These two differences incur
|
|
|
+calls to \code{tail-sum} are indirect. These two differences incur
|
|
|
considerable overhead in a program such as this one, where the
|
|
|
allocations and indirect calls occur inside a tight loop.
|
|
|
|
|
|
One might think that this problem is trivial to solve: can't we just
|
|
|
recognize calls of the form \code{((fun-ref $f$) $e_1 \ldots e_n$)}
|
|
|
-and compile it to a direct call \code{((fun-ref $f$) $e'_1 \ldots e'_n$)}
|
|
|
-instead of treating it like a call to a closure? We would
|
|
|
-also drop the \code{fvs5} parameter of \code{tail\_sum}.
|
|
|
+and compile them to direct calls \code{((fun-ref $f$) $e'_1 \ldots
|
|
|
+ e'_n$)} instead of treating it like a call to a closure? We would
|
|
|
+also drop the \code{fvs5} parameter of \code{tail\_sum1}.
|
|
|
%
|
|
|
However, this problem is not so trivial because a global function may
|
|
|
``escape'' and become involved in applications that also involve
|
|
|
closures. Consider the following example in which the application
|
|
|
-\code{(f 41)} needs to be compiled into a closure application and the
|
|
|
-\code{add1} function might get bound to \code{f}.
|
|
|
+\code{(f 41)} needs to be compiled into a closure application, because
|
|
|
+the \code{lambda} may get bound to \code{f}, but the \code{add1}
|
|
|
+function might also get bound to \code{f}.
|
|
|
\begin{lstlisting}
|
|
|
(define (add1 [x : Integer]) : Integer
|
|
|
(+ x 1))
|
|
@@ -8690,13 +8691,13 @@ closures. Consider the following example in which the application
|
|
|
If a global function name is used in any way other than as the
|
|
|
operator in a direct call, then we say that the function
|
|
|
\emph{escapes}. If a global function does not escape, then we do not
|
|
|
-need to perform closure conversion to the function.
|
|
|
+need to perform closure conversion on the function.
|
|
|
|
|
|
\begin{exercise}\normalfont
|
|
|
Implement an auxilliary function for detecting which global
|
|
|
functions escape. Using that function, implement an improved version
|
|
|
of closure conversion that does not apply closure conversion to
|
|
|
- global functions that do not escape, but instead compiles them as
|
|
|
+ global functions that do not escape but instead compiles them as
|
|
|
regular functions. Create several new test cases that check whether
|
|
|
you properly detect whether global functions escape or not.
|
|
|
\end{exercise}
|
|
@@ -8735,16 +8736,15 @@ to \code{lambda5}:
|
|
|
|
|
|
The problem of determining which lambda will be called from a
|
|
|
particular application is quite challenging in general and the topic
|
|
|
-of considerable research~\citep{Shivers:1988aa,Gilray:2016aa}. For
|
|
|
-this challenge assignment we recommend that you simply maintain an
|
|
|
-environment mapping \code{let}-bound variables to function names that
|
|
|
-is exended whenever you encounter a closure on the right-hand side of
|
|
|
-a \code{let}. The \code{let}-bound variable should be mapped to the
|
|
|
-name of the global function for the closure. Then, when you encounter
|
|
|
-an application in which the operator is a variable, you can compile
|
|
|
-the application to a direct call if that variable is mapped to a
|
|
|
-function name in the environment. This pass should come after closure
|
|
|
-conversion.
|
|
|
+of considerable research~\citep{Shivers:1988aa,Gilray:2016aa}. For the
|
|
|
+following exercise we recommend that you compile an application to a
|
|
|
+direct call when the operator is a variable and the variable is
|
|
|
+\code{let}-bound to a closure. This can be accomplished by maintaining
|
|
|
+an environment mapping \code{let}-bound variables to function names.
|
|
|
+Extend the environment whenever you encounter a closure on the
|
|
|
+right-hand side of a \code{let}, mapping the \code{let}-bound variable
|
|
|
+to the name of the global function for the closure. This pass should
|
|
|
+come after closure conversion.
|
|
|
|
|
|
\begin{exercise}\normalfont
|
|
|
Implement a compiler pass, named \code{optimize-known-calls}, that
|
|
@@ -8752,7 +8752,7 @@ compiles known calls into direct calls. Verify that your compiler is
|
|
|
successful in this regard on several example programs.
|
|
|
\end{exercise}
|
|
|
|
|
|
-This challenge assignment only scratches the surface of optimizing of
|
|
|
+These exercises only scratches the surface of optimizing of
|
|
|
closures. A good next step for the interested reader is to look at the
|
|
|
work of \citet{Keep:2012ab}.
|
|
|
|