Additional example of function call, parameter passing

This is an example of function call using  RZ language as a source language.
x is local to sq(), a is local to main()

sq(x){ return x * x; }

main(){
  a = sq(2);
  print(a);
}

This is the output from the RZ compiler

.s
 rz 0
 retv 28
 bp 29
 rads 30
 sp 31
 print 1
 printch 2
.a 0
.c
   ld sp #1000 ;;  sp
   ld bp #3000 ;;  bp
   jal  rads label_18
   trap  stop rz

   ;;  Func sq 1 0
:label_5
   add  bp bp #2
   ;; -- save regs
   st   @1 sp r1
   st   @2 sp r2
   add  sp sp #2

   ld   r1 @-1 bp ;; x
   ld   r2 @-1 bp
   mul  r1 r1 r2
   or   retv r1 rz

   sub  bp bp #2
   ;; -- restore regs
   ld   r1 @-1 sp
   ld   r2 @0 sp
   sub  sp sp #2
   jr   rads

   ;; -- Func main 0 1
:label_18
   add  bp bp #2
   st   @0 bp rads
   ;; ---- save regs
   st   @1 sp r1
   add  sp sp #1

   ld   r1 #2
   st   @1 bp r1
   jal  rads label_5
   or   r1 retv rz
   st   @-1 bp r1 ;; a

   ld   r1 @-1 bp
   trap print r1

   ld   rads @0 bp
   sub  bp bp #2
   ;; -- restore regs
   ld   r1 @0 sp
   sub  sp sp #1
   jr   rads

.e

Here is the explanation what the code sequence does:
At the function sq(), it starts by creating its own activation record:

   add bp bp #2

the size of the activation record of sq() is 2 words. One word stores return-address, the other word is the local variable x.  This function uses two registers: r1, r2, so they are saved in the stack using this sequence:

   st   @1 sp r1
   st   @2 sp r2
   add  sp sp #2

A stack is a data structure, it is accessed by Last-In-First-Out order.  It is used as a temporary storage in which one doesn't have to specify the actual location, a value can be saved by "pushing" it to a stack, and a value can be retrieved by "poping" it from a stack.

When the calculation in a function is completed, a return-value is stored in a register, specially assigned for this purpose, r28 in this example.

   ld   r1 @-1 bp ;; x
   ld   r2 @-1 bp
   mul  r1 r1 r2
   or   retv r1 rz

The above sequence did x * x and the result is in the register "retv" which is r28.

To return from a function call, the activation record is deleted, registers are restored from a stack and the return-address is restored then jump back to the caller using "jr rads".  In this example, the return-address in "rads" has not been altered therefore there is no need to save and restore it.

   sub  bp bp #2
   ;; -- restore regs
   ld   r1 @-1 sp
   ld   r2 @0 sp
   sub  sp sp #2
   jr   rads

At the main() function, the code starts similar to sq() (all functions behave in similar ways), by creating its own activation record.  The call to sq() passes a value (x) to it.  In this case, the value is a constant 2.  This value is written into the "future" activation record (which is the AR of sq()) as its first local variable (x) using the offset +1.  Then the call is performed by "jal" , the link register is "rads", r30 in this example.

   ld   r1 #2
   st   @1 bp r1
   jal  rads label_5

When the call is returned, the return value is in "retv".  At the termination of main(), the control is transferred back to its caller, the return-address is restored from the current AR, the current AR is deleted, registers are restored and jump back to the caller.

   ld   rads @0 bp
   sub  bp bp #2
   ;; -- restore regs
   ld   r1 @0 sp
   sub  sp sp #1
   jr   rads

The first part of the program is the initialisation of the stack pointer and base pointer and then call to main().

   ld sp #1000 ;;  sp
   ld bp #3000 ;;  bp
   jal  rads label_18
   trap  stop rz

the end.

last update 2 July 2003