The compiler partitions the AVR general purpose registers into three sets.
The C compiler requires that R0 be zero when entering a C function. It can momentarily take non-zero values, but must be zero at the point you call a C function. The standard entry code that the C compiler lays down for an interrupt function sets R0 to zero by default.
The compiler uses the scratch registers to pass values to the called routine for all parameters of simple data type. If there are not enough scratch registers to hold all parameter data to be passed to the called routine, the excess data are passed on the stack.
Simple data types which require more than a single word of storage are passed in register pairs or register quads. The register requirement for the basic data types are:
Allocation of the scratch registers for function calls proceeds in a left-to-right fashion, starting with register R27 and progressing in reverse order to R2. The compiler tries to fit each parameter into the scratch registers and, if it can, allocates those registers to the incoming parameter. If the parameter requires more scratch registers than are free, it is noted and is passed on the stack. All parameters which are passed on the stack are pushed in reverse order.
The compiler uses the scratch registers to return values to the caller.
This section contains some examples of the calling convention in use.
void fun1(char u, char v);
Reading from left to right, the parameter u is passed in register R27 and v is passed in R26. The scratch registers R20 through R25 are not used to pass parameters and can be used in fun1 without needing to be preserved.
void fun1(char u, int v, char w);
The parameter u is passed in register R27. Because v requires two registers to hold its value it is passed in the register pair R26–R25 with R26 holding the high part of v and R24 the low part. The final parameter w is passed in R23.
void fun1(int u, long v, int w, int x);
The parameter u is passed in register pair R27–R26. Because v requires four registers to hold its value, it is passed in the register quad R25–R22 with R25 holding the high byte of v and R22 the low byte. Parameter w is passed in register pair R21–R20. As all scratch registers are now used, x is placed onto the stack.
void fun1(int u, long v, long w);
The parameter u is passed in register pair R27–R26. Because v requires four registers to hold its value it is passed in the register quad R25–R22. When considering w, there are only two free registers left for passing parameters, R21 and R20. The compiler cannot fit w into this register pair and therefore places the argument onto the stack—the compiler does not split the value into two and pass half in registers and half on the stack.
void fun1(int u, long v, long w, int x, int y);
The parameter u is passed in registers R27–R26. The parameter v is passed in the register quad R25–R22. When considering w, there are only two free parameter passing registers left, R21 and R20. The compiler cannot fit w into the register pair R21–R20 and therefore places the argument onto the stack. When considering x, the compiler sees that R21 and R20 are unused and so passes x in the register pair R21–R20. All parameter registers are used when considering y, so the argument is placed onto the stack. The parameters w and x are pushed onto the stack before the call and are pushed in reverse order, with y pushed before w.
This example shows two parameters, w and y, that are passed to the called routine on the stack, but they are separated by a parameter x that is passed in a register.