I'm working on presentation that demonstrates various C++ optimizations and stuck with an example where const
allows them.
Consider following code:
object.h
class Object {
int i1;
int i2;
public:
Object(int i1_, int i2_) : i1(i1_), i2(i2_) {}
int getI1() const { return i1; }
int getI2() const { return i2; }
std::pair<int, int> calculate() const {
return std::pair<int, int>(i1 + i2, i1 * i2);
}
};
constopt.cpp
#include <iostream>
#include "object.h"
int main() {
Object o(10, 20);
std::cout << o.getI1() << " + " << o.getI2() << " = "
<< o.calculate().first << std::endl
<< o.getI1() << " * " << o.getI2() << " = "
<< o.calculate().second << std::endl;
return 0;
}
When calculate()
is inlined, everything fine, G++ directly passes constants (10 and 20) to operator <<
caching getI1()
and getI2()
calls:
mov $0xa,%esi
mov $0x601080,%edi
callq 0x400740 <_ZNSolsEi@plt>
But when I move calculate()
to a separate translation unit, it forces i1
and i2
to be fetched twice (before and after o.calculate().first
):
mov (%rsp),%esi
mov 0x4(%rsp),%r14d
mov $0x601080,%edi
callq 0x400740 <_ZNSolsEi@plt>
I see no difference, because getI1()
doesn't rely on any side effects that can be created by calculate()
and Object
is intended to be const even when calculate()
is in separate translation unit.
Is that G++ is not smart enough or it is not eligible to perform optimizations in such cases? My speculation is that it can cache getI1()
and getI2()
calls came from that answer: How does const after a function optimize the program?
I use gcc version 4.8.1. I have tried both -Os and -O2.
It seems that const
isn't used in GCC optimizer in this case. Instead, it does its own digging (which can't be performed in different translation units), and searches for pure and const functions. Functions can be manually marked with __attribute__((const))
. Phase that eliminates extra getI*()
calls is called FRE (Full Redundancy Elimination).