optimization - z88dk/z88dk GitHub Wiki

Optimization hints

(see also https://github.com/z88dk/z88dk/wiki/WritingOptimalCode)

  • Use the extra optimization flag

    zcc -O3 .... program.c

  • When possible use global variables

    Access to local variables is slightly slower and the generated code gets slightly bigger.

  • Use the same data type where possible

    Limit the use of the 'char' datatypes. The type conversion adds extra code, expecially when unsigned and unsigned datatypes are mixed.

  • Do not reinvent the wheel

    The z88dk function libraries are mostly written in assembly code; this helps saving a lot of memory and execution time; avoid using an equivalent C implementation of the existing functions, if any.

  • Split your libraries in modules

    The z80asm tool is able to link in code portions incrementally, adding them only when they are really used, no matter if they were invoked already by the "header file" declarations or by the assembly code equivalents.

  • Use the _ FASTCALL _ calling mode in functions needing a single parameter

    Most of the z88dk library is based on it to save memory and execution time. It could be worth to use the same technique in your projects.

  • Use the _ CALLEE _ calling mode if possible

    Most of the z88dk library is usese the 'FASTCALL' or 'CALLEE' modes to save memory and execution time. This is a method for advanced users, though.

    -- Calling methods as described by Alvin in the forum pages --

    To first approximation, the best way to get the best performance out of a C compiler for a small cpu is to make sure the libraries are hand coded in asm so that most cycles are spend in handcrafted code rather than compiler generated code. The place that generated code for the z80 is now is still far from optimally hand coded stuff. So a chunk of the effort in z88dk's dev has been in hand coded libraries.

    Further, the idea is to make sure z88dk is not just a C development environment but also an asm level dev environment. This means the preference is to have these hand coded libraries efficiently accessible from both C and asm.

    For this kind of thing to be accessible from sdcc there has to be a convention for calling asm routines and passing parameters to them efficiently.

    Right now in z88dk there are three calling conventions:

      1. the smallc one with the left to right pushing of params on stack and the caller expected to clean
         up the stack after the function returns.  this is z88dk's equivalent of the right to left convention
         in sdcc.
         
         An example bit of generated code:
         
           extern int test(int a, b);
         
           ...
         
           ld hl,(_aloc)  ; push params
           push hl
           ld hl,(_bloc)
           push hl
           call _test
           pop bc    ; clean up stack
           pop bc
         
         
     2. fastcall where a single parameter is passed by register in (DE)HL.  this is meant for asm libraries or
        user supplied asm.
         
        An example bit of code generated by the caller might look like this:
         
           extern int __FASTCALL__ test(int d);
         
           ...
         
           ld hl,(paramlocation)
           call _test
         
         
     3. callee where the target function is expected to clean up the stack.  this is also meant for asm libraries
        or user supplied asm.  asm functions pop params off the stack as they read them, effectively cleaning up
        the stack.  this can lead to savings of hundreds of bytes in compiled programs since the compiler doesn't
        have to generate stack cleanup code each time the function is called.
         
        Example:
         
         
           extern int __CALLEE__ test(int a, int b);
         
           ...
         
           ld hl,(aloc)   ; push params
           push hl
           ld hl,(bloc)
           push hl
           call _test  ; stack cleanup performed at target function
    

    Three different linkage conventions can mess with calls through function pointers unless the compiler can determine what the linkage is. z88dk is not strongly enough typed to do this.

    eg, you can do this:

         void *f;
         f = strcpy;
         (f)(d, s);
    

    No way can the compiler know if strcpy is called CALLEE or C convention. So in z88dk, now, all calls through function pointers are done with C linkage and every CALLEE function has a second entry point associated with it using C linkage. This second entry point does not get linked into the binary unless the program actually needs it. Some cpp macro magic makes sure function pointer assignments like "f = strcpy" get the C linkage stub whereas stuff like "strcpy(d,s)" gets the CALLEE linkage.

  • Remove unused functionalities

https://github.com/z88dk/z88dk/wiki/Platform---Embedded#selected-command-line-options

https://github.com/z88dk/z88dk/wiki/Platform---Embedded#printf-and-scanf-configuration