Как эффективно конвертировать из двух __m128d в один __m128i в MSVC?

Преобразование, затем сдвиг, затем побитовый или единственный способ преобразования из двух __m128d одному __m128i?

Это вполне приемлемо для Xcode в сборке x64

m128d v2dHi = ....
m128d v2dLo = ....
__m128i v4i = _mm_set_epi64(_mm_cvtpd_pi32(v2dHi), _mm_cvtpd_pi32(v2dLo))

и разборка показывает _mm_cvtpd_pi32 использовался. Однако Visual Studio не может скомпилировать это, жалуясь на ошибку компоновщика. Это поддерживается в документах VS, говоря _mm_cvtpd_pi32 не поддерживается на x64.

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

1 ответ

Решение

Если вы получили ошибку компоновщика, вы, вероятно, игнорируете предупреждение о необъявленной встроенной функции.

Ваш текущий код имеет высокий риск компиляции в ужасный ассм. Если он скомпилирован с векторным сдвигом и OR, он уже компилируется в неоптимальный код. (Обновление: это не то, что он компилирует, IDK, откуда у вас эта идея.)

Используйте 2x _mm_cvtpd_epi32, чтобы получить два __m128i векторы с целочисленными значениями в младших 2 элементах каждого. Используйте _mm_unpacklo_epi64, чтобы объединить эти две нижние половины в один вектор со всеми 4 элементами, которые вы хотите.


Вывод компилятора из clang3.8.1 в проводнике компилятора Godbolt. (Я думаю, Xcode использует clang по умолчанию).

#include <immintrin.h>

// the good version
__m128i pack_double_to_int(__m128d a, __m128d b) {
    return _mm_unpacklo_epi64(_mm_cvtpd_epi32(a), _mm_cvtpd_epi32(b));
}
    cvtpd2dq        xmm0, xmm0
    cvtpd2dq        xmm1, xmm1
    punpcklqdq      xmm0, xmm1      # xmm0 = xmm0[0],xmm1[0]
    ret

// the original
__m128i pack_double_to_int_badMMX(__m128d a, __m128d b) {
    return _mm_set_epi64(_mm_cvtpd_pi32(b), _mm_cvtpd_pi32(a));
}
    cvtpd2pi        mm0, xmm1
    cvtpd2pi        mm1, xmm0
    movq2dq xmm1, mm0
    movq2dq xmm0, mm1
    punpcklqdq      xmm0, xmm1      # xmm0 = xmm0[0],xmm1[0]
      # note the lack of EMMS, because of not using the intrinsic for it
    ret

MMX практически полностью бесполезен, когда доступен SSE2 и более поздние версии; просто избегай этого. Смотрите sse tag wiki для некоторых руководств.

Другие вопросы по тегам