Ofek Shilon
Ofek Shilon

Reputation: 16129

Shouldn't strict-aliasing kick in in this code?

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?

Upvotes: 1

Views: 115

Answers (2)

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29965

If you are sure no aliasing happens, most compilers support restrict from C99:

void f(const int& __restrict a, int* dat) {
    for (int i = 0; i < a; ++i) dat[i] += a;
}

Godbolt link

Note that this is dangerous code. A better option would be to take a by value:

void f(const int a, int* dat) {
    for (int i = 0; i < a; ++i) dat[i] += a;
}

Godbolt link

Upvotes: 1

Jeffrey
Jeffrey

Reputation: 11400

Imagine the following:

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;
}

int main()
{
   myInt foo{ 1 };
   f(foo.i, &foo);
}

In this program, a and dat.i actually alias. They are the same variable. So the compiler actually needs to reload one after a write to the other.

Upvotes: 4

Related Questions