对于 64 位目标,在 MSVC 2019 中找不到像 _mm_cvtpd_pi32 这样的 MMX 内在函数;与 2013 年相比有何变化?

Nim*_*imo 5 x86-64 intrinsics visual-c++ mmx visual-studio-2019

我目前正在将大型代码库从 VS2013 更新到 VS2019。我遇到的编译器错误之一如下:

内部函数.h(348):错误C3861:“_mm_cvtpd_pi32”:未找到标识符

这个内部函数在 Visual Studio 的“emmintrin.h”中定义。我只在针对 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);
Run Code Online (Sandbox Code Playgroud)

对此:

#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
Run Code Online (Sandbox Code Playgroud)

即:预处理器指令确保函数现在仅可用于 32 位目标。无论目标是什么(64 位或 32 位),产生错误的第 3 方头文件都会使用这些函数。据推测,这里最好的做法是编辑这个头文件,以确保仅对 32 位目标调用此函数。然而,我更好奇的是,为什么从 2013 年到 2019 年发生了变化?我在这里看到了这个函数的描述:

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

从一开始它就从未适用于 64 位目标吗?或者它是否已被我需要考虑的 64 位版本替换?

Pet*_*des 5

我不知道是否有办法让 MSVC 2019 编译这个遗留的 MMX 内在函数。

在 Windows 上以 64 位代码使用 MMX 指令是安全的,但 MS 并不能让使用 MS 编译器构建此类代码变得容易。较新的 MSVC 可能不支持该内在函数;如果您需要使用 MMX 内在函数编译旧代码,并且 MSVC 没有解决方法,请使用更好的编译器(例如 clang) 。

(在 x86-64 和 64 位 Windows 的早期历史中,MS 删除了一些对 MMX 的编译器或汇编器支持这一事实让一些人担心 Windows 内核可能无法正确地为 x87/MMX 状态进行上下文切换.这个怀疑是没有根据的。如果你能得到MMX代码来编译/汇编,例如使用其他工具,它仍然会运行得很好。Windows支持它,长模式下的x86-64 CPU仍然完全支持MMX。我不要使用 Windows,而且我不记得删除了哪种 MMX 支持。)


当然,通常最好使用 SSE2 而不是 MMX,即 epi32 内在函数而不是 pi32 (或任何其他整数元素宽度)。SSE2 是 x86-64 的基准,也是双精度 SIMD(包括该转换内在函数)所必需的。

该转换的用例(我认为)主要是获取 MMX 整数向量,以便与现有的旧版 MMX 向量化代码一起使用。

但在这种特定情况下,cvtpd2pi实际上并不比cvtpd2qd(正常的 SSE2 _mm_cvtpd_epi32)慢 - 两者都是 2 uops,我认为因为即使在 XMM 寄存器域内,它也必须将 32 位整数洗牌到底部。 https://www.uops.info/table.htmlps与 XMM 寄存器之间 FP->int 转换为单微指令的版本不同。

MMX 指令的吞吐量比最新 CPU 上的等效 SSE2/3 指令(在更少的端口上运行)更差,并且 mov-elimination 对它们不起作用。