首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCC:两个相似循环的向量化差异

GCC:两个相似循环的向量化差异
EN

Stack Overflow用户
提问于 2012-08-23 16:55:13
回答 4查看 3.2K关注 0票数 34

在用gcc -O3编译时,为什么下面的循环不矢量化(自动):

代码语言:javascript
复制
#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foo () {
  int i, j;

  for (i=0; i<SIZE; i++){
    for (j=i; j<SIZE; j++) {
      a[i] = b[i] > c[j] ? b[i] : c[j];
    }
  }
  return a[0];
}

而下一个呢?

代码语言:javascript
复制
#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foov () {
  int i, j;

  for (i=0; i<SIZE; i++){
    for (j=i; j<SIZE; j++) {
      a[i] += b[i] > c[j] ? b[i] : c[j];
    }
  }
  return a[0];
}

唯一的区别是内循环中表达式的结果是分配给ai的,还是添加到ai中的。

作为参考,-ftree-vectorizer-verbose=6为第一个(非矢量化)循环提供了以下输出。

代码语言:javascript
复制
v.c:8: note: not vectorized: inner-loop count not invariant.
v.c:9: note: Unknown alignment for access: c
v.c:9: note: Alignment of access forced using peeling.
v.c:9: note: not vectorized: live stmt not supported: D.2700_5 = c[j_20];

v.c:5: note: vectorized 0 loops in function.

与矢量化循环的输出相同的是:

代码语言:javascript
复制
v.c:8: note: not vectorized: inner-loop count not invariant.
v.c:9: note: Unknown alignment for access: c
v.c:9: note: Alignment of access forced using peeling.
v.c:9: note: vect_model_load_cost: aligned.
v.c:9: note: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
v.c:9: note: vect_model_simple_cost: inside_cost = 1, outside_cost = 1 .
v.c:9: note: vect_model_reduction_cost: inside_cost = 1, outside_cost = 6 .
v.c:9: note: cost model: prologue peel iters set to vf/2.
v.c:9: note: cost model: epilogue peel iters set to vf/2 because peeling for alignment is unknown .
v.c:9: note: Cost model analysis:
  Vector inside of loop cost: 3
  Vector outside of loop cost: 27
  Scalar iteration cost: 3
  Scalar outside cost: 7
  prologue iterations: 2
  epilogue iterations: 2
  Calculated minimum iters for profitability: 8

v.c:9: note:   Profitability threshold = 7

v.c:9: note: Profitability threshold is 7 loop iterations.
v.c:9: note: LOOP VECTORIZED.
v.c:5: note: vectorized 1 loops in function.
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-08-23 17:42:37

(在第一个例子中是):代码在每次迭代中覆盖相同的内存位置a[i]。由于循环迭代不是独立的,这就固有地对循环进行了顺序化。

(实际上,实际上只需要最后一次迭代。所以整个内环都可以被取出来。)

在第二个案例中,:GCC将循环识别为一个缩减操作--它有特殊的案例处理来矢量化。

编译器矢量化通常被实现为某种“模式匹配”。也就是说,编译器对代码进行分析,以确定它是否符合某种模式,从而能够将代码向量化。如果是的话,它就会被矢量化。如果没有,那就没有。

在这种情况下,第一个循环似乎不符合GCC所能处理的任何预编码模式。但第二种情况符合“向量化缩减”模式。

下面是GCC的源代码的相关部分,其中显示了"not vectorized: live stmt not supported: "消息:

http://svn.open64.net/svnroot/open64/trunk/osprey-gcc-4.2.0/gcc/tree-vect-analyze.c

代码语言:javascript
复制
if (STMT_VINFO_LIVE_P (stmt_info))
{
    ok = vectorizable_reduction (stmt, NULL, NULL);

    if (ok)
        need_to_vectorize = true;
    else
        ok = vectorizable_live_operation (stmt, NULL, NULL);

    if (!ok)
    {
        if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
        {
            fprintf (vect_dump, 
                "not vectorized: live stmt not supported: ");
            print_generic_expr (vect_dump, stmt, TDF_SLIM);
        }
        return false;
    }
}

从台词上说:

代码语言:javascript
复制
vectorizable_reduction (stmt, NULL, NULL);

很明显,GCC正在检查它是否符合“可向量化的缩减”模式。

票数 31
EN

Stack Overflow用户

发布于 2012-08-23 17:29:24

GCC向量器可能不够聪明,无法对第一个循环进行矢量化。由于a + 0 == a,加法用例更容易矢量化。考虑一下SIZE==4

代码语言:javascript
复制
  0 1 2 3 i
0 X
1 X X
2 X X X
3 X X X X
j

X表示ij的组合,当a被赋值或增加时。对于加法情况,我们可以计算b[i] > c[j] ? b[i] : c[j]的结果,比方说,j==1i==0..4,并将其放入向量D中。然后我们只需要将D[2..3]为零并将结果向量添加到a[0..3]中。在任务分配方面,则要复杂一些。我们不仅要有零的D[2..3],而且要有零的A[0..1],然后才能把结果结合起来。我想这就是矢量程序失败的地方。

票数 4
EN

Stack Overflow用户

发布于 2012-08-23 18:24:57

第一个循环等价于

代码语言:javascript
复制
#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foo () {
  int i, j;

  for (i=0; i<SIZE; i++){
    a[i] = b[i] > c[SIZE - 1] ? b[i] : c[SIZE - 1];
  }
  return a[0];
}

原来的表达方式的问题是,它并没有那么有意义,所以gcc不能把它矢量化也就不足为奇了。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12096599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档