points by dataflow 1 year ago

> But, the key thing here is that if the programmer wrote *(p+1) = 10; print(q[0]); it is entirely reasonable and legal for the compiler to optimize that to *(p+1) = 10; print(0); Because the abstract model says that stores to one object can not alias another object.

If the programmer wrote that... but that's not what the programmer wrote. The programmer wrote *(char*)iq = 10 which was provably (!) equivalent to both *(char*)(uintptr_t)q = 10 as well as *(char*)(uintptr_t)(p+1) = 10. That means the compiler can't just replace it with the latter while ignoring the former -- it must carry the aliasing constraints implied by the former into the latter.

> However, in this case, the optimizer transformed a legal, well-formed construct into a illegal construct and then optimized as if it was always a illegal construct. Focusing on directly preventing such transforms and why such transforms should be illegal (pointing out the legal -> illegal thing they enable) minimizes the changes needed to the model.

I see where the confusion is.

You're missing this sentence: "I am using C syntax here just as a convenient way to write programs in LLVM IR." The intermediate transformations you see there are not C code.

You're looking at the compiler as "optimize C to faster C, then codegen". In which case you can blame step 2 (the replacement of *(char*)(uintptr_t)(p+1) with *(p+1)) as the violating culprit, due to the aliasing rules.

Which... would be fine if you view it that way, I don't mind too much if you do.

But I'm looking at the compiler as "generate IR for C, then optimize the IR, then codegen" (which is closer to what LLVM does), in which case the "*(p+1) = 10" you see in the 2nd optimization step isn't C code anymore, it's LLVM IR that the author tried to transcribe in some made-up language that superficially resembles C! You can't really say "this is a legal transformation" anymore because it's not the C code anymore, it's just some internal compiler gibberish that someone tried to display with a imitation-C syntax to make it easier to read. The aliasing rules no longer apply there, because it's not actually C... it's LLVM IR.

Which is why I said "q is never written to" (step 3) is the violation. Because as I saw it, step 2 was fine, because it wasn't C, so it didn't have the aliasing semantics of C. In fact it would be illegal for the compiler to transform the original program into that and continue to treat that as equivalent C.

Rusky 1 year ago

> step 2 was fine, because it wasn't C, so it didn't have the aliasing semantics of C.

LLVM still has its own aliasing semantics. It must, both so that it can exploit at least some of C's aliasing rules, and more importantly so that we can determine whether a given transformation is correct, without reference to the entire corpus of optimization passes.

The article describes three possible choices of aliasing semantics for LLVM IR, each of which makes a different optimization pass illegal. You are arguing for one particular choice, without addressing its downsides as also covered in the article.