为啥这个 C 向量循环不自动向量化?

Posted

技术标签:

【中文标题】为啥这个 C 向量循环不自动向量化?【英文标题】:Why doesn't this C vector loop auto-vectorise?为什么这个 C 向量循环不自动向量化? 【发布时间】:2016-07-28 11:21:25 【问题描述】:

我正在尝试通过使用 AVX 内在函数来优化一些代码。编译了一个非常简单的测试用例,但告诉我我的循环没有向量化,原因有很多我不明白。

这是完整的程序,simple.c

#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <immintrin.h>

int main(void)


  __m256 * x = (__m256 *) calloc(1024,sizeof(__m256));    

  for (int j=0;j<32;j++)
    x[j] = _mm256_set1_ps(1.); 

  return(0);

这是命令行: gcc simple.c -O1 -fopenmp -ffast-math -lm -mavx2 -ftree-vectorize -fopt-info-vec-missed

这是输出:

simple.c:11:3:注意:未矢量化:不支持的数据类型 simple.c:11:3:注意:无法确定矢量化因子。 simple.c:6:5:注意:未矢量化:基本块中的数据引用不足。 simple.c:11:3:注意:未矢量化:基本块中的数据引用不足。 simple.c:6:5:注意:未矢量化:基本块中的数据引用不足。 simple.c:6:5:注意:未矢量化:基本块中的数据引用不足。

我有 gcc 5.4 版。

谁能帮我解释这些信息并了解发生了什么?

【问题讨论】:

【参考方案1】:

您已经使用内在函数进行了手动矢量化,因此 gcc 没有任何东西可以自动矢量化。这会导致无趣的警告,我假设尝试自动矢量化内在或循环计数器增量。

我从 gcc 5.3 (on the Godbolt compiler explorer) 获得了很好的 asm,如果我不做一些愚蠢的事情,比如编写一个可以优化掉的函数,或者尝试只使用 -O1 编译它。

#include <immintrin.h>

void set_to_1(__m256 * x) 
  for (int j=0;j<32;j++)
    x[j] = _mm256_set1_ps(1.); 


    push    rbp
    lea     rax, [rdi+1024]
    vmovaps ymm0, YMMWORD PTR .LC0[rip]
    mov     rbp, rsp
    push    r10                      # gcc is weird with r10 in functions with ymm vectors
.L2:                                 # this is the vector loop
    vmovaps YMMWORD PTR [rdi], ymm0
    add     rdi, 32
    cmp     rdi, rax
    jne     .L2
    vzeroupper
    pop     r10
    pop     rbp
    ret

.LC0:
    .long   1065353216
    ... repeated several times because gcc failed to use a vbroadcastss load or generate the constant on the fly

我确实从 -O1 得到了几乎相同的 asm,但使用 -O1 不优化东西并不是了解 gcc 真正能做什么的好方法。

【讨论】:

是否有有用且详细的文档来解释 GCC 关于自动矢量化的信息和警告?我发现输出有时令人困惑。 @Jens:不知道;我总是只看 asm 输出,看看编译器做了什么。在复杂的函数中,在调试器中单步执行可以帮助找到主循环(在剥离的序言/结尾未对齐迭代的噪音中)。 谢谢彼得。我认为这些信息暗示出了问题。到目前为止,您的回答和我的经验表明,确实没有什么可以替代对 asm 的熟悉。最好早点知道这一点。 @ghostofsandy:这些警告可能有助于确定循环为什么在合理认为/希望应该自动矢量化时不会自动矢量化。或者识别回归,当更改使循环不再自动矢量化时。但是,是的,如果您对 asm 很了解,它们只是要查看哪些循环的路标。如果您几乎不知道,那么它们是寻找...ps 指令(打包单)而不是仅...ss(标量单)的线索。例如mulps

以上是关于为啥这个 C 向量循环不自动向量化?的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 2012 中 Eigen 类型向量的自动向量化效果不佳

C++ 矩阵乘法自动向量化

英特尔 Fortran 向量化:向量循环成本高于标量

矩阵乘法的自动向量化

如何确定向量长度以确保向量化过程中没有向量依赖性?

当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为