如何在 MSVC 中有效地从两个 __m128d 转换为一个 __m128i?
How to efficiently convert from two __m128d to one __m128i in MSVC?
转换然后移位然后按位或运算是从两个 __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 文档中得到支持,说 _mm_cvtpd_pi32
在 x64 上不受支持。
我不太担心它不可用,但是是两次转换,一次移位,然后按位-还是最快的方法?
如果您遇到链接器错误,您可能忽略了有关未声明的内部函数的警告。
您当前的代码编译成可怕的 asm 的风险很高。如果它编译为向量移位和 OR,它已经在编译为次优代码。 (更新:这不是它编译的结果,IDK 你是从哪里得到这个想法的。)
使用 2x _mm_cvtpd_epi32 to get two __m128i
vectors with ints you want in the low 2 elements of each. Use _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 几乎完全没用;只是避免它。有关一些指南,请参阅 sse 标签 wiki。
转换然后移位然后按位或运算是从两个 __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 文档中得到支持,说 _mm_cvtpd_pi32
在 x64 上不受支持。
我不太担心它不可用,但是是两次转换,一次移位,然后按位-还是最快的方法?
如果您遇到链接器错误,您可能忽略了有关未声明的内部函数的警告。
您当前的代码编译成可怕的 asm 的风险很高。如果它编译为向量移位和 OR,它已经在编译为次优代码。 (更新:这不是它编译的结果,IDK 你是从哪里得到这个想法的。)
使用 2x _mm_cvtpd_epi32 to get two __m128i
vectors with ints you want in the low 2 elements of each. Use _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 几乎完全没用;只是避免它。有关一些指南,请参阅 sse 标签 wiki。