为什么优化没有发生?

问题描述 投票:0回答:4

我有 C/C++ 代码,如下所示:

static int function(double *I) {
    int n = 0;
    // more instructions, loops,
    for (int i; ...; ++i)
        n += fabs(I[i] > tolerance);
    return n;
}

function(I); // return value is not used.

编译器内联函数,但是它不会优化

n
操作。 我希望编译器能够识别该值永远不会仅用作 rhs。 是否有一些副作用阻碍了优化?

编译器似乎并不重要,我尝试了Intel和gcc。 积极优化,

-O3

谢谢

更完整的代码(完整代码是此类块的重复):

  280         // function registers
  281         double q0 = 0.0;
  282         double q1 = 0.0;
  283         double q2 = 0.0;
  284
  285 #if defined (__INTEL_COMPILER)
  286 #pragma vector aligned
  287 #endif // alignment attribute
  288         for (int a = 0; a < int(N); ++a) {
  289             q0 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,0);
  290             q1 += Ix(a,0,0)*Iy(a,1,0)*Iz(a,0,0);
  291             q2 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,1,0);
  292         }
  293 #endif // not SSE
  294
  295         //contraction coefficients
  296         qK0 += q0*C[k+0];
  297         qK1 += q1*C[k+0];
  298         qK2 += q2*C[k+0];
  299
  300         Ix += 3*dim2d;
  301         Iy += 3*dim2d;
  302         Iz += 3*dim2d;
  303
  304     }
  305     Ix = Ix - 3*dim2d*K;
  306     Iy = Iy - 3*dim2d*K;
  307     Iz = Iz - 3*dim2d*K;
  308
  309     // normalization, scaling, and storage
  310     if(normalize) {
  311         I[0] = scale*NORMALIZE[1]*NORMALIZE[0]*(qK0 + I[0]);
  312         num += (fabs(I[0]) >= tol);
  313         I[1] = scale*NORMALIZE[2]*NORMALIZE[0]*(qK1 + I[1]);
  314         num += (fabs(I[1]) >= tol);
  315         I[2] = scale*NORMALIZE[3]*NORMALIZE[0]*(qK2 + I[2]);
  316         num += (fabs(I[2]) >= tol);
  317     }
  318     else {
  319         I[0] = scale*(qK0 + I[0]);
  320         num += (fabs(I[0]) >= tol);
  321         I[1] = scale*(qK1 + I[1]);
  322         num += (fabs(I[1]) >= tol);
  323         I[2] = scale*(qK2 + I[2]);
  324         num += (fabs(I[2]) >= tol);
  325     }
  326
  327
  328     return num;

我唯一的猜测是潜在的浮点异常,这会带来副作用

c++ c optimization
4个回答
7
投票

代码确实使用了

n
,首先将其初始化为 0,然后在函数左侧的循环内使用,可能会产生副作用 (
fabs
)。

是否实际使用该函数的return并不重要,

n
本身已被使用。

更新:我在 MSVC10 中尝试了这段代码,它优化了整个功能。给我一个我可以尝试的完整示例。

#include <iostream>
#include <math.h>

const int tolerance=10;

static int function(double *I) {
    int n = 0;
    // more instructions, loops,
    for (int i=0; i<5; ++i)
        n += fabs((double)(I[i] > tolerance));
    return n;
}


int main()
{
    double I[]={1,2,3,4,5};

    function(I); // return value is not use
}

2
投票

我认为这个问题的简短答案是,仅仅因为编译器可以在理论上进行一些优化并不意味着它将会。 没有什么是免费的。 如果编译器要优化掉 n,那么就必须有人编写代码来做到这一点。

对于既是奇怪的极端情况又是微不足道的空间节省的东西来说,这听起来像是大量的工作。 我的意思是,人们多久会编写执行复杂计算的函数却丢弃结果? 在这种情况下是否值得编写复杂的优化来恢复 8 个字节的堆栈空间?


1
投票

我不能肯定地说它会产生影响,但你可能想研究一下 GCC 的

pure
const
属性(http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes .html)。它基本上告诉编译器该函数仅对其输入进行操作并且没有副作用。

根据这些额外信息,它可能能够确定该呼叫是不必要的。


0
投票

尽管我在其他线程中遇到过一些争论,但所有编译器都是完美的并且不会错过任何优化。 编译器并不完美,并且经常无法捕获优化。

像这样有趣的:

int 乐趣 ( int a )
{
   开关(a&3)
   {
      情况 0:返回(a+4); 
      情况1:返回(a+2);
      情况2:返回(a);
      情况3:返回(0);
   }
   返回(1);
}

在最长的时间里,如果您将返回值留在最后,您会收到一个错误,表明该函数定义了返回类型但未能返回值。 有些编译器会抱怨函数末尾的 return() ,如果没有它也会抱怨。

据我所知,gcc 与 llvm 相比,gcc 在文件内的函数内进行优化,其中 llvm 对其输入的所有内容进行优化。 您可以将整个项目的字节码加入到一个文件中,并一次性优化整个过程。 目前,gcc 输出的性能比 llvm 好百分之十几或更多,这很有趣。 给它时间。

也许在您的情况下,您正在使用两个未声明为静态(const)的输入进行计算,因此结果 n 可能会改变。 如果针对每个功能进行优化,则无法进一步减少它。 所以我的猜测是它正在优化每个函数,并且调用函数不知道什么会影响我在系统上的动态输入,即使未使用返回值,它仍然需要计算函数(I)来解决依赖于的任何内容I. 我认为这不是无限循环,...意味着施加了一些限制? 如果这里不再是动态的而不是静态的,函数(I)可能是一个终止无限循环函数,或者它可能在那里等待中断服务例程来修改 I 并将其踢出无限循环。

© www.soinside.com 2019 - 2024. All rights reserved.