CPSC 411 - Lab Notes - 04-09 (Function Entry/Exit)

This is it, count the house, douse the lights, we are at the final stage: Code Generation.

The calling stack for a function.

Whenever we call a function, we need to set up various elements on the stack. In this lab, we are assuming our function stack looks like this:

Picture of stack

Caller responsibilities.

The caller has a few things they must do. This code would be part of the gencode for iFunction and iFunctionOrOperationApplication. Note that all code generation methods are passed the current function level. The code needed includes:

Callee responsibilities.

This can be split into two main portions, all of which are generated by the gencode method of iFunctionBody.

Entrance Code.

First, we calculate the deallocation pointer.

dealloc =  -(self.storage  + self.number_of_function_arguments+2)
print "%s: LOAD_I %d"%(self.function_code_start_label,dealloc)

Next, we need to set up the frame pointer as in the above diagram.

print "LOAD_R %sp"
print "STORE_R %fp"

Next allocate storage for local variables and generate the code to create the array storage.

print "ALLOC %d"%(self.storage)
for arr in self.array_info_list:
    arr.codegen(function_level)

Generate the code for the statements in the function.

for s in self.statement_list:
    s.codegen(function_level)

Exit code.

We are now ready to start our return cycle. Our first task, is to take the return value, which is on the top of the stack and place it in the first arguments position. This will be the void cell in the stack when there are no arguments.

print "LOAD_R %fp"
print "STORE_O %d"%(-(self.number_of_function_arguments+4) )  # return value

Next, we save back the dynamic link, which was the previous frame pointer to two positions above the return value. This may overwrite the static pointer in cases of 0 arguments, and in the case of 1 argument, there is actually no movement. Note that at this stage, you do not know how many arguments the function has.

print "LOAD_R %fp" 
print "LOAD_O -3"  # dyn link
print "LOAD_R %fp"
print "STORE_O %d"%(-(self.number_of_function_arguments+2) )

Similarly, we move the code ptr to just above the return value.

print "LOAD_R %fp"
print "LOAD_O -1"  # code ptr
print "LOAD_R %fp"
print "STORE_O %d"%(-(self.number_of_function_arguments+3) )

Next, load the deallocation counter and deallocate all the space.

print "LOAD_R %fp"
print "LOAD_O 0" #dealloc counter
print "ALLOC_S"

Next, restore the old frame pointer (previously put at this position, which after the deallocation, is the TOS) and jump back to the code

print "STORE_R %fp"  
print "JUMP_S"

Finally, generate code for all the functions declared locally in this function.

for f in self.function_body_list:
    f.codegen(function_level+1)
Last modified by Brett Giles

Last modified: Wed Apr 16 08:09:57 MDT 2003 Valid XHTML 1.0!