如何在MSVC中有效地从两个__m128d转换为一个__m128i?

时间:2016-09-15 04:24:00

标签: visual-c++ x86 64-bit sse mmx

是转换然后按位移位还是“从两个__m128d转换为单个__m128i的唯一方法?

x64版本中的Xcode完全可以接受

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

并且反汇编显示正在使用的_mm_cvtpd_pi32。但是,Visual Studio无法编译,抱怨链接器错误。 VS文档支持此功能,说x64不支持_mm_cvtpd_pi32

我不是太担心它不可用,而是两次转换,转变,然后是按位或最快的方式?

1 个答案:

答案 0 :(得分:2)

如果您遇到链接器错误,您可能会忽略有关未声明的内部函数的警告。

您当前的代码很可能会编译为可怕的asm。如果它被编译为向量移位和OR,它已经编译为次优代码。 (更新:这不是它编写的内容,IDK你有这个想法。)

使用2x _mm_cvtpd_epi32来获取两个__m128i向量,其中包含每个向量的低2个元素。使用_mm_unpacklo_epi64将这两个低半部分组合成一个包含所需4个元素的向量。

clang3.8.1 on the Godbolt compiler explorer的编译器输出。 (我认为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
当SSE2及更高版本可用时,MMX几乎完全无用;只是避免它。有关指南,请参阅代码维基。