register saving in stack before function call

Help
zogo
2011-12-22
2013-03-12
  • zogo

    zogo - 2011-12-22

    Hi all,

    I'm just starting with SDCC.
    Today I found that before a call to a function which is receiving a single 8bit parameter, SDCC is pushing the accumulator in a weird way

    ;main.c:5: cls(0);
    ld a,#0x00
    push af
    inc sp
    call _cls
    inc sp

    void cls(uint8_t val) __naked
    {
        val;// to avoid warning: unreferenced function argument
        __asm
        ld bc,#0x0300   ; length
        ld hl,#NAMTBL   ; Write address
        jp FILVRM
        __endasm;

    }

    I am using the latest version 3.1.0 and I'm compiling using sdcc -mz80 -std-sdcc99 -all-callee-saves -nooverlay -c main.c.

    Can someone explain this behavior?

    Thanks a lot.

    Best regards,
    zogo

     
  • Maarten Brock

    Maarten Brock - 2011-12-28

    What is so weird about it? It just tries to save stack space at the cost of code space.

    push af     ;push acc and the flags
    inc  sp     ;drop the flags
    call _cls   ;make the call
    inc  sp     ;drop the parameter
    
     
  • zogo

    zogo - 2011-12-29

    Hi,

    Thanks for your reply. I would have expected that if I use the -all-callee-saves, no code should be generated to push/pop parameters in the stack. Actually if I use the 8051 as target the code generated is behaving correctly

    ; main.c:5: cls(0);
    ; genCall
    mov dpl,#0x00
    lcall _cls
    ; main.c:7: while(1);

     
  • zogo

    zogo - 2011-12-31

    Finally I have managed it introducing a new peephole rule
    replace
    {
    ld a,%1
    push af
    inc sp
    call %2
    inc sp
    }
    by
    {
        ; peephole custom rule, register argument passing
        ld  a,%1
    call %2
    }

    which generates the following code

    ;main.c:5: cls(0);
    ; genIpush
    ; genCall
    ; peephole custom rule, register argument passing
    ld  a,#0x00
    call _cls

    But this should not be the way.

    Regards

     
  • Maarten Brock

    Maarten Brock - 2011-12-31

    The difference is that mcs51 always tries to pass the first argument in registers and z80 always passes all parameters on stack. Using -all-callee-saves has nothing to do with passing arguments but is about who saves the registers, the caller or the callee.

    Your peephole rule may pass the value in the accumulator but in other cases it may not. But the callee has no way of finding out how it was called. Furthermore, unless you write the callee in assembler it will not expect the value in A and still read from stack.

     
  • zogo

    zogo - 2012-01-01

    Hi,

    Thanks again for your comments.

    But if you look to my first post, you will find in bold letters which I think should not be generated in the case the -all-callee-saves. As you said if I use the the switch it should be the responsability of the callee to save the registers.

    I'm fully aware of the problems/restrictions associated with the peephole rule, but at the moment is the only way to implement something similar to the FASTCALL in z88dk.

    BTW: Why not making the z80 port behaving like the 8051? The z80 has plently of registers that should be used for register passing. If not the z80 behavior should be better documented.

    Best regards and Happy new year.

     
  • Maarten Brock

    Maarten Brock - 2012-01-01

    You mistake the PUSH AF for a register saving action which it is not. It is an action of passing function arguments. If it were saving A then A would also be POPped. I don't think the accumulator or the flags would ever be saved across a function call. Only BC, DE, HL, IX and IY can.

    I don't know why the z80 port implementation was chosen differently from the mcs51 port. But it is questionable if passing parameters in registers is really any better than passing them on the stack. It could require a lot of intermediate moves to get the data into the right registers. Or it could obstruct the use of certain instructions like JP (HL) for calling function pointers.

    The mcs51 only passes the first parameter in registers and uses registers that do not hold any (temporary) variable data (DPTR, B and A). And even then it sometimes requires juggling with the data. And it also cannot use JMP @A+DPTR for function pointers with parameters.

    I hope this clears things up a bit. For more details about the z80 port it's main maintainer would have to chime in, as my focus is mostly on mcs51.

    Happy New Year to you too, and may you enjoy using SDCC.
    Maarten

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks