瀏覽代碼

arity in callq

Jeremy Siek 4 年之前
父節點
當前提交
0d546be443
共有 2 個文件被更改,包括 58 次插入33 次删除
  1. 55 30
      book.tex
  2. 3 3
      defs.tex

+ 55 - 30
book.tex

@@ -1378,7 +1378,11 @@ stores the result in $d$.
 %
 The $\key{callq}\,\itm{label}$ instruction executes the procedure
 specified by the label and $\key{retq}$ returns from a procedure to
-its caller. We discuss procedure calls in more detail later in this
+its caller. The abstract syntax for \code{callq} includes an extra
+integer field that represents the arity (number of parameters) of the
+function being called.
+%
+We discuss procedure calls in more detail later in this
 chapter and in Chapter~\ref{ch:functions}. The
 $\key{jmp}\,\itm{label}$ instruction updates the program counter to
 the address of the instruction after the specified label.
@@ -1559,7 +1563,7 @@ field should just contain an empty list.
        \mid \BININSTR{\code{'subq}}{\Arg}{\Arg} \\
        &\mid& \BININSTR{\code{'movq}}{\Arg}{\Arg}
        \mid \UNIINSTR{\code{'negq}}{\Arg}\\
-       &\mid& \CALLQ{\itm{label}} \mid \RETQ{} 
+       &\mid& \CALLQ{\itm{label}}{\itm{int}} \mid \RETQ{} 
        \mid \PUSHQ{\Arg} \mid \POPQ{\Arg} \mid \JMP{\itm{label}} \\
 \Block &::= & \BLOCK{\itm{info}}{\Instr\ldots} \\
 x86_0 &::= & \PROGRAM{\itm{info}}{\CFG{\key{(}\itm{label} \,\key{.}\, \Block \key{)}\ldots}}
@@ -2630,14 +2634,13 @@ As we perform register allocation, we need to be aware of the
 conventions that govern the way in which registers interact with
 function calls, such as calls to the \code{read\_int} function in our
 generated code and even the call that the operating system makes to
-execute our \code{main} function.  The convention for x86 is that the
-caller is responsible for freeing up some registers, the
-\emph{caller-saved registers}, prior to the function call, and the
-callee is responsible for preserving the values in some other
-registers, the \emph{callee-saved registers}.
-\index{caller-saved registers}
-\index{callee-saved registers}
-The caller-saved registers are
+execute our \code{main} function.  The convention for x86 regarding
+how functions share the use of registers is that the caller is
+responsible for freeing up some registers, the \emph{caller-saved
+  registers}, prior to the function call, and the callee is
+responsible for preserving the values of some other registers, the
+\emph{callee-saved registers}.  \index{caller-saved registers}
+\index{callee-saved registers} The caller-saved registers are
 \begin{lstlisting}
 rax rcx rdx rsi rdi r8 r9 r10 r11
 \end{lstlisting}
@@ -2662,6 +2665,21 @@ view, the caller view and the callee view:
   restoring the value in the conclusion of the function.
 \end{itemize}
 
+In x86, registers are also used for passing arguments to a function
+and for the return value.  In particular, the first six arguments of a
+function are passed in the following six registers, in the order
+given.
+\begin{lstlisting}
+rdi rsi rdx rcx r8 r9
+\end{lstlisting}
+If there are more than six arguments, then the convention is to use
+space on the frame of the caller for the rest of the
+arguments. However, in Chapter~\ref{ch:functions} we arrange to never
+need more than six arguments. For now, the only function we care about
+is \code{read\_int} and it takes zero argument.
+%
+The register \code{rax} is for the return value of a function.
+
 The next question is how these calling conventions impact register
 allocation. Consider the $R_1$ program in
 Figure~\ref{fig:example-calling-conventions}.  We first analyze this
@@ -2931,7 +2949,7 @@ shown between each instruction to make the figure easy to read.
 \begin{exercise}\normalfont
 Implement the compiler pass named \code{uncover-live} that computes
 the live-after sets. We recommend storing the live-after sets (a list
-of a set of variables) in the $\itm{info}$ field of the \key{Block}
+of a set of variables) in the $\itm{info}$ field of the \code{Block}
 structure.
 %
 We recommend organizing your code to use a helper function that takes
@@ -2942,10 +2960,14 @@ We recommend creating helper functions to 1) compute the set of
 locations that appear in an argument (of an instruction), 2) compute
 the locations read by an instruction which corresponds to the $R$
 function discussed above, and 3) the locations written by an
-instruction which corresponds to $W$. The \key{callq} instruction
-should include all of the caller-saved registers in its $W$ because
-the calling convention says that those registers may be written to
-during the function call.
+instruction which corresponds to $W$. The \code{callq} instruction
+should include all of the caller-saved registers in its write-set $W$
+because the calling convention says that those registers may be
+written to during the function call. Likewise, the \code{callq}
+instruction should include the appropriate number of argument passing
+registers in its read-set $R$, depending on the arity of the function
+being called. (This is why the abstract syntax for \code{callq}
+includes the arity.)
 
 \end{exercise}
 
@@ -4326,7 +4348,7 @@ x86_1 &::= & \gray{ \key{.globl main} }\\
        \mid \BININSTR{\code{'subq}}{\Arg}{\Arg} } \\
        &\mid& \gray{ \BININSTR{\code{'movq}}{\Arg}{\Arg} 
        \mid \UNIINSTR{\code{'negq}}{\Arg} } \\
-       &\mid& \gray{ \CALLQ{\itm{label}} \mid \RETQ{} 
+       &\mid& \gray{ \CALLQ{\itm{label}}{\itm{int}} \mid \RETQ{} 
        \mid \PUSHQ{\Arg} \mid \POPQ{\Arg} \mid \JMP{\itm{label}} } \\
        &\mid& \BININSTR{\code{'xorq}}{\Arg}{\Arg}
        \mid \BININSTR{\code{'cmpq}}{\Arg}{\Arg}\\
@@ -7072,18 +7094,20 @@ generated by different compilers. As a result, people have developed
 Here we use conventions that are compatible with those of the
 \code{gcc} compiler~\citep{Matz:2013aa}.
 
-Regarding (1) parameter passing, the convention is to use the
-following six registers:
+Regarding (1) parameter passing, recall that the following six
+registers:
 \begin{lstlisting}
 rdi rsi rdx rcx r8 r9
 \end{lstlisting}
-in that order, to pass arguments to a function. If there are more than
-six arguments, then the convention is to use space on the frame of the
-caller for the rest of the arguments. However, to ease the
-implementation of efficient tail calls (Section~\ref{sec:tail-call}),
-we arrange to never need more than six arguments.
+in that order, are used to pass arguments to a function. If there are
+more than six arguments, then the convention is to use space on the
+frame of the caller for the rest of the arguments. However, to ease
+the implementation of efficient tail calls
+(Section~\ref{sec:tail-call}), we arrange to never need more than six
+arguments.
 %
-The register \code{rax} is for the return value of the function.
+Also recall that the register \code{rax} is for the return value of
+the function.
 
 \index{prelude}\index{conclusion}
 
@@ -7538,8 +7562,8 @@ x86_3 &::= & (\key{program} \;\itm{info} \;\Def\ldots)
   \Arg &::=&  \gray{  \INT{\Int} \mid \REG{\Reg} \mid \DEREF{\Reg}{\Int}
      \mid \BYTEREG{\Reg} } \\
      &\mid& \gray{ (\key{Global}~\Var) } \mid \FUNREF{\itm{label}} \\
-  \Instr &::=& \ldots \mid \INDCALLQ{\itm{label}}
-    \mid \TAILJMP{\Arg}\\
+  \Instr &::=& \ldots \mid \INDCALLQ{\itm{label}}{\itm{int}}
+    \mid \TAILJMP{\Arg}{\itm{int}}\\
     &\mid& \BININSTR{\code{'leaq}}{\Arg}{\REG{\Reg}}\\
   \Def &::= & \DEF{\itm{label}}{([\Var\key{:}\Type]\ldots)}{\Type}{((\itm{label}\,\key{.}\,\Block)\ldots)} \\
 x86_3 &::= & \PROGRAMDEFS{\itm{info}}{(\Def\ldots)}
@@ -7552,7 +7576,6 @@ x86_3 &::= & \PROGRAMDEFS{\itm{info}}{(\Def\ldots)}
 \end{figure}
 
 
-
 An assignment of a function reference to a variable becomes a
 load-effective-address instruction as follows: \\
 \begin{tabular}{lcl}
@@ -7648,7 +7671,9 @@ the procedure call stack.  However, we do not yet know how big the
 frame is; that gets determined during register allocation. So instead
 of generating those instructions here, we invent a new instruction
 that means ``pop the frame and then do an indirect jump'', which we
-name \code{TailJmp}.
+name \code{TailJmp}. The abstract syntax for this instruction includes
+an argument that specifies where to jump and an integer that
+represents the arity of the function being called.
 
 Recall that in Section~\ref{sec:explicate-control-r1} we recommended
 using the label \code{start} for the initial block of a program, and
@@ -7710,7 +7735,7 @@ For the \code{print-x86} pass, the cases for \code{FunRef} and
 syntax.
 \begin{lstlisting}
   (FunRef |\itm{label}|) |$\Rightarrow$| |\itm{label}|(%rip)
-  (IndirectCallq |\itm{arg}|) |$\Rightarrow$| callq *|\itm{arg}'|
+  (IndirectCallq |\itm{arg}| |\itm{int}|) |$\Rightarrow$| callq *|\itm{arg}'|
 \end{lstlisting}
 
 The \code{TailJmp} node requires a bit work. A straightforward
@@ -7795,7 +7820,7 @@ Figure~\ref{fig:add-fun} shows an example translation of a simple
 function in $R_4$ to x86. The figure also includes the results of the
 \code{explicate-control} and \code{select-instructions} passes.
 
-\begin{figure}[tbp]
+\begin{figure}[htbp]
 \begin{tabular}{ll}
 \begin{minipage}{0.5\textwidth}
 % s3_2.rkt

+ 3 - 3
defs.tex

@@ -67,13 +67,13 @@
 \newcommand{\STACKLOC}[1]{(\key{stack}\;#1)}
 \newcommand{\BININSTR}[3]{\key{(Instr}\;#1\;\key{(list}\;#2\;#3\key{))}}
 \newcommand{\UNIINSTR}[2]{\key{(Instr}\;#1\;\key{(list}\;#2\key{))}}
-\newcommand{\CALLQ}[1]{\key{(Callq}~#1\key{)}}
-\newcommand{\INDCALLQ}[1]{\key{(IndirectCallq}~#1\key{)}}
+\newcommand{\CALLQ}[2]{\key{(Callq}~#1~#2\key{)}}
+\newcommand{\INDCALLQ}[2]{\key{(IndirectCallq}~#1~#2\key{)}}
 \newcommand{\RETQ}{\key{(Retq)}}
 \newcommand{\PUSHQ}[1]{\key{(Pushq}~#1\key{)}}
 \newcommand{\POPQ}[1]{\key{(Popq}~#1\key{)}}
 \newcommand{\JMP}[1]{\key{(Jmp}~#1\key{)}}
-\newcommand{\TAILJMP}[1]{\key{(TailJmp}~#1\key{)}}
+\newcommand{\TAILJMP}[2]{\key{(TailJmp}~#1~#2\key{)}}
 \newcommand{\JMPIF}[2]{\key{(JmpIf}~#1~#2\key{)}}