[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [f-cpu] calling conventions
On Thu, Jun 06, 2002 at 12:15:00AM +0200, Thomas Lavergne wrote:
[...]
> 15 registers on the whole right for the passages of the parameters? 13 for the
> donnee 1 for the stack of parameters and 1 for the number of parameters.
Right, although I had something different in mind when I proposed the
calling conventions: r1-r13 should hold the first 13 parameters,
r14/r15 length and pointer of *the rest of them*, not all of them as
the manual states.
> After read this section I have made a small script for scann all my source file
> and see the average number of parameter used and I obtained approximately 3
> parameters (a little more or a little less according to the languages) what I
> want to say that there is ten unused register in each functions.
As I mentioned here before, a function is free to use the unused
parameter registers as local (unsaved) temporary registers.
> Moreover there is a stack of register for each calls, which want to say that
> for calling a function we need 3 stages:
> 1/ put the 13 parameters in the registers r1-r13
> 2/ push all the registers in r14 and put their number in r15
Not all of them - just the rest. Since there are few function calls
with 14 or more parameters, this is quite a rare case. There are some
examples, however - like long calls to printf()/scanf().
> 3/ make a jmp on the function (address of return in r60)
> At my opinion the 2nd stages is very ugly, need to store all the parameters in
> memory will impose many accesses in memory which are penalisant, or which will
> be found to cache memory and replace more useful donnee in it.
You're right, that would be pointless.
> What I propose has the place : first an observation, as well the caller
> function as the function to call know at the compile time the number of
> parameters.
Not true. In some languages, there are functions taking a variable
number of arguments - which is of course unknown when the function is
compiled.
> That is to say N the number of parameters:
> * if n inferior to 13
> r1 : number of parameters
> r2-r(n+1) : parameters
> r(n+2)-r31 : temporari registers
That was in fact my proposal.
> * Si n est superieur a 13
> r1 : number of parameters
> r2-r14 : parameters
> r15 : pointer over the parameters list
> r16-r31 : temporari registers
Whether you put the first 13 args in r1-r13 or in r2-r14 doesn't make
much of a difference. The advantage of using r1-r13 is that functions
with fixed and variable argument lists remain call-compatible (which
they won't be if we follow your proposal).
> This has the advantage of optimizing the number of register to use according to
> the number of parameters, a function which uses 3 parameters will mobilize 4
> register for the parameters and will have 27 temporary registers. In the best
> cases, a function which does not have parameters, only one register is to
> mobilize and 30 others are available. In the worst cases, it is has to say
> more than 13 parameters, this calling convention is similar to the proposal of
> the handbook with only an inversion of register.
We could drop the `number of arguments' argument completely:
r1-r14 -> first 14 arguments
r15 -> pointer to additional arguments
In most languages there's no need to pass the *number* of arguments
(unless it's checked at runtime, e.g. in Lisp or Scheme - but those
languages need different calling conventions anyway). But if we have
to do so, r1 is a logical choice (that is, the function has a `hidden'
or `0th' argument).
> In all the cases the register r1 is used (by the number of parameters), it is
> thus available to store the value of return of the function. The number of
> parameters was present, same if it is known of the two functions, in order to
> be able to possibly make checks.
You can always store the result in r1, whether it's the first argument
or the number of arguments. Since you usually do so at the *end* of a
function, it makes no difference.
> In the case of more than 13 parameters I don't know if it is useful to put all
> the parameters in the list pointed by r15. Indeed to have all the parameters
> lists some in very practical, for the function such as [printf] in C or
> [format] in Pascal, but I am not sure time to gain in these function is a
> superior than time wasted to put in memory parameters which are already in the
> registers.
You're right again (and the manual is wrong wrt. this point).
> Otherwise, the registers r32 with r59 are register has to preserve and it is to
> the called to save them. It is a good thing because it save only those which
> it use. But how save does ? With my opinion there are 2 methods : use the SRB
> or a store, for the SRB I don't know if it is possible of chain about thirty
> call of function with as much [srb_save] ? For the second solution I think that
> it was interresting to have a register pointing on a memory area reserved for
> this save.
In conventional (C- or Pascal-style) languages, one of the `global'
registers (r63) serves as a `stack pointer' that can be used for explicit
register saves. *How* you save them (and how many you save) will depend
on the function's needs; therefore the compiler will have to choose an
appropriate method (explicit `load'/`store', `loadm'/`storem', ...)
BTW: The border between `caller-saved' and `global' registers was at
r48 in my proposal, not r60. I intentionally left some global registers
unassigned, for use by applications (and even the current assignments
for r60-r63 can be debated - e.g. if a language doesn't need stack or
frame pointers). That is, the assignment should be:
r0 = always zero
r1 = function return value, and also
r1-r14 = function arguments (call-clobbered)
r15 = pointer to additional function arguments (call-clobbered)
r16-r31 = temporary registers (call-clobbered)
r32-r47 = local registers (saved by callee)
r48-r63 = global registers (shared by all functions)
with the following assignments for C- and Pascal-style languages (but
not necessarily others):
r60 = function return address
r61 = global pointer
r62 = frame pointer
r63 = stack pointer
Note that r48-r63 are *not* callee-saved as the manual states. A function
*must not* expect them to be unchanged across function calls (but *may*
save/restore them on entry/exit and use them like the callee-saved
registers r32-r47 if it doesn't need the global values). Analogously,
a function *may* use r1-r15 as temporary registers if there aren't so
many arguments (or it doesn't need them).
--
Michael "Tired" Riepe <Michael.Riepe@stud.uni-hannover.de>
"All I wanna do is have a little fun before I die"
*************************************************************
To unsubscribe, send an e-mail to majordomo@seul.org with
unsubscribe f-cpu in the body. http://f-cpu.seul.org/