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?