Re: [cc65] Own parameter call stack?

From: Ullrich von Bassewitz <uz1musoftware.de>
Date: 2009-09-01 15:57:28
On Tue, Sep 01, 2009 at 03:04:47PM +0200, Christian Krüger wrote:
> yes, but since the high byte handling takes additional code space, inlining
> is not very attractive now...

Have a look at this example:

    void foo (int, int);
    int main (void)
    {
        foo (3, 4);
    }

This compiles to:

        jsr     decsp4
        lda     #$03
        ldy     #$02
        sta     (sp),y
        iny
        lda     #$00
        sta     (sp),y
        tax
        lda     #$04
        ldy     #$00
        sta     (sp),y
        iny
        txa
        sta     (sp),y
        jsr     _foo

As you can see, the only thing where handling the high byte of the stack
pointer is necessary is in decsp4. Let's look at it:

.proc	decsp4
	lda	sp
	sec
	sbc	#4
	sta	sp
	bcc	@L1
	rts
@L1:	dec	sp+1
	rts
.endproc

Now, if you remove the high byte handling, all you gain are three cycles for
the bcc! Ok, decsp4 may be inlined more aggressively if it is smaller, giving
another 6+6 cycles for jsr/rts. But as can be easily seen from the above, this
is just a small precentage of the execution time when pushing the parameters.

Since you need different functions for parameters and variables, you will have
larger programs with this method. While decsp4 can be used for parameters, we
need another decvarsp4 or similar that reserves space on the parameter stack.

Yes, we can gain a few cycles by this method, but the drawback is big: Some
programs will compile into invalid code and the compiler cannot tell. Many
programs will get slightly larger instead of smaller. There must be two
different libraries written and maintained and the compiler must know about
both sorts of runtime functions. People will complain because they link
modules compiled for one mode with modules compiled for the other, and other
people will complain because they run into a parameter stack overflow which
overwrites memory and goes unnoticed.

> This is not allways possible. My solution for 'leaf'-functions is to transfer data to static parameters,
> but this is difficult to overhaul and error-prone (when it becomes a 'non-leaf-function')...

You can use a struct and pass a pointer to it. This is as fast as using the
stack and just one __fastcall__ parameter is passed:

    typedef struct Params Params;
    struct Params {
        unsigned    A;
        unsigned    B;
        unsigned    C;
    };

    extern void __fastcall__ FancyFunc (const Params*);

    int main (void)
    {
        Params P;
        P.A = 3;
        P.B = P.A + 5;
        P.C = 27;
        FancyFunc (&P);
        ...
    }

In the assembler module just do

    .struct Params
        pA      .word
        pB      .word
        pC      .word
    .endstruct

    .proc   _FancyFunc
        sta     ptr1
        stx     ptr1+1          ; Save pointer to P
        ldy     #Params::pC
        lda     (ptr1),y        ; Load low byte of Params::pC
        ...
    .endproc


Regards


        Uz


-- 
Ullrich von Bassewitz                                  uz@musoftware.de
----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo@musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.
Received on Tue Sep 1 15:59:27 2009

This archive was generated by hypermail 2.1.8 : 2009-09-01 15:59:30 CEST