Take this toy code:
void f(const int& a, int* dat) {
for (int i=0; i<a; ++i )
dat[i] += a;
}
Observe that the compiler is afraid that dat[i] might alias with a, i.e. writing to dat[i] might change the value of a - and so it feels obliged to re-load a on every loop iteration (that's the 'movslq (%rdi), %rax' line at the link).
This could be solved with strict-aliasing, by changing the type of dat:
void f(const int& a, long* dat) {
...
The generated code seems Indeed longer, but that's due to vectorization. It doesn't re-load a on every iteration.
I'm surprised this doesn't work for my own custom type!
struct myInt {
int i;
myInt& operator+=(int rhs) { i += rhs; return *this;}
};
void f(const int& a, myInt* dat) {
for (int i=0; i<a; ++i )
dat[i] += a;
}
Here the compiler returns to re-loading the loop boundary on every iteration. Both clang and gcc do.
Looks like the compiler's alias-analysis treats myInt as a regular int - which is reasonable in many aspects, but causes this optimization to be missed. Could this be a compiler bug? Or is there something I'm missing about strict-aliasing?