Как определить, использует ли 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? Я не владею письменной сборкой, поэтому, если это связано с написанием какой-либо сборки, будет оценен пример кода.
Ответы
Ответ 1
Я нашел ответ через тщательное исследование математики. Это контролируется с помощью метода _set_SSE2_enable
. Это общедоступный символ, зарегистрированный здесь:
Включает или отключает использование потоковых SIMD-расширений 2 (SSE2) инструкции в математических процедурах CRT. (Эта функция недоступна в x64, потому что SSE2 включен по умолчанию.)
Это приводит к тому, что вышеупомянутый флаг ___use_sse2_mathfcns устанавливается на предоставленное значение, эффективно включая или отключая использование подпрограмм SSE2 _pentium4.
В документации упоминается, что это затрагивает только определенные трансцендентные функции, но, глядя на разборку, это, кажется, затрагивает всех из них.
Изменить: переход в каждую функцию показывает, что все они доступны в SSE2, за исключением следующего:
Sqrt является самым большим нарушителем, но его тривиально реализовать в SSE2, используя встроенные средства. Для других нет простого решения, за исключением, возможно, использования сторонней библиотеки, но я, вероятно, обойдусь без нее.
Ответ 2
Почему бы не использовать вашу собственную библиотеку вместо времени выполнения C? Это обеспечило бы еще более надежную гарантию согласованности между компьютерами (предположительно, среда выполнения C предоставляется как DLL и может немного измениться во времени).
Я бы рекомендовал CRlibm. Если вы уже настроили SSE2 и до тех пор, пока вы не собираетесь изменять режим округления FPU, вы находитесь в идеальных условиях для его использования, и вы не найдете более точной реализации.
Ответ 3
Короткий ответ заключается в том, что вы не можете указать В ВАШЕМ КОДЕ определенно, что будет делать библиотека, если только вы не используете специфические детали библиотеки. Это сделает код совершенно неспортивным - даже две разные сборки одного и того же компилятора могут изменить внутренности библиотеки.
Конечно, если переносимость не является проблемой, то с помощью extern <type> ___use_sse2_mathfcns;
и проверки правильности работы.
Я ожидаю, что если процессор имеет SSE2, и вы используете современную библиотеку, она будет использовать SSE2 везде, где это возможно. Но сказать, что это определенно другое дело.
Если это важно для вашего кода, тогда реализуйте свои собственные трансцендентные функции и используйте их - это единственный способ гарантировать тот же результат. Или используйте некоторый подходящий встроенный ассемблерный (или трансцендентный) код для вычисления выбранных значений sin
, cos
и т.д. И сравните их с функциями sin()
и cos()
, предоставляемыми библиотекой.