VS2013升级至VS2019:64位编译缺失_mm_cvtpd_pi32等MMX intrinsics
_mm_cvtpd_pi32标识符找不到的问题 我刚好碰到过类似的VS版本升级问题,给你梳理一下这个问题的来龙去脉和解决办法:
为什么VS2019会添加这个平台限制?
核心原因是__m64类型在64位x86(AMD64/X64)架构下的兼容性问题。_mm_cvtpd_pi32这类函数是MMX和SSE指令集的混合接口,返回的是MMX对应的__m64类型。而在64位模式下,微软编译器对MMX intrinsics的支持本来就很有限:一方面MMX指令和更现代的SSE/AVX指令混用容易导致寄存器冲突(MMX会占用XMM寄存器的低64位),另一方面64位环境下更推荐使用纯SSE/AVX的intrinsics,它们的类型(比如__m128i)更适配64位寄存器模型。
VS2013阶段还没严格限制这类函数的使用场景,但到了VS2019,微软明确把这些依赖__m64的跨指令集转换函数限制在32位目标中,本质是引导开发者使用更适合64位平台的现代指令集接口。
这些函数真的不适用于64位目标吗?
是的,不仅不适配,甚至在64位环境下使用会有潜在问题。__m64类型在64位VS编译环境中没有原生寄存器支持,编译器需要额外代码模拟处理,既影响性能,又容易引发奇怪的兼容性bug。而且这类MMX和SSE混合的转换逻辑,在64位模式下完全可以用纯SSE2的intrinsics替代,没必要再依赖老旧的MMX接口。
64位下的替代方案
针对你提到的三个函数,对应的64位替代intrinsics都是SSE2标准的,完全适配64位平台:
1. 替代_mm_cvtpd_pi32(带舍入的双精度转32位整数)
用_mm_cvtpd_epi32,它返回__m128i类型(64位环境下原生支持的整数向量类型),如果需要提取单个整数,可以配合_mm_extract_epi32:
__m128d input_float = _mm_set_pd(3.7, 2.2); __m128i result_int = _mm_cvtpd_epi32(input_float); // 提取低64位浮点数的转换结果(四舍五入) int val0 = _mm_extract_epi32(result_int, 0); // 结果为2 // 提取高64位浮点数的转换结果(四舍五入) int val1 = _mm_extract_epi32(result_int, 1); // 结果为4
2. 替代_mm_cvttpd_pi32(截断式双精度转32位整数)
用_mm_cvttpd_epi32,用法和上面一致,区别是它会直接截断小数部分:
__m128d input_float = _mm_set_pd(3.7, 2.2); __m128i result_int = _mm_cvttpd_epi32(input_float); int val0 = _mm_extract_epi32(result_int, 0); // 结果为2 int val1 = _mm_extract_epi32(result_int, 1); // 结果为3
3. 替代_mm_cvtpi32_pd(32位整数转双精度浮点数)
用_mm_cvtepi32_pd,不过需要先把整数打包成__m128i类型:
int val0 = 2, val1 = 3; __m128i input_int = _mm_set_epi32(0, 0, val1, val0); // 低64位放val0,高64位放val1 __m128d result_float = _mm_cvtepi32_pd(input_int);
不修改第三方头文件的临时适配
如果不想直接修改第三方头文件,可以用条件编译做一层封装,在64位环境下替换这些函数的定义:
#ifdef _M_X64 // 64位下替换为SSE2实现 #include <emmintrin.h> inline __m128i _mm_cvtpd_pi32(__m128d a) { return _mm_cvtpd_epi32(a); } inline __m128i _mm_cvttpd_pi32(__m128d a) { return _mm_cvttpd_epi32(a); } inline __m128d _mm_cvtpi32_pd(__m128i a) { return _mm_cvtepi32_pd(a); } // 注意:如果第三方代码依赖__m64类型,建议逐步修改为__m128i的逻辑 #else // 32位环境下直接使用原函数 #include "第三方头文件.h" #endif
内容的提问来源于stack exchange,提问作者voronoidea

