【问题标题】:How to make a C compiler to transform all nested loop to a single loop如何使 C 编译器将所有嵌套循环转换为单个循环
【发布时间】:2017-09-24 19:49:33
【问题描述】:

假设有四个具有不同循环计数器和条件的嵌套循环。有没有办法告诉编译器(icc、gcc 和 clang)将所有循环转换为一个循环?

N=128; M=128; P=3; Q=3; //All these variables are constant
for (n=0; n<N; n++){
    for(m=0; m<M; m++){
        temp=0;
        for(p=0; p<P; p++){ 
            for(q=0; q<Q; q++){
                temp += kernel[p][q] * input[n+p][m+q];
            }
        }
        output[n][m]=temp;
    }
}

要转化为:

for(;;)
    //computations...

根据我的经验,当您依赖自动矢量化时,这很有用。如果有办法转换两个嵌套循环也可以。一些解决了this question但使用手写代码的事情。我有一个程序,你可以在 Godbolt 中看到它here

【问题讨论】:

  • 如何将其转换为单个循环?您期望发生什么魔术,以某种方式让编译器自行减少 N*M*P*Q 计算?如果不能,为什么要这样做?
  • 如果可以转换两个也可以工作的嵌套循环。
  • -funroll-all-loops?
  • @MarkWeston 这通常不会降低性能吗?我认为 OP 想要增加。
  • 不,我不希望 --funroll-all-loops 做 OP 要求的事情。首先,该选项中的“全部”是关于哪些循环是展开的候选——它们包括迭代次数不能完全确定为编译时间的循环。并非所有候选循环都已展开。其次,如果它确实展开了所有循环,那么 OP 将留下零个循环,而不是一个。

标签: c gcc clang compiler-optimization icc


【解决方案1】:

我不知道你为什么要这样做,但你可以手动完成。

int accumulator;
for (int i=0; i<N*M*P*Q; ++i) {
    int n = i;
    int q = n % Q;  n /= Q;
    int p = n % P;  n /= P;
    int m = n % M;  n /= M;

    if (!p && !q)
       accumulator = 0;

    accumulator += kernel[p][q] * input[n+p][m+q];

    if (!p && !q)
        output[n][m] = accumulator;
}

两个循环更有意义。

for (int i=0; i<N*M; ++i) {
    int n = i / M;
    int m = i % M;

    int accumulator = 0;
    for (int j=0; j<P*Q; ++j) {
        int p = j / Q;
        int q = j % Q;
        accumulator += kernel[p][q] * input[n+p][m+q];
    }    

    output[n][m] = accumulator;
}

【讨论】:

  • 我建议 OP 检查编译器的自动矢量化输出和他的原始代码并进行比较。
  • 谢谢,我比较过。它使 gcc 和 clang 不能向量化,但 icc 已经向量化了两个嵌套循环!
  • 由于迭代次数为 3,它可能不会矢量化,但您至少可以从内部循环中排除乘法。 (无论如何,2个循环与乘法因素可能会比单个循环更快)
猜你喜欢
  • 2016-04-24
  • 2021-12-30
  • 2012-11-06
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-02
  • 2023-02-15
相关资源
最近更新 更多