In Visual Studio 2013 a new calling convention _vectorcall
exists. It is intended for usage with SSE data types that can be passed in SSE registers.
You can specify the calling convention of a member functions like so.
struct Vector{//a 16 byte aligned type
_m128i _vectorcall operator *(Vector a);
};
This works, it compiles, and the type can be passed by value despite having 16 alignment requirements.
On the other hand if I try to attach it to any constructors (which seems perfectly logical), it fails.
struct Vector
_vectorcall Vector(SomeOtherTypeWith16Alignment a);
};
The compiler spits out the warning message (I have warnings as errors):
warning C4166: illegal calling convention for constructor/destructor.
Forcing me to change the code to this:
struct Vector{
Vector(SomeOtherTypeWith16Alignment a); //fails to compile
};
Which also fails to compile because now SomeOtherTypeWith16Alignment
can't be passed by value since _vectorcall
isn't enabled on the constructor.
So I am forced to change it to this.
struct Vector{
Vector(const SomeOtherTypeWith16Alignment& a);
};
Which compiles. But it is no longer using _vectorcall
and likely won't pass the data in SSE registers as I'd prefer...
So basically, why the hell can't I specify the calling convention used by constructors?
This may be Visual C++ specific (_vectorcall
certainly is). I have not tried this on other compilers--
Calling conventions specify how arguments are passed to a function, how return values are passed back out of a function, how the function is called, and how the function manages the stack and its stack frame. In short, the calling convention specifies how a function call in C or C++ is converted into assembly language.
__cdecl is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code.
The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl . Functions that use this calling convention require a function prototype. The __stdcall modifier is Microsoft-specific.
In the GCC/x86 C calling convention, the first thing any function that accepts formal arguments should do is push the value of EBP (the frame base pointer of the calling function), then copy the value of ESP to EBP.
This is not so much an answer, but more of a collection of observations about this situation. This is indeed an intriguing question because there really seems to be something (I don't know what) that makes constructors (and destructors) fundamentally incompatible with calling conventions.
First of all, don't look for an answer in the C++ standard, because the standard does not care about calling conventions, in fact, the only mention of it in the standard is as an example of something that is out of the scope of that document (i.e., "implementation-defined"). So, the standard does not "forbid" the possibility of specifying or using different calling conventions for the constructors (or destructor).
From a little research and testing, it appears that the situation is as follows for the different main compilers (as best I could gather):
/Gz
for instance) does not affect non-static member functions such as constructors. In other words, there is no way to change the calling convention on constructors, whatever you try to specify, it will be ignored.In other words, all compilers seem to be very stubborn about no allowing any other kind of calling convention on the constructors besides the default one. And the core question is: Why?
Here are a few thoughts on that (speculations).
First off, traditionally, calling conventions have been more about binary compatibility than about performance optimization, i.e., you specify calling conventions when linking with and calling functions from different languages or compilers (e.g., traditionally between C, C++, Pascal and Fortran). And so, this could explain why certain C++ features are excluded from that. For instance, if you are creating an interface for a C++ library (maybe calling it from a different language), then you either have to fall-back on a C API, meaning no classes, no constructors and no member functions, or you have to expose a C++ API on a platform with a standard ABI (e.g, Itanium) which fixes the calling convention. That makes specifying a calling convention for constructors completely useless from a binary compatibility point of view. That may explain why this has been "ignored" (not implemented by the compilers) as a low priority feature.
Another issue that might be involved here, for the constructors specifically, is that if you look for example at the Itanium ABI specification you can see that constructor calls are quite special. In particular, virtual inheritance requires a temporary virtual table pointer to be passed along. This may explain why it is quite a bit more difficult for compiler implementers to provide a variant of each possible calling convention for constructors. In other words, it's not as simple as just adding a "this" pointer as the first "hidden" argument and then applying a standard C calling convention (as it does with normal non-static member functions). I don't think that it would be impossible to implement those alternative calling conventions for constructors, but it would be extra trouble that compiler-vendors simply have not got around to implementing (yet). Also, given the calls to base class constructors, it may also create problems with diagnostics (verifying that base-class constructor calling conventions are compatible with the derived-class calling convention). So, this might simply be a case of "too much trouble; didn't do it". And the fact that the standard allows it, but none of the compilers do it is a strong indicator that this may be the case.
Beyond that, I cannot offer any definitive answer as to why this would be somehow impossible to achieve. The only way you could get a definitive answer is if you find a person who is directly involved in implementing one of those compilers and who has looked into trying to support different calling conventions on constructors. And note that it's possible that such a person doesn't even exist (your best bet might be to check with the LLVM/Clang developer community to see if anyone has looked into this problem).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With