Explorar o código

clarifications in register allocation

Jeremy Siek %!s(int64=2) %!d(string=hai) anos
pai
achega
8b3e99529d
Modificáronse 1 ficheiros con 57 adicións e 50 borrados
  1. 57 50
      book.tex

+ 57 - 50
book.tex

@@ -249,7 +249,7 @@ concepts and algorithms used in compilers.
     syntax trees} and \emph{recursive functions}. 
     syntax trees} and \emph{recursive functions}. 
 {\if\edition\pythonEd
 {\if\edition\pythonEd
 \item In Chapter~\ref{ch:parsing} we learn how to use the Lark
 \item In Chapter~\ref{ch:parsing} we learn how to use the Lark
-  parser generator to create a parser for the language of integer
+  parser framework to create a parser for the language of integer
   arithmetic and local variables. We learn about the parsing
   arithmetic and local variables. We learn about the parsing
   algorithms inside Lark, including Earley and LALR(1).
   algorithms inside Lark, including Earley and LALR(1).
 %
 %
@@ -309,15 +309,21 @@ mathematics.
 %
 %
 At the beginning of the course, students form groups of two to four
 At the beginning of the course, students form groups of two to four
 people.  The groups complete approximately one chapter every two
 people.  The groups complete approximately one chapter every two
-weeks, starting with chapter~\ref{ch:Lvar}. The last two weeks of the
-course involve a final project in which students design and implement
-a compiler extension of their choosing.  The last few chapters can be
-used in support of these projects.  Many chapters include a challenge
-problem that we assign to the graduate students. For compiler courses
-at universities on the quarter system (about ten weeks in length), we
-recommend completing the course through chapter~\ref{ch:Lvec} or
-chapter~\ref{ch:Lfun} and providing some scaffolding code to the
-students for each compiler pass.
+weeks, starting with chapter~\ref{ch:Lvar} and including chapters
+according to the students interests while respecting the dependencies
+between chapters shown in
+Figure~\ref{fig:chapter-dependences}. Chapter~\ref{ch:Lfun}
+(functions) depends on chapter~\ref{ch:Lvec} (tuples) only in the
+implementation of efficient tail calls.
+%
+The last two weeks of the course involve a final project in which
+students design and implement a compiler extension of their choosing.
+The last few chapters can be used in support of these projects.  Many
+chapters include a challenge problem that we assign to the graduate
+students. For compiler courses at universities on the quarter system
+(about ten weeks in length), we recommend completing the course
+through chapter~\ref{ch:Lvec} or chapter~\ref{ch:Lfun} and providing
+some scaffolding code to the students for each compiler pass.
 %
 %
 The course can be adapted to emphasize functional languages by
 The course can be adapted to emphasize functional languages by
 skipping chapter~\ref{ch:Lwhile} (loops) and including
 skipping chapter~\ref{ch:Lwhile} (loops) and including
@@ -326,11 +332,6 @@ dynamically typed languages by including chapter~\ref{ch:Ldyn}.
 %
 %
 %% \python{A course that emphasizes object-oriented languages would
 %% \python{A course that emphasizes object-oriented languages would
 %%   include Chapter~\ref{ch:Lobject}.}
 %%   include Chapter~\ref{ch:Lobject}.}
-%
-Figure~\ref{fig:chapter-dependences} depicts the dependencies between
-chapters. Chapter~\ref{ch:Lfun} (functions) depends on
-chapter~\ref{ch:Lvec} (tuples) only in the implementation of efficient
-tail calls.
 
 
 This book has been used in compiler courses at California Polytechnic
 This book has been used in compiler courses at California Polytechnic
 State University, Portland State University, Rose–Hulman Institute of
 State University, Portland State University, Rose–Hulman Institute of
@@ -569,9 +570,9 @@ input_int() + -8
 \begin{equation}
 \begin{equation}
 \begin{tikzpicture}
 \begin{tikzpicture}
  \node[draw] (plus)  at (0 ,  0) {\key{+}};
  \node[draw] (plus)  at (0 ,  0) {\key{+}};
- \node[draw] (read)  at (-1, -1.5) {{\if\edition\racketEd\footnotesize\key{read}\fi\if\edition\pythonEd\key{input\_int()}\fi}};
- \node[draw] (minus) at (1 , -1.5) {$\key{-}$};
- \node[draw] (8)     at (1 , -3) {\key{8}};
+ \node[draw] (read)  at (-1, -1) {{\if\edition\racketEd\footnotesize\key{read}\fi\if\edition\pythonEd\key{input\_int()}\fi}};
+ \node[draw] (minus) at (1 , -1) {$\key{-}$};
+ \node[draw] (8)     at (1 , -2) {\key{8}};
 
 
  \draw[->] (plus) to (read);
  \draw[->] (plus) to (read);
  \draw[->] (plus) to (minus);
  \draw[->] (plus) to (minus);
@@ -5170,40 +5171,46 @@ to a stack location in the first place. Or better yet, if we can
 arrange for \code{x} to be placed in a callee-saved register, then it
 arrange for \code{x} to be placed in a callee-saved register, then it
 won't need to be saved and restored during function calls.
 won't need to be saved and restored during function calls.
 
 
-The approach that we recommend for call-live variables is either to
-assign them to callee-saved registers or to spill them to the
-stack. On the other hand, for variables that are not call-live, we try
-the following alternatives in order: (1) look for an available
-caller-saved register (to leave room for other variables in the
-callee-saved register), (2) look for a callee-saved register, and (3)
-spill the variable to the stack.
-
-It is straightforward to implement this approach in a graph coloring
-register allocator. First, we know which variables are call-live
-because we already need to compute which variables are in use at every
-instruction (section~\ref{sec:liveness-analysis-Lvar}). Second, when
-we build the interference graph
-(section~\ref{sec:build-interference}), we can place an edge between
-each of the call-live variables and the caller-saved registers in the
-interference graph. This will prevent the graph coloring algorithm
-from assigning them to caller-saved registers.
+We recommend an approach that captures these issues in the
+interference graph, without complicating the graph coloring algorithm.
+During liveness analysis we know which variables are call-live because
+we compute which variables are in use at every instruction
+(section~\ref{sec:liveness-analysis-Lvar}). When we build the
+interference graph (section~\ref{sec:build-interference}), we can
+place an edge between each call-live variable and the caller-saved
+registers in the interference graph. This will prevent the graph
+coloring algorithm from assigning call-live variables to caller-saved
+registers.
+
+On the other hand, for variables that are not call-live, we prefer
+placing them in caller-saved registers to leave more room for
+call-live variables in the callee-saved registers. This can also be
+implemented without complicating the graph coloring algorithm. We
+recommend that the graph coloring algorithm assign variables to
+natural numbers, choosing the lowest number for which there is no
+interference. After the coloring is complete, we assign the numbers to
+registers and stack locations: placing the caller-saved registers in
+the lowest numbers, followed by the callee-saved registers, then
+placing the largest numbers in stack locations. This ordering gives
+preference to registers over stack locations and to caller-saved
+registers over callee-saved registers.
 
 
 Returning to the example in
 Returning to the example in
 figure~\ref{fig:example-calling-conventions}, let us analyze the
 figure~\ref{fig:example-calling-conventions}, let us analyze the
-generated x86 code on the right-hand side. Notice that variable
-\code{x} is assigned to \code{rbx}, a callee-saved register. Thus, it
-is already in a safe place during the second call to
-\code{read\_int}. Next, notice that variable \code{y} is assigned to
-\code{rcx}, a caller-saved register, because \code{y} is not a
-call-live variable.
-
-Next we analyze the example from the callee point of view, focusing on
-the prelude and conclusion of the \code{main} function. As usual, the
-prelude begins with saving the \code{rbp} register to the stack and
-setting the \code{rbp} to the current stack pointer. We now know why
-it is necessary to save the \code{rbp}: it is a callee-saved register.
-The prelude then pushes \code{rbx} to the stack because (1) \code{rbx}
-is a callee-saved register and (2) \code{rbx} is assigned to a variable
+generated x86 code on the right-hand side. Variable \code{x} is
+assigned to \code{rbx}, a callee-saved register. Thus, it is already
+in a safe place during the second call to \code{read\_int}. Next,
+variable \code{y} is assigned to \code{rcx}, a caller-saved register,
+because \code{y} is not a call-live variable.
+
+We have completed the analysis from the caller point of view, so now
+we switch to the callee point of view, focusing on the prelude and
+conclusion of the \code{main} function. As usual, the prelude begins
+with saving the \code{rbp} register to the stack and setting the
+\code{rbp} to the current stack pointer. We now know why it is
+necessary to save the \code{rbp}: it is a callee-saved register.  The
+prelude then pushes \code{rbx} to the stack because (1) \code{rbx} is
+a callee-saved register and (2) \code{rbx} is assigned to a variable
 (\code{x}). The other callee-saved registers are not saved in the
 (\code{x}). The other callee-saved registers are not saved in the
 prelude because they are not used. The prelude subtracts 8 bytes from
 prelude because they are not used. The prelude subtracts 8 bytes from
 the \code{rsp} to make it 16-byte aligned. Shifting attention to the
 the \code{rsp} to make it 16-byte aligned. Shifting attention to the
@@ -22822,7 +22829,7 @@ print(t[1])
 \label{fig:map-resolve}
 \label{fig:map-resolve}
 \end{figure}
 \end{figure}
 
 
-\section{Erase Types}
+\section{Erase Generic Types}
 \label{sec:erase_types}
 \label{sec:erase_types}
 
 
 We use the \CANYTY{} type presented in chapter~\ref{ch:Ldyn} to
 We use the \CANYTY{} type presented in chapter~\ref{ch:Ldyn} to