Ofek Shilon
Ofek Shilon

Reputation: 16129

Aliasing - what is the clang optimizer afraid of?

Take this toy code (godbolt link):

int somefunc(const int&);
void nothing();

int f(int i) {
    i = somefunc(i);
    i++;
    nothing();
    i++;
    nothing();
    i++;
    return i;
}

As can be seen in the disassembly at the link, the compiler reloads i from the stack 3 times, increments and stores back.

If somefunc is modified to accept int by value, this doesn't happen.

(1) Is the optimizer 'afraid' that since somefunc has access to is address, it can indirectly modify it? Can you give an example of well defined code that does that? (remember that const_cast'ing away and modifying is undefined behavior).

(2) Even if that was true, I'd expect that decorating somefunc with __attribute__((pure)) would stop that pessimization. It doesn't. Why?

Are these llvm missed optimizations?


Edit: If somefunc returns void, __attribute__((pure)) does kick in as expected:

void somefunc(const int&) __attribute__((pure));
void nothing();

int f(int i) {
    somefunc(i);
    i++;
    nothing();
    i++;
    nothing();
    i++;
    return i;
}

Maybe this attribute is sort of half baked (it is rare in practice).

Upvotes: 2

Views: 161

Answers (1)

Sneftel
Sneftel

Reputation: 41474

As mentioned in a comment, using const_cast to remove the constness of a reference to an object that was defined as non-const is well-defined. In fact, that's its only real use.

As for __attribute__((pure)): Who knows. The nothing() calls are necessary to reproduce the situation; if those are marked pure then proper optimization is done; the invocation of somefunc doesn't have much of an impact on that situation. Basically, the compiler tends to be quite conservative unless everything in a code block is pure. While it should arguably be able to deduce that nothing() doesn't affect i, that's very much a "best effort" area of optimization and not something that properly optimized code should rely on.

Upvotes: 6

Related Questions