Подтвердить что ты не робот

Как определить, использует ли C математика SSE2?

Я вступил в сборку трансцендентных математических функций библиотеки C с MSVC в режиме fp: strict. Все они, похоже, следуют одной и той же схеме, вот что происходит для sin.

Сначала существует процедура отправки из файла с именем "disp_pentium4.inc". Он проверяет, установлена ​​ли переменная ___use_sse2_mathfcns; если это так, называет __sin_pentium4, иначе вызывает __sin_default.

__sin_pentium4 (в "sin_pentium4.asm" ) начинается с передачи аргумента из x87 fpu в регистр xmm0, выполняет вычисления с использованием инструкций SSE2 и загружает результат обратно в fpu.

__sin_default (в "sin.asm" ) сохраняет переменную в стеке x87 и просто вызывает fsin.

Итак, в обоих случаях операнд помещается в стек x87 и возвращается на него, делая его прозрачным для вызывающего, но если ___use_sse2_mathfcns определено, операция фактически выполняется в SSE2, а не в x87.

Это очень интересно для меня, потому что трансцендентальные функции x87 известны тем, что в зависимости от реализации несколько отличаются поведением, тогда как данный фрагмент кода SSE2 всегда должен давать воспроизводимые результаты.

Есть ли способ определить, наверняка, в процессе компиляции или времени выполнения, что будет использоваться путь кода SSE2? Я не владею письменной сборкой, поэтому, если это связано с написанием какой-либо сборки, будет оценен пример кода.

4b9b3361

Ответ 1

Я нашел ответ через тщательное исследование математики. Это контролируется с помощью метода _set_SSE2_enable. Это общедоступный символ, зарегистрированный здесь:

Включает или отключает использование потоковых SIMD-расширений 2 (SSE2) инструкции в математических процедурах CRT. (Эта функция недоступна в x64, потому что SSE2 включен по умолчанию.)

Это приводит к тому, что вышеупомянутый флаг ___use_sse2_mathfcns устанавливается на предоставленное значение, эффективно включая или отключая использование подпрограмм SSE2 _pentium4.

В документации упоминается, что это затрагивает только определенные трансцендентные функции, но, глядя на разборку, это, кажется, затрагивает всех из них.

Изменить: переход в каждую функцию показывает, что все они доступны в SSE2, за исключением следующего:

  • fmod
  • зп
  • сЬ
  • TANH
  • SQRT

Sqrt является самым большим нарушителем, но его тривиально реализовать в SSE2, используя встроенные средства. Для других нет простого решения, за исключением, возможно, использования сторонней библиотеки, но я, вероятно, обойдусь без нее.

Ответ 2

Почему бы не использовать вашу собственную библиотеку вместо времени выполнения C? Это обеспечило бы еще более надежную гарантию согласованности между компьютерами (предположительно, среда выполнения C предоставляется как DLL и может немного измениться во времени).

Я бы рекомендовал CRlibm. Если вы уже настроили SSE2 и до тех пор, пока вы не собираетесь изменять режим округления FPU, вы находитесь в идеальных условиях для его использования, и вы не найдете более точной реализации.

Ответ 3

Короткий ответ заключается в том, что вы не можете указать В ВАШЕМ КОДЕ определенно, что будет делать библиотека, если только вы не используете специфические детали библиотеки. Это сделает код совершенно неспортивным - даже две разные сборки одного и того же компилятора могут изменить внутренности библиотеки.

Конечно, если переносимость не является проблемой, то с помощью extern <type> ___use_sse2_mathfcns; и проверки правильности работы.

Я ожидаю, что если процессор имеет SSE2, и вы используете современную библиотеку, она будет использовать SSE2 везде, где это возможно. Но сказать, что это определенно другое дело.

Если это важно для вашего кода, тогда реализуйте свои собственные трансцендентные функции и используйте их - это единственный способ гарантировать тот же результат. Или используйте некоторый подходящий встроенный ассемблерный (или трансцендентный) код для вычисления выбранных значений sin, cos и т.д. И сравните их с функциями sin() и cos(), предоставляемыми библиотекой.