避免人工循环展开

向量化缺陷,避免人工展开

面向英特尔® MIC 架构的编译器方法

避免人工循环展开

如果不是人工展开循环结构,英特尔® 编译器通常能够生成高效的向量化代码。更好的方式是让编译器执行展开操作,您可以通过 "#pragma unroll (n)" 来控制展开。如果编译器必须“取消”人工展开,那向量对齐、循环破裂以及与其他循环优化的交互将变得更加复杂。举一个最简单的例子,用户必须执行重建操作才能获得性能最高的向量代码。

另外,人工循环展开会针对特定的处理器或架构来调试循环,可能不利于未来进行某些应用的移植。通常,以最直观、最易于读取的方式编写代码是一个很好的选择。这最有利于编译器对特定的循环结构进行优化。

Fortran 示例(在源代码中执行人工展开):

  m = MOD(N,4)

  if ( m /= 0 ) THEN
    do i = 1 , m
      Dy(i) = Dy(i) + Da*Dx(i)
    end do
    if ( N < 4 ) RETURN
  end if

  mp1 = m + 1
  do i = mp1 , N , 4
    Dy(i) = Dy(i) + Da*Dx(i)
    Dy(i+1) = Dy(i+1) + Da*Dx(i+1)
    Dy(i+2) = Dy(i+2) + Da*Dx(i+2)
    Dy(i+3) = Dy(i+3) + Da*Dx(i+3)
  end do

最好以简单的方式来表达:

   do i=1,N

     Dy(i)= = Dy(i) + Da*Dx(i)
   end do

这有助于编译器针对整个计算生成高效的向量代码以及提高代码的可读性。

C++ 示例(在源代码中执行人工展开):

double accu1 = 0, accu2 = 0, accu3 = 0, accu4 = 0;

double accu5 = 0, accu6 = 0, accu7 = 0, accu8 = 0;

for (i = 0; i < NUM; i += 8) {
    accu1 = src1[i+0]*src2 + accu1;
    accu2 = src1[i+1]*src2 + accu2;
    accu3 = src1[i+2]*src2 + accu3;
    accu4 = src1[i+3]*src2 + accu4;
    accu5 = src1[i+4]*src2 + accu5;
    accu6 = src1[i+5]*src2 + accu6;
    accu7 = src1[i+6]*src2 + accu7;
    accu8 = src1[i+7]*src2 + accu8;
}
accu = accu1 + accu2 + accu3 + accu4 +
accu5 + accu6 + accu7 + accu8;

最好以简单的方式来表达:

double accu = 0;

for (i = 0; i < NUM; i++ ) {
    accu = src1[i]*src2 + accu;
}

下一步

要在英特尔® 至强融核™ 协处理器上成功调试您的应用,请务必通读此指南,并点击文中的超链接查看相关内容。本指南提供了实现最佳应用性能所要执行的步骤。

返回到 “向量化要素” 矢量化要素。

有关编译器优化的更完整信息,请参阅优化通知