Преобразование встроенной функции x87 fsqrt на ассемблере из C++ в C для x86-64

Я рассматривал различные методы вычисления квадратного корня, в частности один (sqrt14 из здесь) привлек мое внимание, к сожалению, он был написан на C++ (он использует только ассемблер), мне сложно перевести его обратно на C - если это возможно.

double inline __declspec (naked) __fastcall sqrt14(double n)
{
    _asm fld qword ptr [esp+4]
    _asm fsqrt
    _asm ret 8
} 

Как видно здесь, вставка сборки в C++ отличается от C.

Я хотел спросить вас, возможно ли иметь эквивалент C, и если да, могу ли я попросить вас написать его? Если это полезно, моя архитектура 64-битная.

Я подозреваю, что объявление функции будет таким:

double inline __attribute__((fastcall, naked)) sqrt14(double n);

... но я недостаточно знаю об ассемблере, чтобы сделать все остальное...


person TheBigBadBoy    schedule 25.01.2021    source источник
comment
Большая часть кода в вопросе является расширением компилятора и не связана ни с C, ни с C++. FWIW в оригинале нет ничего специфичного для С++.   -  person Eugene Sh.    schedule 25.01.2021
comment
Ответ, на который вы ссылаетесь, дает разные ответы для gcc и Visual C++. Visual C++, несмотря на свое название, также является компилятором C, а gcc, несмотря на свое название, также является компилятором C++.   -  person molbdnilo    schedule 25.01.2021
comment
Что плохого в том, чтобы позвонить sqrt или sqrtf из math.h?   -  person fuz    schedule 25.01.2021
comment
Вы должны проверить вывод языка ассемблера из вашего компилятора (в режиме выпуска с высокой оптимизацией). Предоставленный вами язык ассемблера вызывает только функцию квадратного корня процессора с плавающей запятой. Это может происходить автоматически компилятором при высоких настройках оптимизации.   -  person Thomas Matthews    schedule 25.01.2021
comment
@fuz На самом деле мне нужно сделать симуляцию, а это занимает гораздо больше времени с обычными функциями sqrt и sqrtf. Например, он работает в 3 раза быстрее, используя быстрый обратный квадратный корень (из Quake III). Поэтому я искал другие чудо-функции, которые были либо быстрее, либо точнее — не теряя лишнего времени.   -  person TheBigBadBoy    schedule 26.01.2021
comment
Кроме того, я не понимаю одного (пожалуйста, объясните мне): почему за вопрос проголосовали? Я думал, что это по теме, потому что это конкретная проблема программирования, как сказано здесь: stackoverflow.com/help/on-topic Возможно, мой вопрос был недостаточно ясен?   -  person TheBigBadBoy    schedule 26.01.2021
comment
@TheBigBadBoy Для какой архитектуры и набора инструментов вы программируете?   -  person fuz    schedule 26.01.2021
comment
@fuz Я использую 64-битный компьютер с Intel i5-3210M, на Ubuntu с использованием gcc 9.3.0. Пока я программирую только на своем компьютере, но в будущем все может измениться...   -  person TheBigBadBoy    schedule 27.01.2021
comment
@TheBigBadBoy Рассмотрите возможность использования опции -fno-math-errno и функций стандартной библиотеки. Это заставит gcc генерировать соответствующие инструкции SSE для квадратных корней вместо библиотечных вызовов. Также не забудьте скомпилировать с включенной оптимизацией. Если вы зададите новый вопрос с более подробной информацией о конкретном коде, который вы пытаетесь оптимизировать, я смогу дать более конкретные ответы.   -  person fuz    schedule 27.01.2021
comment
@TheBigBadBoy Что касается рассматриваемого кода, вы можете заменить его на static inline double sqrt14(double x) { asm("fsqrt" : "+t"(x)); return (x); }. Однако обратите внимание, что это, вероятно, будет медленнее, чем вызов sqrt() из math.h.   -  person fuz    schedule 27.01.2021
comment
@fuz Спасибо за советы!   -  person TheBigBadBoy    schedule 27.01.2021


Ответы (1)


Приведенный вами пример очень специфичен для одного компилятора...

  • __declspec (naked) — это особенность реализации (нестандартная)
  • __fastcall — это функция, специфичная для реализации (нестандартная).

Даже в вашем исправленном примере:

  • __attribute__((fastcall, naked)) — это особенность реализации (нестандартная)

Даже включение ассемблера является особенностью реализации (нестандартной), т.е. каждый компилятор может делать это немного по-разному.

Таким образом, код примера подходит для компилятора и целевого процессора, но его нельзя переносить на другую цепочку инструментов или процессор.

person Andrew    schedule 25.01.2021
comment
Ах хорошо. Действительно, я предпочитаю мобильность программы, а не ее скорость. Спасибо за объяснение. - person TheBigBadBoy; 25.01.2021
comment
@TheBigBadBoy: современные компиляторы будут встраивать sqrt() как инструкцию SSE2 sqrtsd без каких-либо глупых накладных расходов на вызов функций или сохранения аргумента в памяти и перезагрузки с помощью устаревшей x87. Вы не теряете скорость, избавляясь от этого старого встроенного ассемблера, вы, вероятно, набираете скорость. Особенно, если вы используете gcc -O3 -ffast-math (если вы действительно заботитесь о 32-битном коде, как это было, тогда также тестируйте с -mfpmath=sse) - person Peter Cordes; 25.01.2021