【问题标题】:Faster way to do _mm256_set1_ps更快的方法来做 _mm256_set1_ps
【发布时间】:2020-07-01 13:47:37
【问题描述】:

有没有比 C 内在函数更快的方法来在汇编中执行 _mm256_set1_ps?似乎内在函数编译为一系列 vmovss、vshufps、vmovss、vshufps 和 vinsertf128,甚至内在函数指南本身也表示效率低下。我想知道是否有其他方法可以做到这一点。我意识到如果有英特尔可能已经实现了它,但问一下也无妨....

【问题讨论】:

  • 你想设置什么值?一个常数,一个来自内存的值,来自另一个寄存器?你是怎么编译的(你是用-march=native -O2,还是类似的东西)? VBROADCASTSS 我认为这是非常量值的最有效方法。
  • @chtz:一个好的编译器通常会使用vbroadcastss 来实现_mm256_set1_ps,特别是如果它是来自内存的运行时变量,例如array[i] 或其他东西。一些编译器很愚蠢,在编译时将标量常量扩展为向量常量,即使它们最终只是在循环之前将其加载到寄存器中,而不是将其用作内存源操作数。这为vmovapsvbroadcastss 节省了 1 字节的代码大小,但需要 32 字节的数据缓存占用空间,而不是 4 字节。(AVX CPU 直接在加载端口中实现广播加载,至少英特尔是这样做的。)

标签: x86-64 avx2


【解决方案1】:

虽然这已经部分解决了一段时间,但我发现它是处理一些类似问题的一部分,并认为正式的答案可能会引起人们的兴趣。我知道两种主要情况。

  1. _mm256_set1_ps() 的常量位于内存中的已知地址。正如上面 cmets 中提到的@Peter Cordes,AVX vbroadcastss 适用于这种情况。
  2. 常量已经在寄存器的低位。 AVX2 vbroadcastss 适合这里(我相信AVX 需要vpermilps 设置低128 位,然后vperm2f128 设置高128)。

由于各种原因,我遇到了与此相关的低效代码生成,并实现了我自己的 _mm_set1_ps()_mm256_set1_ps() 变体以鼓励更高效的编译。但是,不要觉得我可以提出比检查你得到的反汇编更具体的建议。

【讨论】:

  • 这是标记为 AVX2;这意味着vbroadcastss ymm, xmm 可用于已注册案例。 (AVX1 仅提供内存源版本。)felixcloutier.com/x86/vbroadcast。如果您的编译器不这样做,请确保启用优化和 -march=znver1-march=haswell(或 MSVC -arch:AVX2),如果这不起作用,则升级到最新的 clang 或 GCC。
  • 谢谢彼得,注意到了。 (不过,在使用 C/C++ 以外的语言进行编码时,更新 clang 或 gcc 不会有帮助。)
  • 如果不是 C 或 C++(或 Objective-C),您可能不会使用 C 内在函数。许多其他语言使用相同的 GCC 或 LLVM 后端优化器,尽管其中许多也不使用 C 内部函数,例如 Rust,它有自己的内部函数风格,我认为它具有相似的名称。
  • 嗨彼得,我认为我们正在接近无趣的头发分裂,但我遇到的大多数讨论都使用英特尔的内在和指令名称,无论编程语言或编译器如何。我不知道具体的内在调查,但语言级别的数据表明 C 和 C++ 可能不是主要的用例。由于 OP 没有放置语言标签,我选择不做假设。
  • 是的,我们在这里偏离主题,但现在我很好奇。是否还有其他具有 SIMD 内在函数的主流语言使用 _mm_add_epi32 之类的名称?或者你只是说开发人员以这种方式谈论内在函数,即使他们使用像 C# 这样的语言,内在函数看起来像 Sse2.add?嗯,文档确实提到了 C 内在名称 _mm_add_epi8 以及更短更简单的 paddb。我总是只考虑 asm 助记符,因为那是 uops/latency 表使用的。
猜你喜欢
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多