• Welcome to Valhalla Legends Archive.
 

Does visual c++ 2k3's inline asm support this?

Started by warz, May 01, 2006, 10:25 AM

Previous topic - Next topic

Skywing

Quote from: Kp on May 02, 2006, 09:27 PM
Brood War uses _fastcall, which is rather inefficient about register usage.  It'd be much better to do it the gcc way, which is: eax, edx, ecx.

It's also worth noting that in many places, __fastcall and register calling conventions for x86 are worse than just stack calling conventions.

In most non-leaf functions you will end up having to spill parameter values to the stack to preserve them across subsequent function values anyway (because eax/ecx/edx are volatile for most x86 calling conventions).  So, you don't really gain anything in the common case of a non-leaf function that uses its parameters across function calls.

This is why if you look at highly optimized x86 code (like, say, ntoskrnl) then you'll find that mostly you *don't* use register callling conventions except for leaf functions or very simple functions.

For better designed architectures and calling conventions (like x64), however, register parameter passing is a much better idea.

Kp

True.  Just to give some cases where _fastcall is useful:

C++ member functions which make extensive use of member variables often benefit from _thiscall (which is a variant of _fastcall) by pushing a stable register to the stack and keeping this in the stable register for the life of the function.  Procedural code which followed the same concept (having 1 or 2 high importance objects that're referenced often) would also benefit from _fastcall.

Redirection functions, such as the one below, also benefit from _fastcall.

int _fastcall foo(int x, int y)
{
    return bar(x, y, 3);
}


My original comment was mainly about the silliness of the number and order of registers used in _fastcall.  Since ecx is used as the counting register for repeatable instructions, it's best to allocate it last among _fastcall registers.  By doing so, 1 and 2 argument register-called functions keep ecx clear for immediate use in loops.  Incidentally, gcc allows you to specify anywhere from 0 to 3 arguments to be passed in registers.  If you expect the compiler will want immediate use of ecx, you could opt to pass only two arguments in registers (even if you had many more arguments), so that the called function would not need to spill ecx to the stack.

Aside from spilling concerns, there's no reason not to use eax as an additional argument register.  It's unstable anyway, so functions that benefit from register-call will do better having eax available.  If they need many arguments quickly, consuming eax reduces the number of stack references required.  If they only need to pass 2 arguments quickly, eax can be used in preference to ecx, thereby avoiding consuming the counting register.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Arta

Just FYI: If you use a library like libdisasm, disassembling the instructions to determine their length would become pretty easy, as would making appropriate repairs. Might make your program a little more bulky though -- uses lots of big tables in memory to decode instructions.