mfro wrote:I'm afraid the fastcall attribute is not implemented for m68k
Oh well, now we know. I don't rely on it so I wasn't sure - some of those attributes are sparsely supported on the various targets.
but also think - as you have already explained - it's not necessary anyway.
Short functions get properly inlined, for large functions the calling overhead is neglectable.
Not having the choice of different ABIs saves you a lot of headaches, though
Indeed all true. I was concerned at one point that m68k gcc passes all args as longwords regardless of size, but in fact it's just an alignment thing. It still uses word access for short args - the gaps are unused padding, at least on plain m68k (Maybe not so on 020+)
To simonsunnyboy... here are a few tips to help avoid the cost of arg passing. By tips I mean these methods work... but be aware that picking the right one at the right time will help you avoid making a large scale mess of your program. Optimization is always best done by forward planning, design and choice of solutions - anything not covered by that gets done last of all.
Some C tips:
1) Declaring a function 'static' tells the compiler the code can't be seen/used from outside that sourcefile and is therefore categorized as 'anything goes' for optimization purposes. The compiler *will* use that information and do radical things to the code. It's your #1 optimization hint for functions. It can make arg passing 'disappear'.
2) Not delcaring a function 'static' (the more common case) means the compiler has to treat it as a public export which can be seen and used from other sourcefiles. It therefore has to instance the code as a real function and use the standard arg passing convention (stack) to reach it. This tends to be implicit because such functions can't live in a header file (due to symbol collisions they would cause), so chances of inlining are limited anyway. But....
3) If you declare a function 'static' it will not 'collide' with other functions with the same name in other sourcefiles, since it's effectively private to the sourcefile. This means you can stick it in a header file and share it across a whole project, without getting duplicate symbol problems at linktime.
4) Declaring a function 'static inline' does the same as 'static', but more likely to encourage inlining, and discourage instancing (making the function 'real' and callable). This in turn means you can put complete functions in header files (sometimes called 'implementation' headers) which optimize/fuse into other code very well without any arg passing involved. Watch out because 'inline' keyword didn't exist in ANSI C and arrived later. If using an older dialect, it may exist as an extension instead e.g. __inline. It became official later on and with C++ (minus the underscores).
5) If you try to take the address of such a static/inline function (say, to make a function pointer out of it), this may not prevent it from inlining in other locations - but it will force it to be instanced in that sourcefile to produce a valid address. This means the code you call through your function pointer isn't the code that's being used when the function is called directly (even if they do the same job). While this is normally not a problem, it could get very confusing when taking into account (***) below.
Some C++ tips
6) You can fully define a function within a class, and it gets treated with inline semantics by default, with or without the keyword. It also doesn't cause symbol collisions because it's been defined as part of the class. You can therefore implement whole classes fully within header files and share them, and they are likely to inline in most circumstances (this is not necessarily appropriate, but it is nonetheless true).
7) Defining a function 'static' in a C++ class means it doesn't need any state from the class, and that's one less pointer needed when calling it. However you don't really want to design a class around static functions. It has specific purposes - just be aware it implicitly costs the same or less than a normal class method depending on the compiler.
C++ has awesome code generation/expansion capabilities via templates - a kind of 'super macro' language wrapped around/into C. It's hard to learn the depths of it, but the performance possible from meta-programs written in terms of templates is unbeatable because such programs can calculate a lot of stuff during compilation, leaving only the unknown, dynamic work to the runtime. The biggest downside is the awful spaghetti error messages which result from the simplest syntax foibles. But you do get used to it
(***) Be very, very careful with 'static inline' when using C++. You can also declare variables static, which means the variable is shared and persistent across any calls using it (effectively a local variable that behaves like a global variable). Using these within a 'static inline' function is usually disastrous, because it can easily create multiple (fused) instances of the function across the program, and therefore also the variable, each with its own state. Since you don't know how many instances of the inline function get created in the program, you can't tell how many copies of the variable there are either. Don't mix static vars with static funcs unless you really mean to, and probably don't mix them with static inline funcs, ever. Even if it seems like it should work - recommend avoid.
These tips were limited to optimizing how code is defined / instanced between modules and calling overhead. It's not meant to be an exhaustive list of optimizations - just things that affect argument passing.