возвращая double в плавающем стеке, используя __asm ​​в Visual Studio - PullRequest
1 голос
/ 28 января 2012

Я использую 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?

Ответы [ 2 ]

2 голосов
/ 28 января 2012

На самом деле, ответ на мой вопрос заключается в том, что я ошибся в одном из высказываний вопроса выше:

double f(double x)
{
    __asm{ ...body code... }
}

без какого-либо оператора возврата, с операторами __asm ​​в теле, прекрасно компилируется, без каких-либо ошибок или предупреждений. Компилятор предполагает (правильно), что я организовал для возвращаемых значений, которые будут переданы / возвращены соответственно. Компилятор правильно генерирует коды входа и выхода и рад предоставить все остальное мне. Пойди разберись - почему я думал, что проверил это и обнаружил ошибки компиляции? Вздох. Извините, что беспокою всех.

0 голосов
/ 28 января 2012

Вы можете использовать только голые функции, однако они не требуют оператора возврата C и не требуют создания фреймов стека.однако, если у вас нет действительно веской причины использовать asm, ваш способ лучше делать это на C по многим причинам, главным образом, с переносимостью, а другой - с целью оптимизации, например, SIMD.

...