Встроенные функции MMX, такие как _mm_cvtpd_pi32, не найдены в MSVC 2019 для 64-битных целей; изменить с 2013 года?

В настоящее время я работаю над обновлением большой базы кода с VS2013 до VS2019. Одна из ошибок компилятора, с которой я столкнулся, выглядит следующим образом:

intrinsics.h (348): ошибка C3861: '_mm_cvtpd_pi32': идентификатор не найден

Эта внутренняя функция определена в файле "emmintrin.h" Visual Studio. Я получаю эту ошибку только при нацеливании на 64-битные сборки. При ближайшем рассмотрении можно увидеть, что между 2013 и 2019 годами определение emmintrin.h изменилось с этого:

extern __m64 _mm_cvtpd_pi32(__m128d _A);
extern __m64 _mm_cvttpd_pi32(__m128d _A);
extern __m128d _mm_cvtpi32_pd(__m64 _A);

К этому:

#if defined(_M_IX86)
extern __m64 _mm_cvtpd_pi32(__m128d _A);
extern __m64 _mm_cvttpd_pi32(__m128d _A);
extern __m128d _mm_cvtpi32_pd(__m64 _A);
#endif

т.е.: директива препроцессора гарантирует, что функции теперь доступны только для 32-битных целей. Заголовочный файл третьей стороны, из которого возникла ошибка, использует эти функции независимо от цели (64 или 32 бит). По-видимому, лучший способ действий здесь - отредактировать этот файл заголовка, чтобы гарантировать, что эта функция вызывается только для 32-битных целей. Однако меня больше интересует, почему это было изменено с 2013 на 2019 год? Я вижу здесь описание этой функции:

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_pi32&expand=1705

Разве это никогда не было применимо к 64-битным целям? Или его заменили на 64-битную версию, которую мне нужно рассмотреть?


person Nimo    schedule 30.03.2020    source источник
comment
Они решили больше не поддерживать регистры x87 для 64-битного кода. Официально задокументированный здесь. Пока это сложно только для кода WDM, но игнорировать его не стоит. Также смотрите здесь.   -  person Hans Passant    schedule 30.03.2020
comment
@HansPassant: Нет причин ожидать, что эти ограничения кода ядра когда-либо будут применяться к пользовательскому пространству. Для ядер совершенно нормально ограничиваться только целочисленным кодом в целом или требовать специальных вещей, прежде чем вы сможете их использовать. (например, как Linux kernel_fpu_begin, поэтому ядру не нужно сохранять / восстанавливать состояние FPU / SIMD для обработчиков прерываний / системных вызовов.) Но именно по этим причинам (ядра стараются сохранять / восстанавливать пользовательское пространство Состояние FPU / SIMD, включая x87), машинный код пользовательского пространства может ожидать, что он по-прежнему сможет использовать MMX / x87, как текущую Windows.   -  person Peter Cordes    schedule 31.03.2020
comment
По сути, я хочу сказать, что есть веские причины не поддерживать x87 / MMX в ядре, даже если вы не планируете в конечном итоге отказываться от поддержки пользовательского пространства. Так что вывод, который вы, кажется, делаете, не следует. Независимо от того, поддерживают ли определенные компиляторы встроенные функции MMX или нет, это отдельный вопрос. Другие компиляторы Windows, такие как GCC и clang, по-прежнему поддерживают встроенные функции MMX и имеют параметры, позволяющие использовать long double = 80-битный x87. Некоторые популярные проекты, такие как x264 и FFmpeg, все еще (к сожалению) используют MMX в рукописном asm.   -  person Peter Cordes    schedule 31.03.2020


Ответы (1)


Я не знаю, есть ли способ заставить MSVC 2019 скомпилировать эту устаревшую встроенную функцию MMX.

Использование инструкций MMX в 64-битном коде в Windows безопасно, но MS не упрощает создание такого кода с помощью компиляторов MS. Встроенная функция может не поддерживаться новым MSVC; используйте лучший компилятор (например, clang), если вам нужно компилируйте старый код со встроенными функциями MMX, если для MSVC нет обходного пути.

(В начале истории x86-64 и 64-битной Windows тот факт, что MS удалила некоторую поддержку компилятора или ассемблера для MMX, некоторых людей беспокоило, что, возможно, ядро ​​Windows не будет должным образом переключать контекст для состояния x87 / MMX. Это сомнение было необоснованным. Если вы можете получить код MMX для компиляции / сборки, например, с помощью других инструментов, он все равно будет работать отлично. Windows поддерживает его, а процессоры x86-64 в длинном режиме по-прежнему полностью поддерживают MMX. не используйте Windows, и я точно не помню, какая поддержка MMX была удалена.)


Конечно, обычно лучше использовать SSE2 вместо MMX, т.е. инстринсики epi32 вместо pi32 (или любой другой ширины целочисленного элемента). SSE2 является базовым для x86-64, а также требуется для SIMD с двойной точностью (включая это внутреннее преобразование).

Вариант использования этого преобразования (я думаю) в основном заключается в получении целочисленных векторов MMX для использования с существующим устаревшим векторизованным кодом MMX.

Но в этом конкретном случае cvtpd2pi на самом деле не медленнее, чем cvtpd2qd (нормальный SSE2 _mm_cvtpd_epi32) - я думаю, оба на 2 мопа, потому что даже в регистровом домене XMM он должен перетасовать 32-битные целые числа вниз. https://www.uops.info/table.html. В отличие от версии ps, где преобразование FP-> int между регистрами XMM является однократным.

Инструкции MMX имеют худшую пропускную способность, чем эквивалентные инструкции SSE2 / 3 на последних процессорах (работающих на меньшем количестве портов), и удаление mov на них не работает.

person Peter Cordes    schedule 30.03.2020