In Windows, fastcall calling convention is implemented in the following way: * an argument that has integer type with size less-or-equal than 4 bytes is eligible for fastcall * the first argument that is eligible for fastcall is passed in ECX * the second argument that is eligible for fastcall is passed in EDX GCC implementes it badly, structures and 64-bit integer arguments are not correctly passed in registers but they incorrectly increase the register number in "function_arg_advance_32" and further arguments eligible for fastcall are not passed in registers. Example: struct s { int a; }; int __attribute__((fastcall,noinline)) f(struct s s, int a1, int a2) { printf("args: %d, %d, %d\n", a1, a2, s.a); return 0; } int main() { struct s s = { 3 }; f(s, 1, 2); return 0; } --- on Windows, s goes on the stack, a1 goes in ECX and a2 goes in EDX. --- in gcc, s goes on the stack (but it incorrectly increased a register number), a1 goes in EDX and a2 goes on the stack too because gcc runs out of fastcall registers.
"an argument that has integer type" should really be "an argument that has integer or pointer type" ... pointers are passed in registers too. Anything else isn't, I think.
Another inconsistency: struct { float f }; is returned in ST(0) in GCC and in EAX on Windows. struct { double f }; is returned in ST(0) in GCC and in EDX:EAX on Windows. See PR 41017 for more examples. Another one: On Windows, structure with zero size ( struct { int a[0]; }) is treated like having size 4 when passing arguments and treated like being returned in registers (well, really, there is nothing returned because the structure is empty, but it differs from GCC: GCC will pass dummy return place argument and Windows won't). Another one: struct { int a; int b[]; } is treated like having variable-size and allways returned by reference in GCC. In Windows b[] and b[0] seem to be equivalent and this is treated like having the size 4 and returned in EAX. I also quite didn't get the purpose of MS_AGGREGATE_RETURN --- it seems to be doing the same thing as -freg-struct-return in current gcc code. How are these two supposed to differ? But it could be used to differentiate this zero-sized-member thing.