【问题标题】:unrolling nested for loops - C展开嵌套的 for 循环 - C
【发布时间】:2015-05-31 18:07:35
【问题描述】:

我无法展开嵌套的 forloops。我理解这个概念,我正在尝试将其付诸实践,但我在编辑 for 循环中的语句以匹配展开时遇到了麻烦。

如果有人可以向我展示一个有效的展开并引导我完成它,那将是一个巨大的帮助。

这是我要展开的循环部分:

for (i=1 ; i < WIDTH-1 ; ++i) 
{
      for (j = 1 ; j < HEIGHT-1 ; ++j) 
      {
         n = getNeighbors(prv, i, j);    /* This is where I'm confused */
         mask = (prev[i][j] << 1);       
         next[i][j] = !(((n >> prev[i][j]) ^ 3) ^ mask);
      }
}

更新: 这是正确的吗?

for (i=1 ; i < WIDTH-1 ; i+=4) 
{
      for (j = 1 ; j < HEIGHT-1 ; j+=4) 
      {
         n = getNeighbors(prv, i, j);  
         mask = (prev[i][j] << 1);       
         next[i][j] = !(((n >> prev[i][j]) ^ 3) ^ mask);
         n = getNeighbors(prv, i, j+1);  
         mask = (prev[i][j+1] << 1);       
         next[i][j+1] = !(((n >> prev[i][j+1]) ^ 3) ^ mask);
         n = getNeighbors(prv, i, j+2);  
         mask = (prev[i][j+2] << 1);       
         next[i][j+2] = !(((n >> prev[i][j+2]) ^ 3) ^ mask);
         n = getNeighbors(prv, i, j+3);  
         mask = (prev[i][j+3] << 1);       
         next[i][j+3] = !(((n >> prev[i][j+3]) ^ 3) ^ mask);
      }
      for (j = 1 ; j < HEIGHT-1 ; j+=4) 
      {
         n = getNeighbors(prv, i+1, j);  
         mask = (prev[i+1][j] << 1);       
         next[i+1][j] = !(((n >> prev[i+1][j]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+1, j+1);  
         mask = (prev[i+!][j+1] << 1);       
         next[i+1][j+1] = !(((n >> prev[i+1][j+1]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+1, j+2);  
         mask = (prev[i+1][j+2] << 1);       
         next[i+1][j+2] = !(((n >> prev[i+1][j+2]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+1, j+3);  
         mask = (prev[i+1][j+3] << 1);       
         next[i+1][j+3] = !(((n >> prev[i+1][j+3]) ^ 3) ^ mask);
      }
      for (j = 1 ; j < HEIGHT-1 ; j+=4) 
      {
         n = getNeighbors(prv, i+2, j);  
         mask = (prev[i+2][j] << 1);       
         next[i+2][j] = !(((n >> prev[i+2][j]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+2, j+1);  
         mask = (prev[i+2][j+1] << 1);       
         next[i+2][j+1] = !(((n >> prev[i+2][j+1]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+2, j+2);  
         mask = (prev[i+2][j+2] << 1);       
         next[i+2][j+2] = !(((n >> prev[i+2][j+2]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+2, j+3);  
         mask = (prev[i+2][j+3] << 1);       
         next[i+2][j+3] = !(((n >> prev[i+2][j+3]) ^ 3) ^ mask);
      }
      for (j = 1 ; j < HEIGHT-1 ; j+=4) 
      {
         n = getNeighbors(prv, i+3, j);  
         mask = (prev[i+3][j] << 1);       
         next[i+3][j] = !(((n >> prev[i+3][j]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+3, j+1);  
         mask = (prev[i][j+1] << 1);       
         next[i+3][j+1] = !(((n >> prev[i+3][j+1]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+3, j+2);  
         mask = (prev[i][j+2] << 1);       
         next[i+3][j+2] = !(((n >> prev[i+3][j+2]) ^ 3) ^ mask);
         n = getNeighbors(prv, i+3, j+3);  
         mask = (prev[i+3][j+3] << 1);       
         next[i+3][j+3] = !(((n >> prev[i+3][j+3]) ^ 3) ^ mask);
      }
}

【问题讨论】:

  • 什么是prv?你试图通过展开循环来实现什么?你最终想要一个循环还是根本不想要循环?
  • 为什么不让编译器为您处理展开循环?
  • WIDTH 和 HEIGHT 是常量吗?这些值是展开所必需的。
  • 很抱歉没有提供细节。 prv 是一个二维数组,我正在尝试学习如何优化代码并实现更快的运行时,我想我根本不需要循环,但我想同时查看两个版本。我正在尝试在没有编译器帮助的情况下学习它。 WIDTH 和 HEIGHT 是常量。

标签: c loop-unrolling


【解决方案1】:

让循环成为:

for(int i = 0; i < x; ++i)
    for(int j = 0; j < y; ++j)
        dosomething(i, j);

它可以展开为:

for(int i = 0; i < x; i += 4) {
    for(int j = 0; j < y; j += 4) {
        dosomething(i, j);
        dosomething(i, j + 1);
        dosomething(i, j + 2);
        dosomething(i, j + 3);
    }
    for(int j = 0; j < y; j += 4) {
        dosomething(i + 1, j);
        dosomething(i + 1, j + 1);
        dosomething(i + 1, j + 2);
        dosomething(i + 1, j + 3);
    }
    for(int j = 0; j < y; j += 4) {
        dosomething(i + 2, j);
        dosomething(i + 2, j + 1);
        dosomething(i + 2, j + 2);
        dosomething(i + 2, j + 3);
    }
    for(int j = 0; j < y; j += 4) {
        dosomething(i + 3, j);
        dosomething(i + 3, j + 1);
        dosomething(i + 3, j + 2);
        dosomething(i + 3, j + 3);
    }
}

不确定这会有多大好处。您应该在展开后分析您的代码。

【讨论】:

  • 感谢您的评论。如果我在循环中有多个语句,例如我的代码中的 3 个分配,我将如何构建它?我假设我会像您在评论中向我展示的那样做,每个作业(例如)用 +1、+2、+3 完成 4 次
  • 只有当xy4 的倍数时才可能进行这种展开。展开外循环不如展开内循环有用。
【解决方案2】:

只是一个例子:

int r[3][3];

// loop version
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        r[i][j] = i + j;
    }
}

// unrolled version
r[0][0] = 0;
r[0][1] = 1;
r[0][2] = 2;
r[1][0] = 1;
r[1][1] = 2;
r[1][2] = 3;
r[2][0] = 2;
r[2][1] = 3;
r[2][2] = 4;

请注意,只有在编译时大小已知的向量或矩阵才能轻松实现这种完全展开。另请注意,最近的编译器通常能够自行展开此类循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    相关资源
    最近更新 更多