【问题标题】:Loop unrolling with dependent loops使用依赖循环展开循环
【发布时间】:2013-06-12 15:14:48
【问题描述】:

我正在开发一个大型应用程序,我需要针对某个过程对后续相关循环执行循环展开。我在下面写了一小段代码来复制更大的版本。

考虑原始代码:

void main()
{

 int a[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
 int b[20] = {10,9,8,7,6,5,4,3,2,1,20,19,18,17,16,15,14,13,12,11};
 int i,j,k,l;
 int nab =4, vab =10;
 int dimi, dimj, dimij, dimk, diml, dimkl, dimijkl;
 int count = 0;

 for (i = nab+1; i< nab+vab; i++) 
 {
   dimi = a[i];
   for (j = i; j< nab+vab; j++)
   {
    dimj = b[j];
    dimij = dimi*dimj;
    count = count +1;

    for (k = nab+1; k< nab+vab; k++)
    {
     dimk = a[k-1];
     for (l =k; l< nab+vab; l++)
     {
      diml = a[l-1];
      dimkl = dimk*diml;
      dimijkl = dimij * dimkl;
     }
    }
   }
  }
 printf ("Final dimension:%d \n ", dimijkl);
 printf ("Count:%d \n ", count);
}

现在我将循环 i 展开 2 倍:

for (i = nab+1; i< nab+vab; i+=2)
{
  dimi = a[i];
  for (j = i; j< nab+vab; j++)
  {
   dimj = b[j];
   dimij = dimi*dimj;
   count = count +1;

   for (k = nab+1; k< nab+vab; k++)
   {
     dimk = a[k-1];
     for (l =k; l< nab+vab; l++)
     {
      diml = a[l-1];
      dimkl = dimk*diml;
      dimijkl = dimij * dimkl;
     }
    }
  }

  dimi = a[i+1];
  for (j = i+1; j< nab+vab; j++)
  {
    dimj = b[j];
    dimij = dimi*dimj;
    count = count +1;

     for (k = nab+1; k< nab+vab; k++)
     {
      dimk = a[k-1];
      for (l =k; l< nab+vab; l++)
      {
        diml = a[l-1];
        dimkl = dimk*diml;
        dimijkl = dimij * dimkl;
      }    
     }
    }
   }
   printf ("Final dimension:%d \n ", dimijkl);
   printf ("Count:%d \n ", count);

现在我希望将循环 ij 展开 2 倍,但由于循环 j 取决于循环 i,我有点不确定应该如何编写它。如何重写代码以将 ij 展开 2 倍。 此外,随着我​​增加展开因子,代码将变得越来越笨拙。有没有一种聪明的方法可以手动展开它,而不会使代码变得太难看。

在这种特殊情况下,我不能使用编译器标志(例如:-funroll-loops)。我想通过手动循环展开来接近它。

感谢您的宝贵时间。

【问题讨论】:

    标签: c loops loop-unrolling


    【解决方案1】:

    也许不是最优雅的解决方案,但您可以使用宏:

    #define INNER_L_LOOP(l) \
        { \
            diml = a[l-1]; \
            dimkl = dimk*diml; \
            dimijkl = dimij * dimkl; \
        } 
    
    #define INNER_K_LOOP(k) \
        { \
            dimk = a[k-1]; \
            for (l =k; l< nab+vab; l++) \
            { \
                INNER_L_LOOP(l) \
            } \
        } 
    
    #define INNER_J_LOOP(j) \
        { \
            dimj = b[j]; \
            dimij = dimi*dimj; \
            count = count +1; \
            \
            for (k = nab+1; k< nab+vab; k += 2) \
            { \
                INNER_K_LOOP(k) \
                if (k+1 < nab+vab) \
                    INNER_K_LOOP(k+1) \
            } \
        } 
    
    #define INNER_I_LOOP(i) \
        { \
            dimi = a[i]; \
            for (j = i; j< nab+vab; j+= 2) \
            { \
                INNER_J_LOOP(j) \
                if (j+1 < nab+vab) \
                    INNER_J_LOOP(j+1) \
            } \
        } 
    
     for (i = nab+1; i< nab+vab; i+=2) 
     {
         INNER_I_LOOP(i)
         INNER_I_LOOP(i+1)
     }
    

    在这里,我将 i、j 和 k 循环分别展开了 2 倍,您会注意到最内层循环的代码不必重复 8 次(这就是您想要的避免,如果我理解正确的话)。

    您还会注意到,对于 j 和 k 循环,我正在检查索引是否超出数组边界。此检查对性能有轻微影响,我将由您自行优化。 ;)

    【讨论】:

      猜你喜欢
      • 2010-09-12
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      相关资源
      最近更新 更多