我有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;
我唯一的猜测是潜在的浮点异常,它引入了副作用
答案 0 :(得分: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
}
答案 1 :(得分:2)
我认为对这个问题的简短回答是,仅仅因为编译器可以在理论上进行一些优化并不意味着它将。没有什么是免费的。如果编译器要优化n,那么有人必须编写代码才能完成它。
这听起来像是一件很奇怪的角落案例和琐碎的空间节省。我的意思是,人们多久写一次执行复杂计算的函数只是为了丢弃结果?在这种情况下,是否值得编写复杂的优化来恢复8字节的堆栈空间?
答案 2 :(得分:1)
我无法确定它会产生影响,但您可能需要查看GCC的pure
和const
属性(http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html)。它基本上告诉编译器该函数仅对其输入进行操作并且没有副作用。
鉴于这些额外信息,它可能能够确定呼叫是不必要的。
答案 3 :(得分:0)
尽管我已经在其他线程中提出过所有编译器都很完美但绝不会错过优化的论点。编译器并不完美,也不经常进行优化。
有趣的人:
int fun ( int a ) { switch(a&3) { case 0: return(a+4); case 1: return(a+2); case 2: return(a); case 3: return(0); } return(1); }
如果你在结束时离开那个返回的时间最长,你会得到一个错误,该函数定义了一个返回类型但是没有返回一个值。有些编译器会在函数结束时抱怨return()并在没有它的情况下抱怨。
从gcc vs say llvm我可以看出,gcc在一个文件中的函数内进行优化,llvm优化了它所提供的所有内容。您可以将整个项目的字节码合并到一个文件中,并一次性优化整个项目。目前,gcc输出优于llvm十几个或更多,这很有趣。给它时间。
也许在您的情况下,您使用两个未声明为static(const)的输入进行计算,因此结果n可能会发生变化。如果在每个功能的基础上进行优化,则无法进一步降低它。所以我的猜测是它正在优化每个函数,并且调用函数不知道影响我在系统上的动态输入是什么,即使没有使用返回值,它仍然需要计算函数(I)来解决依赖于I.我认为这不是一个无限循环,......意味着强加一些限制?如果不是动态而不是静态,函数(I)可能是一个终止无限循环函数,或者它可能在那里等待中断服务程序修改I并将其踢出无限循环。