无法检测为什么以下代码段未被矢量化

11

我一直在尝试将一个特定的应用程序向量化,但是我已经尝试了所有方法。从自动向量化到手写的SSE内部函数,但是不知何故,在基于stencil的应用程序上无法获得加速。

以下是我的当前代码片段,我使用了SSE指令集进行向量化。当我使用-vec-report3编译它(Intel icc)时,我不断收到以下消息:
remark: loop was not vectorized: statement cannot be vectorized.

  #pragma ivdep
  for ( i = STENCIL; i < z - STENCIL; i+=4 )
  {
    it = it2 + i;

    __m128 tmp2i = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j4+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j4+k*it_k])),X4_i); //loop was not vectorized: statement cannot be vectorized
    __m128 tmp3 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j3+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j3+k*it_k])),X3_i);
    __m128 tmp4 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j2+k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j2+k*it_k])),X2_i);
    __m128 tmp5 = _mm_mul_ps(_mm_add_ps(_mm_load_ps(&p2[i+j*it_j-it_j +k*it_k]),_mm_load_ps(&p2[i+j*it_j+it_j +k*it_k])),X1_i);

    __m128 tmp6 = _mm_add_ps(_mm_add_ps(_mm_add_ps(tmp2i,tmp3),_mm_add_ps(tmp4,tmp5)), _mm_mul_ps(_mm_load_ps(&p2[it]),C00_i));

    _mm_store_ps(&tmp2[i],tmp6);

   }

我是否遗漏了什么关键的东西?由于该消息没有详细说明为什么它不能被向量化,我很难确定瓶颈所在。

更新: 经过认真考虑建议,我按照以下方式调整了代码。我认为将其进一步分解以识别实际负责向量相关性的语句是最好的做法。

//#pragma ivdep
  for ( i = STENCIL; i < z - STENCIL; i+=4 )
  {
    it = it2 + i;
    __m128 center = _mm_mul_ps(_mm_load_ps(&p2[it]),C00_i);

    u_j4 = _mm_load_ps(&p2[i+j*it_j-it_j4+k*it_k]); //Line 180
    u_j3 = _mm_load_ps(&p2[i+j*it_j-it_j3+k*it_k]);
    u_j2 = _mm_load_ps(&p2[i+j*it_j-it_j2+k*it_k]);
    u_j1 = _mm_load_ps(&p2[i+j*it_j-it_j +k*it_k]);
    u_j8 = _mm_load_ps(&p2[i+j*it_j+it_j4+k*it_k]);
    u_j7 = _mm_load_ps(&p2[i+j*it_j+it_j3+k*it_k]);
    u_j6 = _mm_load_ps(&p2[i+j*it_j+it_j2+k*it_k]);
    u_j5 = _mm_load_ps(&p2[i+j*it_j+it_j +k*it_k]);

    __m128 tmp2i = _mm_mul_ps(_mm_add_ps(u_j4,u_j8),X4_i);
    __m128 tmp3 = _mm_mul_ps(_mm_add_ps(u_j3,u_j7),X3_i);
    __m128 tmp4 = _mm_mul_ps(_mm_add_ps(u_j2,u_j6),X2_i);
    __m128 tmp5 = _mm_mul_ps(_mm_add_ps(u_j1,u_j5),X1_i);

    __m128 tmp6 = _mm_add_ps(_mm_add_ps(tmp2i,tmp3),_mm_add_ps(tmp4,tmp5));
    __m128 tmp7 = _mm_add_ps(tmp6,center);

    _mm_store_ps(&tmp2[i],tmp7);  //Line 196

   }

如果我在没有使用 #pragma ivdep 的情况下编译(icc)上面的代码,我会收到以下信息:

remark: loop was not vectorized: existence of vector dependence.
vector dependence: assumed FLOW dependence between tmp2 line 196 and tmp2 line 196.
vector dependence: assumed ANTI dependence between tmp2 line 196 and tmp2 line 196.

当我使用#pragma ivdep编译(icc)时,我得到如下消息:

remark: loop was not vectorized: unsupported data type. //Line 180
为什么在第196行建议存在依赖关系?如何消除建议的向量依赖关系?

这并不是我最初想到的对齐方式(Mysticial 纠正了我),但简化数组偏移表达式肯定是值得尝试的起点。 - Viktor Latypov
@Mystical:这只是我的代码片段。实际代码是一个3D图案,我已经测试了512到1024这么大的数据大小。这意味着浮点运算的总数为(512)^ 3 * 31 * 200。200是迭代次数。当将4个浮点操作一起调度(使用SSE内部函数)时,与单个时钟周期中的1相比,我预计会有一些改进。 - PGOnTheGo
6
那不是问题所在。你在仅进行13个操作时有10次内存访问,这太多了。CPU很可能会被加载限制而不是计算。根据我的经验,你真的需要至少3比1的计算/内存访问比率。 - Mysticial
此外,您的循环体似乎具有相当长的依赖链。我建议手动展开2到4次迭代。 - Mysticial
2
减少内存访问的唯一方法是改变数据处理方式。如果您需要多次访问相同的数据,请尝试将它们分组在一起。这里没有更多可以说的了。您可以查看:http://en.wikipedia.org/wiki/Loop_tiling - Mysticial
显示剩余6条评论
1个回答

2
问题在于您试图将自动向量化与手动向量化的代码一起使用。编译器表示该行无法向量化,因为您无法向量化向量函数。
要么让编译器自动向量化它,要么禁用自动向量化并手动向量化您的代码。正如已经评论过的那样,自动向量化程序会计算向量化的盈利能力:它检查是否值得向量化您的代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接