[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [f-cpu] calling conventions

On Thu, 6 Jun 2002 10:56:36 +0200, Christophe wrote:
>I see a difficulty : printf and scanf and likes use varargs, that is
>which is pushed in stack and accessible via a pointer :
>Here an example such you can find for PC :
>va_start (fmt,arg) --> arg = (void *)((typeof(fmt))+1);
>va_arg(arg,type) --> *((type *)arg)++;

The first thing I would say is : this problems is C specific...
but I must admit that C is the most used language so...

How can we handle this ? I don't see any solution. If we use a stack
for parameters passing we lost the advantage of big number of
registers. If we use the register we can't do some specific thing of
some language. And if we mix the two like in manual we must duplicate
all parameters and this looks very ugly.

But if va_start was implemented as a macro I think it was possible for
this macro to store all register in memory and use this mem space
after for each va_arg call and free it in va_end.
This system slow down the va_arg handling but keep speed for all other
call, and most of function call doesn't use va_arg.

>Let us be precise :) :
>- caller side : it DOES know the number of parameters so it can tell
>to the
>callee via a dedicated register. ==> COMPILE-TIME.
>- callee side : it DOESN'T know the number of parameters but it can
>get it if
>the caller tells this number to it. ==> RUN-TIME.
>Now, is knowing this number necessary for callee ? well, it depends
>on what the
>callee really needs.

It's why I have put the number of arg in a function call not if we
have more than 13 parameters.

>> > In all the cases the register r1 is used (by the number of
>>parameters), it
>> > 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
>> > be able to possibly make checks.
>> You can always store the result in r1, whether it's the first
>> or the number of arguments. Since you usually do so at the *end*
>>of a
>> function, it makes no difference.
>Advantage :
>r1:int addi (r1:int a,r2:int b) {
>  return a + b;
>instead of :
>r1:int addi (r2:int a,r3:int b) {
>  return a + b;
>will give us :
>r1 += r2;
>instead of :
>r1 = r2 + r3;
>and save r3 for temporary register.

Bad example, you never make function like this is ridiculous, you
spent a lot of time in call of function so you don't see the other
And with a more real example the econmics was not a real advantage
because you generaly need number of arg only in start or function so
you can use his register for temp var, like r3 in your example.

>Another advantage :
>struct { r1:int error; r2:struct open_file *file; } file_open
>You can have not only one register as result but several registers
>this way !

So this is a different calling convention that allow multiple return

>> > In the case of more than 13 parameters I don't know if it is
>>useful to put
>> > the parameters in the list pointed by r15. Indeed to have all
>> > 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
>> > registers.
>> You're right again (and the manual is wrong wrt. this point).
>See above
>> r0      = always zero
>> r1      = function return value, and also
>> r1-r14  = function arguments (call-clobbered)
>> r15     = pointer to additional function arguments
>> 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
>> 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
>> *must not* expect them to be unchanged across function calls (but
>> save/restore them on entry/exit and use them like the callee-saved
>> registers r32-r47 if it doesn't need the global values).
>> a function *may* use r1-r15 as temporary registers if there aren't
>> many arguments (or it doesn't need them).
>I don't see the purpose to have so many global registers (shared by
>functions). What can really be shareable between all functions ?
>very few
>indeed... unless it should be for kernel but even for such a thing
>it is a very
>bad idea because any applications might access or modify them.
>There is another point else which I would enlight : what about the
>ability to
>use a pair of registers to have 128 bit when 64 bits is default ?
>for such opcodes which use or return  a pair of register (Rn,Rn^1) ?
>not very
>good if the first parameter or return register starts from r1.
>Worse, what can
>happen if we use an OPCODE which uses or computes a pair of register
>especially when Rn == R1 ? Rn^1 would be R0, but R0 is hardwired to
>0 !

You can use it for global variable sharing or for temp reg. But if you
use it as temp reg you must save it before and restore it after use.

Thomas Lavergne                       "Le vrai rÍveur est celui qui
                                       de l'impossible."  (Elsa

d-12@laposte.net    ICQ:#137121910

To unsubscribe, send an e-mail to majordomo@seul.org with
unsubscribe f-cpu       in the body. http://f-cpu.seul.org/