Я использую MS Visual Studio (2005, но это не должно быть важно).У меня есть функция, тело которой реализовано (обязательно) во встроенной сборке:
double f(double x)
{
__asm{ ...body code... }
}
Код сборки заканчивается с возвращаемым результатом, содержащимся в ST0.Используется соглашение о вызовах __cdecl, поэтому соглашение состоит в том, что возвращаемое двойное значение возвращается в ST0.Таким образом, после завершения кода __asm {... body code ...} функция готова к запуску возвращаемого кода очистки стека и ret.Тем не менее, приведенный выше код не будет компилироваться, конечно, потому что нет «return dblVal;»заявление.Это можно исправить, изменив код на:
double f(double x)
{
double dRet;
__asm{ ...body code... }
__asm{ fst dRet }
return dRet;
}
, но у этого есть два недостатка: (1) сразу после сохранения в dRet следует fld dRet, который является полной тратой и ненужным (и этоиспользуется бесчисленное количество раз в подпрограмме Монте-Карло, поэтому каждый цикл имеет значение) (2) что еще более важно, значение в ST0 было тщательно вычислено в теле с точностью до 64-битной мантиссы, которую я должен сохранить, и fstзатем fld полностью убивает это.
Как я могу сказать компилятору VisualStudio, что возвращаемый двойной объект уже находится в ST0?Я мог бы написать код выхода в явном виде:
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
}
, но тогда нужно знать код входа, который генерирует компилятор (и на самом деле код выхода выше неверен).Таким образом, мы могли бы пойти дальше и написать код входа и код выхода:
__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
}
, но это ОЧЕНЬ ужасно.Итак, как мне заставить компилятор позаботиться о коде входа и коде выхода и сказать ему, что возвращаемое значение уже находится в ST0?