I came across very strange behavior in gcc regarding operators and functions marked with __attribute((const)) . Logical and arithmetic operators lead to various optimizations, and I donβt understand why.
Actually, this is not a mistake, since __attribute((const)) is just a hint, and there is no guarantee of its influence, but still it is very surprising. Anyone have any explanation?
Here is the code. Therefore, I define the __attribute((const)) function:
int f(int & counter) __attribute((const)); int f(int & counter) { ++counter; return 0; }
Then I define a statement validation macro. This is done using macros rather than templates / functors to present simple code to the compiler and simplify optimization:
int global = 0; // forces results to be computed #define TestOp(OP) \ { \ int n = 0; \ global += (f(n) OP f(n)); \ std::cout << "op" #OP " calls f " << n << " times" << std::endl; \ }
And finally, I test the different operators as follows. Comments correspond to the output of g++-4.8 -std=c++11 -O2 -Wall -pedantic the same output in -O3 and -Ofast
int main() { // all calls optimized away TestOp(^) // 0 TestOp(-) // 0 // one call is optimized away TestOp(|) // 1 TestOp(&) // 1 TestOp(||) // 1 TestOp(&&) // 1 // no optimization TestOp(+) // 2 TestOp(*) // 2 return global; }
My question is: why do arithmetic operators give two calls? Why can't f()+f() be optimized like 2*f() ? Is there any way to help / force this optimization? At first I thought that multiplication could be expensive, but I tried using f()+....+f() , and 10 additions are still not reduced to 10*f() . In addition, since arithmetic is int , the order of operations does not matter (unlike float s).
I also checked asm, but that does not help: all ints seem to be pre-computed at compile time.