zcc -O3 .... program.c
Access to local variables is slightly slower and the generated code
gets slightly bigger.
Limit the use of the 'char' datatypes.
The type conversion adds extra code, expecially when unsigned and
unsigned datatypes are mixed.
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.
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
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.
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
An example bit of generated code:
extern int test(int a, b);
ld hl,(_aloc) ; push params
pop bc ; clean up stack
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);
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.
extern int __CALLEE__ test(int a, int b);
ld hl,(aloc) ; push params
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:
f = strcpy;
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.