40 2 Imperative Programming Languages
2.9.3 Function Call and Return
Let us discuss the two crucial problems with the implementation of C functions, the
call and, thus, starting the execution of a function and the return, that is, exiting after
having processed a function’s body.
First we examine the call of a function. Let f be the currently active function. Its
stack frame is at the top of the stack. Now assume that function f calls a function g.
An instruction sequence must be generated for the call of g that processes the call of
g and leaves the return value on top of the stack. Note that this instruction sequence
computes an R-value(as long as the function does not return void). In particular, this
return value has no (sensible) L-value. This means that according to our translation
schemes the return value cannot be directly accessed by a selector. One solution to
this problem is to apply a program transformation before code generation that places
the return values of all problematic function calls in auxiliary local variables. As an
example, the assignment x
← f (y + 2).a; is transformed into the block:
{struct t tmp; tmp ← f (y + 2); x ← tmp.a; }
for a new variable tmp, where t is the return value of function f .
The following sequence of actions must be executed for starting the execution of
the function g:
1. The valuesoftheactualparametersmustbecomputedandpushedontothestack.
2. The old values of registers EP and FP must be pushed onto the stack.
3. The start address of function g must be computed.
4. The return address must be computed and recorded in the corresponding organi-
zational cell.
5. Register FP must be made to point to the top of the new stack frame.
6. Control must proceed to the start address of g.
7. Register EP for the new call must be set to the current value of g.
8. Space must be reserved on the stack for the local variables of g.
Then the sequence of instructions for the body of function g can be executed. When
designing translation schemes, we must distributethe listed actions among the caller
f and the callee g. Such a distribution must take the respective knowledge into ac-
count. It is, for example, only the caller f that can provide the values of the actual
parameters, while only function g knows the space requirement for its local vari-
ables. In our list, the borderline between caller code and callee code lies between
points (6) and (7). For saving the registers EP and FP in point (2), we introduce the
instruction mark (Fig. 2.26). This instruction pushes the contents of both registers
consecutively onto the stack. For setting the new FP, saving the return address, and
jumping to the code of the callee in points (6), (4) and (5), we introduce the instruc-
tion call (Fig. 2.27). The instruction call is the last instruction of the call sequence
of g in the caller f . When executing this instruction, the PC register corresponds
exactly to the return address! This means that the actions (4) and (5) are jointly im-
plemented by swapping the contents of the topmost stack cell with the contents of
register PS.