I am using MS Visual Studio (2005, but that should not be important). I have a function whose body is implemented (necessarily) in inline assembly:
double f(double x)
{
__asm{ ...body code... }
}
The assembly code finishes with the result to be returned contained in ST0. The calling convention being used is __cdecl, so the convention is that a return double value is returned in ST0. Thus, after the __asm{...body code...} code is completed, the function is ready to have its returning stack-cleanup code run and ret. However, the code above will not compile, of course, because there is no "return dblVal;" statement. It could be corrected by changing the code to:
double f(double x)
{
double dRet;
__asm{ ...body code... }
__asm{ fst dRet }
return dRet;
}
but this has two disadvantages: (1) the store to dRet is immediately followed by fld dRet, which is a complete waste and unnecessary (and this is being used innumerable times in a monte-carlo routine, so every cycle counts) (2) more importantly, the value in ST0 has been carefully computed in the body to 64-bit-mantissa accuracy, which I need to preserve, and the fst followed by fld completely kills this.
How can I tell the VisualStudio compiler that the double to be returned is already in ST0? I could write the exit code explicitly:
double f(double x)
{
__asm{ ...body code... }
__asm{ __asm leave
__asm ret
}
return 0.0; //dummy code that is never executed, to make the compiler happy
}
but then one has to know the entry code that that the compiler generates (and in fact, the exit code above is wrong). So we could take this further, and write both the entry code and the exit code:
__declspec ( naked ) double f(double x)
{
__asm{ ...entry code...}
__asm{ ...body code... }
__asm{ ...exit code... }
return 0.0; //dummy code that is never executed, to make the compiler happy
}
but that is all VERY ugly. So, how do I get the compiler to look after the entry code and exit code, and tell it that the return value is already in ST0?
Actually, the answer to my question is that I was wrong about one thing in the statements of the question above:
double f(double x)
{
__asm{ ...body code... }
}
without any return statement, with the __asm statements in the body, compiles just fine, without any errors or warnings. The compiler assumes (correctly) that I have arranged for the return values to be passed/returned appropriately. The compiler correctly generates the entry and exit codes and is happy leaving the rest to me. Go figure - why did I think I had tested that and found compile errors? Sigh. Sorry for bothering everyone.