【问题标题】:How to cast __m128i to __m256i while setting upper bits to zero?如何在将高位设置为零的同时将 __m128i 转换为 __m256i?
【发布时间】:2020-05-21 06:26:14
【问题描述】:

我希望 VC++ 发出这样的代码:

vpxor     ymm0, ymm0, ymm0
vmovdqa   xmm0, xmm7

在人类语言中,我想要一个 32 字节的 __m256i 值,其中最低 16 字节来自另一个变量,最高 16 字节为零。相当于_mm256_castsi128_si256 固有的,只是我需要高128 位为零,而不是未定义。

这是我尝试过的:

_mm256_setr_m128i( low, _mm_setzero_si128() )
_mm256_insertf128_si256( _mm256_setzero_si256(), low, 0 )

上面两行都编译成vinsertf128,比较慢,3-4个周期延迟,比vmovdqa慢很多。 VC++ 2017 有什么解决方法吗?

【问题讨论】:

  • 你实际上并不想要vpxor ymm0, ymm0, ymm0;简单地编写一个 XMM 寄存器使用 VEX 或 EVEX 编码指令,如 vmovdqa(不是传统 SSE)已经零扩展到全宽。这就是 128 位 AVX 指令在没有 SSE/AVX 转换惩罚的情况下避免错误依赖的方式。这与在 x86-64 上编写 32 位整数寄存器相同。实际上,将 YMM 寄存器归零的最有效方法是对相应的 XMM 进行异或零处理,因此 AMD CPUs before Zen2 still only need 1 uop.
  • 至于让编译器不可怕;祝你好运。如果 MSVC 使用 _mm256_setr_m128i 和非 r set 版本将自己击倒,那么您可能会被搞砸。赞成您的问题,因为它比您想象的更大错过了优化。在 IvB+ 和 Bulldozer/Zen 上使用 1 uop 实现零延迟是可能的。

标签: c++ visual-c++ simd avx2


【解决方案1】:

首先,您不需要vpxor ymm0, ymm0, ymm0,因为vmovdqa xmm0, xmm7 已经将目标ymm/zmm 寄存器的高位归零。这与传统的 movdqa 指令不同,无论如何您都不应该在 AVX 代码中使用它。

其次,特定指令的选择是编译器的责任。如果您的编译器生成的代码效率低下,请考虑向编译器供应商报告错误。例如,gcc 识别这种内在函数模式并生成 optimal code

对于 MSVC,鉴于 x86-64 模式下不支持内联汇编,除了使用单独编译的汇编源之外,没有可靠的方法来确保特定指令。您可能会发现一些内在函数的组合会生成您想要的代码,但这将是不可靠的(并且可能会调用未定义的行为),并且可能会从一个编译器版本更改为另一个编译器版本。

【讨论】:

  • MSVC 通常根本不优化内在函数(对于真正的指令);如果你写_mm256_insertf128_si256,你会得到vinsertf128。虽然显然并非总是如此。顺便说一句,您的测试忘记将-arch:AVX2 用于MSVC;在一种情况下,它将在 vinsertf128 之前使用非 VEX xorps xmm2,xmm2gcc.godbolt.org/z/HEcHDe。您应该使用-arch:AVX2 -Gv(vectorcall 调用约定,所以__m128i args 在XMM regs 中传递)。 gcc.godbolt.org/z/fm2heu 表明 MSVC 19.21 及更高版本认为 __m128i args 已经零扩展为 256,并且仅发出 ret x86 和 x64
  • 具有讽刺意味的是,GCC 用_mm256_set_m128i 射自己的脚。 只有 clang 不擅长这样的事情(以及优化随机播放)。 gcc.godbolt.org/z/9HNtpi(GCC、clang 和 x86-64 MSVC 19.24)
  • 谢谢,我添加了 MSVC 参数并使用新链接更新了答案。是的,我同意 MSVC 在矢量内在函数方面尤其糟糕。
  • 它不能有这样的保证,因为可以从 SSE 代码调用 AVX 代码,并且 SSE 代码可能会以脏上向量状态执行。另外,我为 gcc 创建了一张票:gcc.gnu.org/bugzilla/show_bug.cgi?id=93594。另请参阅后续gcc.gnu.org/bugzilla/show_bug.cgi?id=93613。希望它会尽快改善。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
相关资源
最近更新 更多